diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000000..e69de29bb2 diff --git a/404.html b/404.html new file mode 100644 index 0000000000..6fa25b1c86 --- /dev/null +++ b/404.html @@ -0,0 +1,16 @@ + + + + + +Interchain Security + + + + +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

+ + \ No newline at end of file diff --git a/404/index.html b/404/index.html new file mode 100644 index 0000000000..6f0d4b4200 --- /dev/null +++ b/404/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/adrs/adr-001-key-assignment.html b/adrs/adr-001-key-assignment.html new file mode 100644 index 0000000000..71c4ffd5b9 --- /dev/null +++ b/adrs/adr-001-key-assignment.html @@ -0,0 +1,79 @@ + + + + + +Key Assignment | Interchain Security + + + + +
Skip to main content
Version: main

ADR 001: Key Assignment

+

Changelog

+
    +
  • 2022-12-01: Initial Draft
  • +
  • 2024-03-01: Updated to take into account they key-assigment-replacement deprecation.
  • +
+

Status

+

Accepted

+

Context

+

KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate.

+

Decision

+

It is possible to change the keys at any time by submitting a transaction (i.e., MsgAssignConsumerKey).

+

State required

+
    +
  • ValidatorConsumerPubKey - Stores the validator assigned keys for every consumer chain.
  • +
+
ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey
+
    +
  • ValidatorByConsumerAddr - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol.
  • +
+
ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress
+
    +
  • ConsumerAddrsToPrune - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ValidatorByConsumerAddr.
  • +
+
ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses
+

Protocol overview

+

On receiving a MsgAssignConsumerKey(chainID, providerAddr, consumerKey) message:

+
// get validator from staking module  
validator, found := stakingKeeper.GetValidator(providerAddr)
if !found {
return ErrNoValidatorFound
}
providerConsAddr := validator.GetConsAddr()

// make sure consumer key is not in use
consumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)
if _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {
return ErrInvalidConsumerConsensusPubKey
}

// check whether the consumer chain is already registered
// i.e., a client to the consumer was already created
if _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {
// get the previous key assigned for this validator on this consumer chain
oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)
if found {
// mark this old consumer key as prunable once the VSCMaturedPacket
// for the current VSC ID is received
oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)
vscID := GetValidatorSetUpdateId()
AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)
}
} else {
// if the consumer chain is not registered, then remove the previous reverse mapping
if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {
oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)
DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)
}
}


// set the mapping from this validator's provider address to the new consumer key
SetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)

// set the reverse mapping: from this validator's new consensus address
// on the consumer to its consensus address on the provider
SetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)
+

When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see MakeConsumerGenesis).

+
func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {
// ...
// get initial valset from the staking module
var updates []abci.ValidatorUpdate{}
stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {
validator := stakingKeeper.GetValidator(providerAddr)
providerKey := validator.TmConsPublicKey()
updates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})
return false
})

// applies the key assignment to the initial validator
for i, update := range updates {
providerAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)
if consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {
updates[i].PubKey = consumerKey
}
}
gen.InitialValSet = updates

// get a hash of the consumer validator set from the update
updatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)
hash := tendermint.NewValidatorSet(updatesAsValSet).Hash()

return gen, hash, nil
}
+

Note that key assignment works hand-in-hand with epochs. +For each consumer chain, we store the consumer validator set that is currently (i.e., in this epoch) validating the consumer chain. +Specifically, for each validator in the set we store among others, the public key that it is using on the consumer chain during the current (i.e., ongoing) epoch. +At the end of every epoch, if there were validator set changes on the provider, then for every consumer chain, we construct a VSCPacket +with all the validator updates and add it to the list of PendingVSCPackets. We compute the validator updates needed by a consumer chain by +comparing the stored list of consumer validators with the current bonded validators on the provider, with something similar to this:

+
// get the valset that has been validating the consumer chain during this epoch 
currentValidators := GetConsumerValSet(consumerChain)
// generate the validator updates needed to be sent through a `VSCPacket` by comparing the current validators
// in the epoch with the latest bonded validators
valUpdates := DiffValidators(currentValidators, stakingmodule.GetBondedValidators())
// update the current validators set for the upcoming epoch to be the latest bonded validators instead
SetConsumerValSet(stakingmodule.GetBondedValidators())
+

where DiffValidators internally checks if the consumer public key for a validator has changed since the last +epoch and if so generates a validator update. This way, a validator can change its consumer public key for a consumer +chain an arbitrary amount of times and only the last set consumer public key would be taken into account.

+

On receiving a SlashPacket from a consumer chain with id chainID for a infraction of a validator data.Validator:

+
func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {
// ...
// the slash packet validator address may be known only on the consumer chain;
// in this case, it must be mapped back to the consensus address on the provider chain
consumerAddr := sdk.ConsAddress(data.Validator.Address)
providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)
if !found {
// the validator has the same key on the consumer as on the provider
providerAddr = consumerAddr
}
// ...
}
+

On receiving a VSCMatured:

+
func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {
// ...
// prune previous consumer validator address that are no longer needed
consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)
for _, addr := range consumerAddrs {
DeleteValidatorByConsumerAddr(chainID, addr)
}
DeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)
// ...
}
+

On stopping a consumer chain:

+
func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {
// ...
// deletes all the state needed for key assignments on this consumer chain
// ...
}
+

Consequences

+

Positive

+
    +
  • Validators can use different consensus keys on the consumer chains.
  • +
+

Negative

+
    +
  • None
  • +
+

Neutral

+
    +
  • The consensus state necessary to create a client to the consumer chain must use the hash returned by the MakeConsumerGenesis method as the nextValsHash.
  • +
  • The consumer chain can no longer check the initial validator set against the consensus state on InitGenesis.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/adrs/adr-001-key-assignment.html.html b/adrs/adr-001-key-assignment.html.html new file mode 100644 index 0000000000..6c906bc37e --- /dev/null +++ b/adrs/adr-001-key-assignment.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/adrs/adr-002-throttle.html b/adrs/adr-002-throttle.html new file mode 100644 index 0000000000..02947e0a0f --- /dev/null +++ b/adrs/adr-002-throttle.html @@ -0,0 +1,164 @@ + + + + + +Jail Throttling | Interchain Security + + + + +
Skip to main content
Version: main

ADR 002: Jail Throttling

+

Changelog

+
    +
  • 2023-01-26: Initial Draft
  • +
  • 2023-02-07: Property refined, ADR ready to review/merge
  • +
  • 2023-11-22: Refactor for better understanding
  • +
+

Status

+

Accepted

+

Context

+

The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols. +In practice, this assumption may not hold. +A malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider.

+

Before the throttling feature was implemented, the following attack was possible. +Attacker(s) would create provider validators just below the provider's active set. +Using a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once. +Control of the provider would then pass over to the attackers' validators. +This enables the attacker(s) to halt the provider. +Or even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC.

+

Decision

+

The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack, +i.e., this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time.

+

Required State

+

Slash meter: There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time. +This meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params.

+

Global entry queue: There exists a single queue which stores "global slash entries". +These entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering. +This queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.

+

Per-chain data queue: For each established consumer, there exists a queue which stores "throttled packet data", +i.e.,pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering. +Order is enforced by IBC sequence number. +These "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.

+

Note: The reason for a multiple-queue design is the VSC Maturity and Slashing Order property (see spec). +There are other ways to ensure such a property (like a queue of linked lists, etc.), but the proposed approach seemed to be the most understandable and easiest to implement with a KV store.

+

Params

+

SlashMeterReplenishPeriod -- the period after which the slash meter is replenished.

+

SlashMeterReplenishFraction -- the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs. This param also serves as a maximum fraction of total voting power that the slash meter can hold.

+

MaxThrottledPackets -- the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value. +This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness.

+

Protocol Overview

+

OnRecvSlashPacket

+

Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:

+
    +
  1. A global slash entry is queued.
  2. +
  3. The data of such a packet is added to the per-chain queue.
  4. +
+

OnRecvVSCMaturedPacket

+

Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue.

+

Endblocker

+

In the EndBlock of the provider CCV module, there are three actions performed:

+
    +
  • replenish the slash meter;
  • +
  • handle the leading VSCMaturedPackets;
  • +
  • and handle the throttle queues.
  • +
+
Slash Meter Replenishment
+

Once the slash meter becomes not full, it'll be replenished after SlashMeterReplenishPeriod by incrementing the meter with its allowance for the replenishment block, where allowance = SlashMeterReplenishFraction * currentTotalVotingPower. +The slash meter will never exceed its current allowance (function of the total voting power for the block) in value.

+

Note a few things:

+
    +
  1. The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power. +In such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods.
  2. +
  3. Total voting power of a chain changes over time, especially as validators are jailed. +As validators are jailed, total voting power decreases, and so does the jailing allowance. +See below for more detailed throttling property discussion.
  4. +
  5. The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1. +If the SlashMeterReplenishFraction is set too low, integer rounding will put this minimum value into effect. +That is, if SlashMeterReplenishFraction * currentTotalVotingPower < 1, then the effective allowance would be 1. +This min value of allowance ensures that there's some packets handled over time, even if that is a very long time. +It's a crude solution to an edge case caused by too small of a replenishment fraction.
  6. +
+

The behavior described above is achieved by executing CheckForSlashMeterReplenishment() every EndBlock, BEFORE HandleThrottleQueues() is executed.

+
Handle Leading VSCMaturedPackets
+

In every block, it is possible that VSCMaturedPacket data was queued before any slash packet data. +Since this "leading" VSCMatured packet data does not have to be throttled (see VSC Maturity and Slashing Order), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes.

+
Handle Throttle Queues
+

In every EndBlock, the following logic is executed to handle data from the throttle queues.

+
meter := getSlashMeter()

// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist
while meter.IsPositiveOrZero() && entriesExist() {
// Get next entry in queue
entry := getNextGlobalSlashEntry()
// Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet
valPower := entry.getValPower()
meter = meter - valPower
// Using the per-chain queue, handle the single slash packet using its queued data,
// then handle all trailing VSCMatured packets for this consumer
handleSlashPacketAndTrailingVSCMaturedPackets(entry)
// Delete entry in global queue, delete handled data
entry.Delete()
deleteThrottledSlashPacketData()
deleteTrailingVSCMaturedPacketData()
}
+

System Properties

+

All CCV system properties should be maintained by implementing this feature, see CCV spec - Consumer Initiated Slashing.

+

One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than MaxThrottledPackets, then the provider binary will panic, and the provider chain will halt. +Therefore this param should be set carefully. See SetThrottledPacketDataSize. +This behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators.

+

Main Throttling Property

+

Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions.

+

First, we introduce the following definitions:

+
    +
  • A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.
  • +
  • The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.
  • +
  • There is a list of honest validators such that if they are jailed, X% of the initial validator set will be jailed.
  • +
+

For the Throttling Property to hold, the following assumptions must be true:

+
    +
  1. We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack.
  2. +
  3. No validator has more than SlashMeterReplenishFraction of total voting power on the provider.
  4. +
  5. SlashMeterReplenishFraction is large enough that SlashMeterReplenishFraction * currentTotalVotingPower > 1, +i.e., the replenish fraction is set high enough that we can ignore the effects of rounding.
  6. +
  7. SlashMeterReplenishPeriod is sufficiently longer than the time it takes to produce a block.
  8. +
+

Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined.

+

Throttling Property: The time it takes to jail/tombstone X% of the initial validator set will be greater than or equal to +SlashMeterReplenishPeriodXSlashMeterReplenishFraction2SlashMeterReplenishPeriod\mathit{SlashMeterReplenishPeriod} \cdot \frac{X}{\mathit{SlashMeterReplenishFraction}} - 2 \cdot \mathit{SlashMeterReplenishPeriod}.

+
+

Intuition

+

Let's use the following notation:

+
    +
  • CC: Number of replenishment cycles
  • +
  • PP: SlashMeterReplenishPeriod\mathit{SlashMeterReplenishPeriod}
  • +
  • FF: SlashMeterReplenishFraction\mathit{SlashMeterReplenishFraction}
  • +
  • VmaxV_{\mathit{max}}: Max power of a validator as a fraction of total voting power
  • +
+

In CC number of replenishment cycles, the fraction of total voting power that can be removed, aa, is aFC+Vmaxa \leq F \cdot C + V_{\mathit{max}} (where VmaxV_{\mathit{max}} is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value).

+

So, we need at least CaVmaxFC \geq \frac{a - V_{\mathit{max}}}{F} cycles to remove aa fraction of the total voting power.

+

Since we defined the start of the attack to be the moment when the first slash request arrives, then FF fraction of the initial validator set can be jailed immediately. For the remaining XFX - F fraction of the initial validator set to be jailed, it takes at least C(XF)VmaxFC \geq \frac{(X - F) - V_{\mathit{max}}}{F} cycles. Using the assumption that VmaxFV_{\mathit{max}} \leq F (assumption 2), we get CX2FFC \geq \frac{X - 2F}{F} cycles.

+

In order to execute CC cycles, we need CPC \cdot P time.

+

Thus, jailing the remaining XFX - F fraction of the initial validator set corresponds to P(X2F)F\frac{P \cdot (X - 2F)}{F} time.

+

In other words, the attack must take at least PXF2P\frac{P \cdot X}{F} - 2P time (in the units of replenish period PP).

+
+

This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests. +For example, if SlashMeterReplenishFraction is set to 0.06, then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub. +Note that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power.

+

Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings.

+

How Unjailing Affects the Main Throttling Property

+

Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained.

+

If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider.

+

In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack.

+

Consequences

+

Positive

+
    +
  • The described attack is slowed down in seemingly all cases.
  • +
  • If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded.
  • +
+

Negative

+
    +
  • Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below. +However, this is sacrificing liveness in a edge case scenario for the sake of security. +As an improvement, using retries would fully prevent this attack vector.
  • +
+

Neutral

+
    +
  • Additional state is introduced to the provider chain.
  • +
  • VSCMatured and slash packet data is not always handled in the same block that it is received.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/adrs/adr-002-throttle.html.html b/adrs/adr-002-throttle.html.html new file mode 100644 index 0000000000..be70137892 --- /dev/null +++ b/adrs/adr-002-throttle.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/adrs/adr-003-equivocation-gov-proposal.html b/adrs/adr-003-equivocation-gov-proposal.html new file mode 100644 index 0000000000..0b7d026783 --- /dev/null +++ b/adrs/adr-003-equivocation-gov-proposal.html @@ -0,0 +1,60 @@ + + + + + +Equivocation governance proposal | Interchain Security + + + + +
Skip to main content
Version: main

ADR 003: Equivocation governance proposal

+

Changelog

+
    +
  • 2023-02-06: Initial draft
  • +
  • 2023-11-30: Change status to deprecated
  • +
+

Status

+

Deprecated

+

Context

+

Note: ADR deprecated as the equivocation proposal was removed by the +cryptographic verification of equivocation feature +(see ADR-005 and +ADR-013).

+

We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain.

+

For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence.

+

Decision

+

To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain.

+

A new kind of governance proposal is added to the provider module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain.

+

If such proposal passes, the proposal handler delegates to the evidence module to process the equivocation. This module ensures the evidence isn’t too old, or else ignores it (see code). Too old is determined by 2 consensus params :

+
    +
  • evidence.max_age_duration number of nanoseconds before an evidence is considered too old
  • +
  • evidence.max_age_numblocks number of blocks before an evidence is considered too old.
  • +
+

On the hub, those parameters are equals to

+
// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682
(...)
"evidence": {
"max_age_num_blocks": "1000000",
"max_age_duration": "172800000000000",
(...)
},
(...)
+

A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the evidence module when the proposal passes and is handled by the hub.

+

For max_age_num_blocks=1M, the parameter is big enough if we consider the hub produces 12k blocks per day (blocks_per_year/365 = 436,0000/365). The evidence can be up to 83 days old (1,000,000/12,000) and not be ignored.

+

For max_age_duration=172,800,000,000,000, the parameter is too low, because the value is in nanoseconds so it’s 2 days. Fortunately the condition that checks those 2 parameters uses a AND, so if max_age_num_blocks condition passes, the evidence won’t be ignored.

+

Consequences

+

Positive

+
    +
  • Remove the possibility from a malicious consumer chain to “attack” the provider chain by slashing/jailing validators.
  • +
  • Provide a more acceptable implementation for the validator community.
  • +
+

Negative

+
    +
  • Punishment action of double-signing isn’t “automated”, a governance proposal is required which takes more time.
  • +
  • You need to pay 250ATOM to submit an equivocation evidence.
  • +
+

Neutral

+

References

+
+ + \ No newline at end of file diff --git a/adrs/adr-003-equivocation-gov-proposal.html.html b/adrs/adr-003-equivocation-gov-proposal.html.html new file mode 100644 index 0000000000..fdcd51cdfd --- /dev/null +++ b/adrs/adr-003-equivocation-gov-proposal.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/adrs/adr-004-denom-dos-fixes.html b/adrs/adr-004-denom-dos-fixes.html new file mode 100644 index 0000000000..5042808731 --- /dev/null +++ b/adrs/adr-004-denom-dos-fixes.html @@ -0,0 +1,59 @@ + + + + + +Denom DOS fixes | Interchain Security + + + + +
Skip to main content
Version: main

ADR 004: Denom DOS fixes

+

Changelog

+
    +
  • 5/9/2023: ADR created
  • +
+

Status

+

Accepted

+

Context

+

The provider and consumer modules are vulnerable to similar issues involving an attacker sending millions of denoms to certain addresses and causing the chain to halt. This ADR outlines both fixes since they are similar. Both fixes involve processing only denoms that are on a whitelist to avoid iterating over millions of junk denoms but have different requirements and are implemented in different ways.

+

Decision

+

Provider

+
    +
  • Put the distribution module's FeePoolAddress back on the blocklist so that it cannot receive funds from users.
  • +
  • Create a new address called ConsumerRewardPool and unblock it, allowing funds to be sent to it.
  • +
  • Create a set of strings in the store for allowed ConsumerRewardDenoms.
  • +
  • Create an endpoint called RegisterConsumerRewardDenom which deducts a fee from the sender's account, sends it to the community pool and adds a string to the ConsumerRewardDenoms set.
  • +
  • Create a parameter called ConsumerRewardDenomRegistrationFee which determines the fee which is charged to register a consumer reward denom in the step above.
  • +
  • Create a function called TransferRewardsToFeeCollector which gets the entire ConsumerRewardDenoms set from the store, iterates over it, and for each entry: +
      +
    • Gets the balance of this denom for the ConsumerRewardPool account
    • +
    • Sends the entire balance out to the FeePoolAddress using SendCoinsFromModuleToModule which is not affected by the blocklist.
    • +
    +
  • +
  • Run TransferRewardsToFeeCollector in the endblock
  • +
+

Now, nobody can send millions of junk denoms to the FeePoolAddress because it is on the block list. If they send millions of junk denoms to the ConsumerRewardPool, this does not matter because all balances are not iterated over, only those which are in the ConsumerRewardDenoms set.

+

We also add a new tx: register-consumer-reward-denom, and a new query: registered-consumer-reward-denoms

+

Consumer

+
    +
  • Create a new param RewardDenoms with a list of strings
  • +
  • Create a new param ProviderRewardDenoms with a list of strings
  • +
  • Create a function AllowedRewardDenoms which iterates over ProviderRewardDenoms and converts each denom to its ibc-prefixed denom using the provider chain's ibc channel information, then concatenates the RewardDenoms list and returns the combined list of allowed denoms.
  • +
  • In SendRewardsToProvider, instead of iterating over the balances of all denoms in the ToSendToProvider address, iterate over AllowedRewardDenoms
  • +
+

Now, if somebody sends millions of junk denoms to ToSendToProvider, they will not be iterated over. Only the RewardDenoms and ProviderRewardDenoms will be iterated over. Since we do not require this feature to be permissionless on the consumer, the registration fee process is not needed.

+

Consequences

+

Positive

+
    +
  • Denom DOS is no longer possible on either provider or consumer.
  • +
+

Negative

+
    +
  • Consumer chain teams must pay a fee to register a denom for distribution on the provider, and add some extra parameters in their genesis file.
  • +
+ + \ No newline at end of file diff --git a/adrs/adr-004-denom-dos-fixes.html.html b/adrs/adr-004-denom-dos-fixes.html.html new file mode 100644 index 0000000000..4de34f6075 --- /dev/null +++ b/adrs/adr-004-denom-dos-fixes.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/adrs/adr-005-cryptographic-equivocation-verification.html b/adrs/adr-005-cryptographic-equivocation-verification.html new file mode 100644 index 0000000000..bc0a08a058 --- /dev/null +++ b/adrs/adr-005-cryptographic-equivocation-verification.html @@ -0,0 +1,145 @@ + + + + + +Cryptographic verification of equivocation evidence | Interchain Security + + + + +
Skip to main content
Version: main

ADR 005: Cryptographic verification of equivocation evidence

+

Changelog

+
    +
  • 5/1/2023: First draft
  • +
  • 7/23/2023: Add light client attacks handling
  • +
  • 9/6/2023: Add double signing attacks handling
  • +
  • 11/3/2023: Update limitations to clarify amnesia attacks are ignored
  • +
+

Status

+

Accepted

+

Context

+

Currently, we use a governance proposal to slash validators for equivocation (double signing and light client attacks). +Every proposal needs to go through a (two weeks) voting period before it can be approved. +Given a three-week unbonding period, this means that an equivocation proposal needs to be submitted within one week since the infraction occurred.

+

This ADR proposes a system to slash validators automatically for equivocation, immediately upon the provider chain's receipt of the evidence. Another thing to note is that we intend to introduce this system in stages, since even the partial ability to slash and/or tombstone is a strict improvement in security. +The feature is implemented in two parts, each with its dedicated endpoint. One endpoint handles light client attacks, while the other handles double signing attacks.

+

Light Client Attack

+

In a nutshell, the light client is a process that solely verifies a specific state machine's +consensus without executing the transactions. The light clients get new headers by querying +multiple nodes, called primary and witness nodes.

+

Light clients download new headers committed on chain from a primary. Headers can be verified in two ways: sequentially, +where the block height of headers is serial, or using skipping. This second verification method allows light clients to download headers +with nonconsecutive block height, where some intermediate headers are skipped (see Tendermint Light Client, Figure 1 and Figure 3). +Additionally, light clients are cross-checking new headers obtained from a primary with witnesses to ensure all nodes share the same state.

+

A light client attack occurs when a Byzantine validator sends invalid headers to a light client. +As the light client doesn't execute transactions, it can be deceived into trusting corrupted application state transitions. +For instance, if a light client receives header A from the primary and header B from a witness for the same block height H, +and both headers are successfully verified, it indicates a light client attack. +Note that in this case, either the primary or the witness or both are malicious.

+

The types of light client attacks are defined by analyzing the differences between the conflicting headers. +There are three types of light client attacks: lunatic attack, equivocation attack, and amnesia attack. +For details, see the CometBFT specification.

+

When a light client agent detects two conflicting headers, it will initially verify their traces (see cometBFT detector) using its primary and witness nodes. +If these headers pass successful verification, the Byzantine validators will be identified based on the header's commit signatures +and the type of light client attack. The agent will then transmit this information to its nodes using a LightClientAttackEvidence evidence to be eventually voted on and added to a block. +Note that from a light client agent perspective, it is not possible to establish whether a primary or a witness node, or both, are malicious. +Therefore, it will create and send two evidences: one against the primary (sent to the witness), and one against the witness (sent to the primary). +Both nodes will then verify it before broadcasting it and adding it to the evidence pool. +If an evidence is finally committed to a block, the chain's evidence module will execute it, resulting in the jailing and the slashing of the validators responsible for the light client attack.

+

Light clients are a core component of IBC. In the event of a light client attack, IBC relayers notify the affected chains by submitting an IBC misbehavior message. +A misbehavior message includes the conflicting headers that constitute a light client attack evidence. Upon receiving such a message, +a chain will first verify whether these headers would have convinced its light client. This verification is achieved by checking +the header states against the light client consensus states (see IBC misbehaviour handler). If the misbehaviour is successfully verified, the chain will then "freeze" the +light client, halting any further trust in or updating of its states.

+

Double Signing Attack

+

A double signing attack, also known as equivocation, +occurs when a validator votes for two different blocks in the same round of the CometBFT consensus. +This consensus mechanism operates with multiple voting rounds at each block height, +and it strictly prohibits sending two votes of the same type during a round +(see CometBFT State Machine Overview).

+

When a node observes two votes from the same peer, it will use these two votes to create +a DuplicateVoteEvidence +evidence and gossip it to the other nodes in the network +(see CometBFT equivocation detection). +Each node will then verify the evidence according to the CometBFT rules that define a valid double signing infraction, and based on this verification, they will decide whether to add the evidence to a block. +During the evidence verification process, the signatures of the conflicting votes must be verified successfully. +Note that this is achieved using the public key of the misbehaving validator, along with the chain ID of the chain where the infraction occurred (see CometBFT equivocation verification).

+

Once a double signing evidence is committed to a block, the consensus layer will report the equivocation to the evidence module of the Cosmos SDK application layer. +The application will, in turn, punish the malicious validator through jailing, tombstoning and slashing +(see handleEquivocationEvidence).

+

Decision

+

Light Client Attack

+

In the first part of the feature, we introduce a new endpoint: HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour). +The main idea is to leverage the current IBC misbehaviour handling and update it to solely jail and slash the validators that +performed a light client attack. Note that in this context, we assume that chains connected via a light client +share a subset of the validator set of the provider.

+

This endpoint reuses the IBC client libraries to verify that the misbehaviour headers would have fooled the light client. +Additionally, it’s crucial that the endpoint logic results in the slashing and jailing of validators under the same conditions +as a light client agent detector. Therefore, the endpoint ensures that the two conditions are met: +the headers in the misbehaviour message have the same block height, and +the light client isn’t expired.

+

After having successfully verified a misbehaviour, the endpoint executes the jailing and slashing of the malicious validators similarly as in the evidence module.

+

Double Signing Attack

+

In the second part of the feature, we introduce a new endpoint HandleConsumerDoubleVoting( ctx sdk.Context, evidence *tmtypes.DuplicateVoteEvidence, chainID string, pubkey cryptotypes.PubKey). +Simply put, the handling logic verifies a double signing evidence against a provided +public key and chain ID and, if successful, executes the jailing of the malicious validator who double voted.

+

We define a new +MsgSubmitConsumerDoubleVoting message to report a double voting evidence observed +on a consumer chain to the endpoint of the provider chain. This message contains two fields: +a double signing evidence +duplicate_vote_evidence and a light client header for the infraction block height, +referred to as infraction_block_header. +The latter provides the malicious validator's public key and the chain ID required to verify the signature of the votes contained in the evidence.

+

Note that double signing evidence is not verified using the same conditions as in the implementation CometBFT (see +verify(evidence types.Evidence) method). Specifically, we do not check that the evidence hasn't expired. +More details can be found in the "Current limitations" section below.

+

Upon a successful equivocation verification, the misbehaving validator is jailed for the maximum time +(see DoubleSignJailEndTime +in the SDK evidence module).

+

Current limitations:

+
    +
  • +

    We cannot derive an infraction height from the evidence, so it is only possible to jail validators, not actually slash them. +To explain the technical reasons behind this limitation, let's recap the initial consumer initiated slashing logic. +In a nutshell, consumer heights are mapped to provider heights through VSCPackets, namely through the so called vscIDs. +When an infraction occurs on the consumer, a SlashPacket containing the vscID obtained from mapping the consumer infraction height +is sent to the provider. Upon receiving the packet, the provider maps the consumer infraction height to a local infraction height, +which is used to slash the misbehaving validator. In the context of untrusted consumer chains, all their states, including vscIDs, +could be corrupted and therefore cannot be used for slashing purposes.

    +
  • +
  • +

    For the same reasons explained above, the age of a consumer double signing evidence can't be verified, +either using its infraction height or its unsigned timestamp. Note that changes the jailing behaviour, potentially leading to a validator's jailing based on some "old" evidence from a consumer, which wouldn't occur if the consumer were a standalone chain.

    +
  • +
  • +

    In the first stage of this feature, validators are jailed indefinitely without being tombstoned. +The underlying reason is that a malicious validator could take advantage of getting tombstoned +to avoid being slashed on the provider (see comment).

    +
  • +
  • +

    Currently, the endpoint can only handle equivocation light client attacks. This is because the lunatic attacks require the endpoint to possess the ability to dissociate which header is conflicted or trusted upon receiving a misbehavior message. Without this information, it's not possible to extract the Byzantine validators from the conflicting headers (see comment). In addition, "amnesia" attacks are ignored, similar to CometBFT (see ADR-056).

    +
  • +
+

Consequences

+

Positive

+
    +
  • It is now possible for the provider chain to jail validators who committed +light client or double signing attacks on a consumer chain.
  • +
+

Negative

+
    +
  • N/A
  • +
+

References

+
+ + \ No newline at end of file diff --git a/adrs/adr-005-cryptographic-equivocation-verification.html.html b/adrs/adr-005-cryptographic-equivocation-verification.html.html new file mode 100644 index 0000000000..245a2ab0f4 --- /dev/null +++ b/adrs/adr-005-cryptographic-equivocation-verification.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/adrs/adr-007-pause-unbonding-on-eqv-prop.html b/adrs/adr-007-pause-unbonding-on-eqv-prop.html new file mode 100644 index 0000000000..e0b600350d --- /dev/null +++ b/adrs/adr-007-pause-unbonding-on-eqv-prop.html @@ -0,0 +1,98 @@ + + + + + +Pause validator unbonding during equivocation proposal | Interchain Security + + + + +
Skip to main content
Version: main

ADR 007: Pause validator unbonding during equivocation proposal

+

Changelog

+
    +
  • 2023-05-16: Initial Draft
  • +
  • 2023-11-30: Change the status to rejected
  • +
+

Status

+

Rejected

+

Context

+

Note: ADR rejected as the equivocation proposal was removed by the +cryptographic verification of equivocation feature +(see ADR-005 and +ADR-013).

+

Currently, if an equivocation slashing proposal is created after more than one +week has passed since the equivocation, it is possible that the validator in +question could unbond and get away without being slashed, since the unbonding +period is 3 weeks, and the voting period is 2 weeks. For this reason, it might +be good to pause unbondings for validators named in an equivocation slashing +proposal until the proposal's voting period is over.

+

Decision

+

How

+

Pausing the unbonding period is already possible thanks to the changes in the +staking module of the cosmos-sdk:

+
    +
  • stakingKeeper.PutUnbondingOnHold pauses an unbonding period
  • +
  • stakingKeeper.UnbondingCanComplete unpauses an unbonding period
  • +
+

These methods use a reference counter under the hood, that gets incremented +every time PutUnbondingOnHold is called, and decreased when +UnbondingCanComplete is called instead. A specific unbonding is considered +fully unpaused when its underlying reference counter reaches 0. Therefore, as +long as we safeguard consistency - i.e. we make sure we eventually decrement +the reference counter for each time we have incremented it - we can safely use +this existing mechanism without conflicts with the Completion of Unbonding +Operations system.

+

When pause

+

The unbonding period (if there is any unbonding) should be paused once an +equivocation proposal enters the voting period. For that, the gov module's +hook AfterProposalDeposit can be used.

+

If the hook is triggered with a an equivocation proposal in voting period, then +for each equivocation of the proposal, the unbonding operations of the related +validator that were initiated after the equivocation block time must be paused

+
    +
  • i.e. the underlying reference counter has to be increased.
  • +
+

Note that even after the voting period has started, a proposal can receive +additional deposits. The hook is triggered however at arrival of a deposit, so +a check to verify that the proposal is not already in voting period is +required.

+

When unpause

+

We can use a gov module's hook also here and it is +AfterProposalVotingPeriodEnded.

+

If the hook is triggered with an equivocation proposal, then for each +associated equivocation, the unbonding operations of the related validator that +were initiated between the equivocation block time and the start of the +proposal voting period must be unpaused - i.e. decrease the underlying +reference counter - regardless of the proposal outcome.

+

Consequences

+

Positive

+
    +
  • Validators subject to an equivocation proposal cannot finish unbonding +their tokens before the end of the voting period.
  • +
+

Negative

+
    +
  • A malicious consumer chain could forge slash packets enabling submission of +an equivocation proposal on the provider chain, resulting in the freezing of +validator's unbondings for an undeterminated amount of time.
  • +
  • Misbehavior on a consumer chain can potentially go unpunished, if no one +submits an equivocation proposal in time, or if the proposal doesn't pass.
  • +
+

Neutral

+
    +
  • This feature can't be used for social slashing, because an equivocation +proposal is only accepted if there's a slash log for the related +validator(s), meaning the consumer chain has reported the equivocation to +the provider chain.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html b/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html new file mode 100644 index 0000000000..165473d8ab --- /dev/null +++ b/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/adrs/adr-008-throttle-retries.html b/adrs/adr-008-throttle-retries.html new file mode 100644 index 0000000000..8e971955b4 --- /dev/null +++ b/adrs/adr-008-throttle-retries.html @@ -0,0 +1,133 @@ + + + + + +Throttle with retries | Interchain Security + + + + +
Skip to main content
Version: main

Throttle with retries

ADR 008: Throttle with retries

+

Changelog

+
    +
  • 6/9/23: Initial draft
  • +
  • 6/22/23: added note on consumer pending packets storage optimization
  • +
  • 7/14/23: Added note on upgrade order
  • +
+

Status

+

Accepted

+

Context

+

For context on why the throttling mechanism exists, see ADR 002.

+

Note the terms slash throttling and jail throttling are synonymous, since in Interchain Security a SlashPacket simply jails a validator for downtime infractions.

+

Currently the throttling mechanism is designed so that provider logic (slash meter, etc.) dictates how many SlashPackets can be handled over time. +Throttled SlashPackets are persisted on the provider, leading to multiple possible issues. Namely:

+
    +
  • If SlashPackets or VSCMaturedPackets are actually throttled/queued on the provider, state can grow and potentially lead to a DoS attack. +We have short term solutions around this, but overall they come with their own weaknesses. +See #594.
  • +
  • If a jailing attack described in ADR 002 were actually to be carried out with the current throttling design, we'd likely have to halt the provider, and perform an emergency upgrade and/or migration to clear the queues of SlashPackets that were deemed to be malicious. +Alternatively, validators would just have to tough it out and wait for the queues to clear, during which all/most validators would be jailed. +Right after being jailed, validators would have to unjail themselves promptly to ensure safety. +The coordination required to maintain safety in such a scenario is not ideal.
  • +
+

As a solution, we can improve the throttling mechanism to instead queue/persist relevant data on each consumer, and have consumers retry slash requests as needed.

+

Decision

+

Consumer changes

+

Note the consumer already queues up both SlashPackets and VSCMaturedPackets via AppendPendingPacket. +Those packets are dequeued in every EndBlock in SendPackets and sent to the provider.

+

Instead, we will now introduce the following logic on EndBlock:

+
    +
  • Slash packets will always be sent to the provider once they're at the head of the queue. +However, once sent, the consumer will not send any subsequent VSCMaturedPackets from the queue until the provider responds with an acknowledgement that the sent SlashPacket has been handled, i.e., validator was jailed. +That is, SlashPackets block the sending of subsequent VSCMaturedPackets in the consumer queue.
  • +
  • If two SlashPackets are at the head of the queue, the consumer will send the first SlashPacket, and then wait for a success acknowledgement from the provider before sending the second SlashPacket. +This seems like it'd simplify implementation.
  • +
  • VSCMaturedPackets at the head of the queue (i.e., NOT following a SlashPacket) can be sent immediately, and do not block any other packets in the queue, since the provider always handles them immediately.
  • +
+

To prevent the provider from having to keep track of what SlashPackets have been rejected, the consumer will have to retry the sending of SlashPackets over some period of time. +This can be achieved with an on-chain consumer param, i.e., RetryDelayPeriod. +To reduce the amount of redundant re-sends, we recommend setting RetryDelayPeriod ~ SlashMeterReplenishmentPeriod, i.e., waiting for the provider slash meter to be replenished before resending the rejected SlashPacket.

+

Note to prevent weird edge case behavior, a retry would not be attempted until either a success or failure acknowledgement has been received from the provider.

+

With the behavior described, we maintain very similar behavior to the previous throttling mechanism regarding the timing that SlashPackets and VSCMaturedPackets are handled on the provider. +Obviously the queueing and blocking logic is moved, and the two chains would have to send more messages between one another (only in the case the throttling mechanism is triggered).

+

In the normal case, when no or a few SlashPackets are being sent, the VSCMaturedPackets will not be delayed, and hence unbonding will not be delayed.

+

For the implementation of this design, see throttle_retry.go.

+

Consumer pending packets storage optimization

+

In addition to the mentioned consumer changes, an optimization will need to be made to the consumer's pending packets storage to properly implement the feature from this ADR.

+

The consumer ccv module previously queued "pending packets" to be sent in each EndBlock in SendPackets. +These packets are queued in state with a protobuf list of ConsumerPacketData. +For a single append operation, the entire list is deserialized, then a packet is appended to that list, and the list is serialized again. +See older version of AppendPendingPacket. +That is, a single append operation has O(N) complexity, where N is the size of the list.

+

This poor append performance isn't a problem when the pending packets list is small. +But with this ADR being implemented, the pending packets list could potentially grow to the order of thousands of entries when SlashPackets need to be resent.

+

We can improve the append time for this queue by converting it from a protobuf-esq list, to a queue implemented with sdk-esq code. +The idea is to persist a uint64 index that will be incremented each time you queue up a packet. +You can think of this as storing the tail of the queue. +Then, packet data will be keyed by that index, making the data naturally ordered byte-wise for sdk's iterator. +The index will also be stored in the packet data value bytes, so that the index can later be used to delete certain packets from the queue.

+

Two things are achieved with this approach:

+
    +
  • More efficient packet append/enqueue times
  • +
  • The ability to delete select packets from the queue (previously all packets were deleted at once)
  • +
+

Provider changes

+

The main change needed for the provider is the removal of queuing logic for SlashPackets and VSCMaturedPackets upon being received.

+

Instead, the provider will consult the slash meter to determine if a SlashPacket can be handled immediately. +If not, the provider will return an acknowledgement message to the consumer communicating that the SlashPacket could not be handled, and needs to be sent again in the future (retried).

+

VSCMaturedPackets will always be handled immediately upon being received by the provider.

+

Note spec. Specifically the section on VSC Maturity and Slashing Order. Previously the onus was on the provider to maintain this property via queuing packets and handling them FIFO.

+

Now this property will be maintained by the consumer sending packets in the correct order, and blocking the sending of VSCMaturedPackets as needed. Then, the ordered IBC channel will ensure that SlashPackets and VSCMaturedPackets are received in the correct order on the provider.

+

The provider's main responsibility regarding throttling will now be to determine if a received SlashPacket can be handled via slash meter etc., and appropriately acknowledge to the sending consumer.

+

Handling VSCMaturedPackets immediately

+

Why the provider can handle VSCMatured packets immediately

+

A VSCMaturedPacket communicates to the provider that sufficient time passed on the consumer since the corresponding VSCPacket has been applied (on the consumer) such that infractions committed on the consumer could have been submitted.

+

If the consumer is following the queuing/blocking protocol described, then no bad behavior occurs and the VSC Maturity and Slashing Order property is maintained.

+

If a consumer sends VSCMaturedPackets too leniently -- the consumer is malicious and sends duplicate VSCMaturedPackets, or sends the packets sooner than the CCV protocol specifies -- then the provider needs to handle VSCMaturedPackets immediately to prevent DOS, state bloat, or other issues. +The only possible negative outcome is that the malicious consumer may not be able to jail a validator who should have been jailed. +The malicious behavior only creates a negative outcome for the consumer chain that is being malicious.

+

If a consumer blocks the sending of VSCMaturedPackets, then unbonding operations on the provider will be delayed, but only until the VSC timeout period has elapsed. +At that time, the consumer is removed. +Again the malicious behavior only creates a negative outcome for the consumer chain that is being malicious.

+

Splitting of PRs and Upgrade Order

+

This feature will implement consumer changes in #1024.

+

These changes should be deployed to production for all consumers before the provider changes are deployed to production.

+

In other words, the consumer changes in #1024 are compatible with the current ("v1") provider implementation of throttling that's running on the Cosmos Hub as of July 2023.

+

Once all consumers have deployed the changes in #1024, the provider changes from #1321 can be deployed to production, fully enabling v2 throttling.

+

Consequences

+
    +
  • Consumers will now have to manage their own queues, and retry logic.
  • +
  • Consumers still aren't trustless, but the provider is now less susceptible to mismanaged or malicious consumers.
  • +
  • Recovering from the "jailing attack" is more elegant.
  • +
  • Some issues like #1001 will now be handled implicitly by the improved throttling mechanism.
  • +
  • SlashPackets and VSCMaturedPackets can be handled immediately once received by the provider if the slash meter allows.
  • +
  • In general, we reduce the amount of computation that happens in the provider EndBlock.
  • +
+

Positive

+
    +
  • We no longer have to reason about a "global queue" and a "chain specific queue", and keeping those all in-sync. +Now SlashPackets and VSCMaturedPackets queuing is handled on each consumer individually.
  • +
  • Due to the above, the throttling protocol becomes less complex overall.
  • +
  • We no longer have to worry about throttle related DoS attack on the provider, since no queuing exists on the provider.
  • +
+

Negative

+
    +
  • Increased number of IBC packets being relayed anytime throttling logic is triggered.
  • +
  • Consumer complexity increases, since consumers now have manage queuing themselves, and implement packet retry logic.
  • +
+

Neutral

+
    +
  • Core throttling logic on the provider remains unchanged, i.e., slash meter, replenishment cycles, etc.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/adrs/adr-008-throttle-retries.html.html b/adrs/adr-008-throttle-retries.html.html new file mode 100644 index 0000000000..f45be9a6de --- /dev/null +++ b/adrs/adr-008-throttle-retries.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/adrs/adr-009-soft-opt-out.html b/adrs/adr-009-soft-opt-out.html new file mode 100644 index 0000000000..1dd2274b59 --- /dev/null +++ b/adrs/adr-009-soft-opt-out.html @@ -0,0 +1,51 @@ + + + + + +Soft Opt-Out | Interchain Security + + + + +
Skip to main content
Version: main

Soft Opt-Out

ADR 009: Soft Opt-Out

+

Changelog

+
    +
  • 6/13/23: Initial draft of ADR. Feature already implemented and in production.
  • +
  • 6/19/24: Change status to deprecated
  • +
+

Status

+

Deprecated +Deprecated by Partial Set Security

+

Context

+

Some small validators may not have the resources needed to validate all consumer chains. Therefore a need exists to allow the bottom x% of validators to opt-out of validating a consumer chain. Meaning downtime infractions for these validators are dropped without ever reaching the provider.

+

This document specifies a modification to the ccv protocol which allows the bottom x% of the validator set by power to opt out of validating consumer chains without being jailed or otherwise punished for it. The feature is implemented with entirely consumer-side code.

+

Decision

+

A consumer param exists, known as SoftOptOutThreshold, which is a string decimal in the range of [0, 0.2], that determines the portion of validators which are allowed to opt out of validating that specific consumer.

+

In every consumer beginblocker, a function is ran which determines the so called smallest non opt-out voting power. Validators with voting power greater than or equal to this value must validate the consumer chain, while validators below this value may opt out of validating the consumer chain.

+

The smallest non opt-out voting power is recomputed every beginblocker in UpdateSmallestNonOptOutPower(). In a nutshell, the method obtains the total voting power of the consumer, iterates through the full valset (ordered power ascending) keeping track of a power sum, and when powerSum / totalPower > SoftOptOutThreshold, the SmallestNonOptOutPower is found and persisted.

+

Then, whenever the Slash() interface is executed on the consumer, if the voting power of the relevant validator being slashed is less than SmallestNonOptOutPower for that block, the slash request is dropped and never sent to the provider.

+

Consequences

+

Positive

+
    +
  • Small validators can opt out of validating specific consumers without being punished for it.
  • +
+

Negative

+
    +
  • The bottom x% is still part of the total voting power of the consumer chain. This means that if the soft opt-out threshold is set to 10% for example, and every validator in the bottom 10% opts out from validating the consumer, then a 24% downtime of the remaining voting power would halt the chain. This may be especially problematic during consumer upgrades.
  • +
  • In nominal scenarios, consumers with soft opt out enabled will be constructing slash packets for small vals, which may be dropped. This is wasted computation, but necessary to keep implementation simple. Note that the sdk's full downtime logic is always executed on the consumer, which can be computationally expensive and slow down certain blocks.
  • +
  • In a consumer chain, when a validator that has opted out becomes the proposer, there will naturally be no proposal made and validators would need to move to the next consensus round for the same height to reach a decision. As a result, we would need more time to finalize blocks on a consumer chain.
  • +
+

Neutral

+
    +
  • Validators in the bottom of the valset who don't have to validate, may receive large delegation(s) which suddenly boost the validator to the subset that has to validate. This may catch the validator off guard.
  • +
+

References

+
    +
  • Original issue with some napkin math #784
  • +
+ + \ No newline at end of file diff --git a/adrs/adr-009-soft-opt-out.html.html b/adrs/adr-009-soft-opt-out.html.html new file mode 100644 index 0000000000..bb5cdf94c9 --- /dev/null +++ b/adrs/adr-009-soft-opt-out.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/adrs/adr-010-standalone-changeover.html b/adrs/adr-010-standalone-changeover.html new file mode 100644 index 0000000000..ba6a288991 --- /dev/null +++ b/adrs/adr-010-standalone-changeover.html @@ -0,0 +1,53 @@ + + + + + +Standalone to Consumer Changeover | Interchain Security + + + + +
Skip to main content
Version: main

Standalone to Consumer Changeover

ADR 010: Standalone to Consumer Changeover

+

Changelog

+
    +
  • 6/30/23: Feature completed, first draft of ADR.
  • +
+

Status

+

Implemented

+

Context

+

Stride will be the first consumer to "changeover" from a standalone cosmos blockchain, to a consumer chain secured by the Cosmos Hub. This document outlines the changes made to support this changeover process.

+

Decision

+

Process

+

Prior to the changeover, the consumer chain will have an existing staking keeper and validator set, these may be referred to as the "standalone staking keeper" and "standalone validator set" respectively.

+

The first step in the changeover process is to submit a ConsumerAdditionProposal. If the proposal passes, the provider will create a new IBC client for the consumer at spawn time, with the provider's validator set. A consumer genesis will also be constructed by the provider for validators to query. Within this consumer genesis contains the initial validator set for the consumer to apply after the changeover.

+

Next, the standalone consumer chain runs an upgrade which adds the CCV module, and is properly setup to execute changeover logic.

+

The consumer upgrade height must be reached after the provider has created the new IBC client. Any Interchain Security validators who will run the consumer, but are not a part of the sovereign validator set, must sync up a full node before the consumer upgrade height is reached. The disk state of said full node will be used to run the consumer chain after the changeover has completed.

+

The meat of the changeover logic is that the consumer chain validator set is updated to that which was specified by the provider via the queried consumer genesis. Validators which were a part of the old set, but not the new set, are given zero voting power. Once these validator updates are given to Comet, the set is committed, and in effect 2 blocks later (see FirstConsumerHeight).

+

A relayer then establishes the new IBC connection between the provider and consumer. The CCV channel handshake is started on top of this connection. Once the CCV channel is established and VSC packets are being relayed, the consumer chain is secured by the provider.

+

Changes to CCV Protocol

+
    +
  • Consumer Genesis state is updated to include a PreCCV boolean. When this boolean is set true in the consumer genesis JSON, special logic is executed on InitGenesis to trigger the changeover process on the consumer's first endblocker after the upgrade which adds the CCV module. Note that InitGenesis is not automatically called during chain upgrades, so the consumer must manually call the consumer's InitGenesis method in an upgrade handler.
  • +
  • The ConsumerAdditionProposal type is updated to include a DistributionTransmissionChannel field. This field allows the consumer to use an existing IBC transfer channel to send rewards as a part of the CCV protocol. Consumers that're not changing over from a standalone chain will leave this field blank, indicating that a new transfer channel should be created on top of the same connection as the CCV channel.
  • +
  • The CCV consumer keeper is updated to contain an optional reference to the standalone staking keeper. The standalone staking keeper is used to slash for infractions that happened before the changeover was completed. Ie. any infraction from a block height before the changeover, that is submitted after the changeover, will call the standalone staking keeper's slash method. Note that a changeover consumer's standalone staking keeper becomes a democracy module keeper, so it is possible for a governance token to be slashed.
  • +
+

Consequences

+

Positive

+
    +
  • Existing cosmos chains are now able to onboard over to a consumer chain secured by a provider.
  • +
  • The previous staking keepers for such chains can be transitioned to democracy staking module keepers.
  • +
+

Negative

+
    +
  • The delineation between different types of consumers in this repo becomes less clear. Ie. there is code in the democracy consumer's app.go that only applies to a previously standalone chain, but that file also serves as the base for a normal democracy consumer launched with RS from genesis.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/adrs/adr-010-standalone-changeover.html.html b/adrs/adr-010-standalone-changeover.html.html new file mode 100644 index 0000000000..2d07083aef --- /dev/null +++ b/adrs/adr-010-standalone-changeover.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/adrs/adr-011-improving-test-confidence.html b/adrs/adr-011-improving-test-confidence.html new file mode 100644 index 0000000000..4ad8d2cc5a --- /dev/null +++ b/adrs/adr-011-improving-test-confidence.html @@ -0,0 +1,158 @@ + + + + + +Improving testing and increasing confidence | Interchain Security + + + + +
Skip to main content
Version: main

ADR 011: Improving testing and increasing confidence

+

Changelog

+
    +
  • 2023-08-11: Proposed, first draft of ADR.
  • +
+

Status

+

Proposed

+

Context

+

Testing, QA, and maintenance of interchain-security libraries is an ever-evolving area of software engineering we have to keep incrementally improving. The purpose of the QA process is to catch bugs as early as possible. In an ideal development workflow a bug should never reach production. A bug found in the specification stage is a lot cheaper to resolve than a bug discovered in production (or even in testnet). Ideally, all bugs should be found during the CI execution, and we hope that no bugs will ever even reach the testnet (although nothing can replace actual system stress test under load interacting with users).

+

During development and testnet operation the following types of bugs were the most commonly found:

+
    +
  • improper iterator usage
  • +
  • unbounded array access/iteration
  • +
  • improper input handling and validation
  • +
  • improper cached context usage
  • +
  • non-determinism check (improper use of maps in go, relying on random values)
  • +
  • KV store management and/or how keys are defined
  • +
  • deserialization issues arising from consumer/provider versioning mismatch
  • +
+

Such bugs can be discovered earlier with better tooling. Some of these bugs can induce increases in block times, chain halts, state corruption, or introduce an attack surface which is difficult to remove if other systems have started depending on that behavior.

+

Current state of testing

+

Our testing suites consist of multiple parts, each with their own trade-offs and benefits with regards to code coverage, complexity and confidence they provide.

+

Unit testing

+

Unit testing is employed mostly for testing single-module functionality. It is the first step in testing and often the most practical. While highly important, unit tests often test a single piece of code and don't test relationships between different moving parts, this makes them less valuable when dealing with multi-module interactions.

+

Unit tests often employ mocks to abstract parts of the system that are not under test. Mocks are not equivalent to actual models and should not be treated as such.

+

Out of all the approaches used, unit testing has the most tools available and the coverage can simply be displayed as % of code lines tested. Although this is a very nice and very easy to understand metric, it does not speak about the quality of the test coverage.

+

Since distributed systems testing is a lot more involved, unit tests are oftentimes not sufficient to cover complex interactions. Unit tests are still necessary and helpful, but in cases where unit tests are not helpful e2e or integration tests should be favored.

+

Integration testing

+

With integration testing we test the multi-module interactions while isolating them from the remainder of the system. +Integration tests can uncover bugs that are often missed by unit tests.

+

It is very difficult to gauge the actual test coverage imparted by integration tests and the available tooling is limited. +In interchain-security we employ the ibc-go/testing framework to test interactions in-memory.

+

At present, integration testing does not involve the consensus layer - it is only concerned with application level state and logic.

+

End-to-end testing

+

In our context end-to-end testing comprises of tests that use the actual application binaries in an isolated environment (e.g. docker container). During test execution the inputs are meant to simulate actual user interaction, either by submitting transactions/queries using the command line or using gRPC/REST APIs and checking for state changes after an action has been performed. With this testing strategy we also include the consensus layer in all of our runs. This is the closest we can get to testing user interactions without starting a full testnet.

+

End-to-end testing strategies vary between different teams and projects and we strive to unify our approach to the best of our ability (at least for ICS and gaia).

+

The available tooling does not give us significant (or relevant) line of code coverage information since most of the tools are geared towards analyzing unit tests and simple code branch evaluation.

+

We aim to adapt our best practices by learning from other similar systems and projects such as cosmos-sdk, ibc-go and CometBFT.

+

Decision

+

1. Connect specifications to code and tooling

+

Oftentimes, specifications are disconnected from the development and QA processes. This gives rise to problems where the specification does not reflect the actual state of the system and vice-versa. +Usually specifications are just text files that are rarely used and go unmaintained after a while, resulting in consistency issues and misleading instructions/expectations about system behavior.

+

Decision context and hypothesis

+

Specifications written in a dedicated and executable specification language are easier to maintain than the ones written entirely in text. +Additionally, we can create models based on the specification OR make the model equivalent to a specification.

+

Models do not care about the intricacies of implementation and neither do specifications. Since both models and specifications care about concisely and accurately describing a system (such as a finite state machine), we see a benefit of adding model based tools (such as quint) to our testing and development workflows.

+

Main benefit

+

MBT tooling can be used to generate test traces that can be executed by multiple different testing setups.

+

2. Improve e2e tooling

+

Matrix tests

+

Instead of only running tests against current main branch we should adopt an approach where we also:

+
    +
  • run regression tests against different released software versions (ICS v1 vs v2 vs v3)
  • +
  • run non-determinism tests to uncover issues quickly
  • +
+

Matrix tests can be implemented using CometMock and refactoring our current e2e CI setup.

+

Introducing e2e regression testing

+

This e2e test suite would execute using a cronjob in our CI (nightly, multiple times a day etc.)

+

Briefly, the same set of traces is run against different maintained versions of the software and the main branch. +This would allow us to discover potential issues during development instead of in a testnet scenarios.

+

The most valuable issues that can be discovered in this way are state breaking changes, regressions and version incompatibilities.

+

The setup is illustrated by the image below. +e2e matrix tests

+

This table explains which versions are tested against each other for the same set of test traces:

+
    +
  • ✅ marks a passing test
  • +
  • ❌ marks a failing test
  • +
+
USES: ICS v1 PROVIDERstart chainadd keydelegateundelegateredelegatedowntimeequivocationstop chain
v1 consumer (sdk45,ibc4.3)
v2 consumer (sdk45, ibc4.4)
v3 consumer (sdk47, ibc7)
main consumer
neutron
stride
+

Introducing e2e CometMock tests

+

CometMock is a mock implementation of the CometBFT consensus engine. It supports most operations performed by CometBFT while also being lightweight and relatively easy to use.

+

CometMock tests allow more nuanced control of test scenarios because CometMock can "fool" the blockchain app into thinking that a certain number of blocks had passed. +This allows us to test very nuanced scenarios, difficult edge cases and long-running operations (such as unbonding operations).

+

Examples of tests made easier with CometMock are listed below:

+
    +
  • regression tests
  • +
  • non-determinism tests
  • +
  • upgrade tests
  • +
  • state-breaking changes
  • +
+

With CometMock, the matrix test approach can also be used. The image below illustrates a CometMock setup that can be used to discover non-deterministic behavior and state-breaking changes. +e2e matrix tests

+

This table explains which versions are tested against each other for the same set of test traces:

+
    +
  • ✅ marks a passing test
  • +
  • ❌ marks a failing test
  • +
+
SCENARIOstart chainadd keydelegateundelegateredelegatedowntimeequivocationstop chain
v3 provi + v3 consu
main provi + main consu
commit provi + commit consu
+

Briefly; multiple versions of the application are run against the same CometMock instance and any deviations in app behavior would result in app hash errors (the apps would be in different states after performing the same set of actions).

+

3. Introduce innovative testing approaches

+

When discussing e2e testing, some very important patterns emerge - especially if test traces are used instead of ad-hoc tests written by hand.

+

We see a unique opportunity to clearly identify concerns and modularize the testing architecture.

+

The e2e testing frameworks can be split into a pipeline consisting of 3 parts: model, driver and harness.

+

Model

+

Model is the part of the system that can emulate the behavior of the system under test. +Ideally, it is very close to the specification and is written in a specification language such as quint, TLA+ or similar. +One of the purposes of the model is that it can be used to generate test traces.

+

Driver

+

The purpose of the driver is to accept test traces (generated by the model or written by hand), process them and provide inputs to the next part of the pipeline.

+

Basically, the driver sits between the model and the actual infrastructure on which the test traces are being executed on.

+

Harness

+

Harness is the infrastructure layer of the pipeline that accepts inputs from the driver.

+

There can be multiple harnesses as long as they can perform four things:

+
    +
  • bootstrap a test execution environment (local, docker, k8s…)
  • +
  • accept inputs from drivers
  • +
  • perform the action specified by the driver
  • +
  • report results after performing actions
  • +
+

Consequences

+

The procedure outlined in this ADR is not an all-or-nothing approach. Concepts introduced here do not rely on each other, so this ADR may only be applied partially without negative impact on test coverage and code confidence.

+

Positive

+
    +
  1. introduction of maintainable MBT solutions
  2. +
+
    +
  • improvement over the current "difftest" setup that relies on an opinionated typescript model and go driver
  • +
+
    +
  1. increased code coverage and confidence
  2. +
+
    +
  • using CometMock allows us to run more tests in less time
  • +
  • adding matrix e2e tests allows us to quickly pinpoint differences between code versions
  • +
+

Negative

+

It might be easier to forgo the MBT tooling and instead focus on pure property based testing

+ +

The solutions are potentially expensive if we increase usage of the CI pipeline - this is fixed by running "expensive" tests using a cronjob, instead of running them on every commit.

+

Neutral

+

The process of changing development and testing process is not something that can be thought of and delivered quickly. Luckily, the changes can be rolled out incrementally without impacting existing workflows.

+

References

+
+

Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!

+
+
+ + \ No newline at end of file diff --git a/adrs/adr-011-improving-test-confidence.html.html b/adrs/adr-011-improving-test-confidence.html.html new file mode 100644 index 0000000000..4f4fffa5b7 --- /dev/null +++ b/adrs/adr-011-improving-test-confidence.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/adrs/adr-012-separate-releasing.html b/adrs/adr-012-separate-releasing.html new file mode 100644 index 0000000000..93312d022c --- /dev/null +++ b/adrs/adr-012-separate-releasing.html @@ -0,0 +1,79 @@ + + + + + +Separate Releasing | Interchain Security + + + + +
Skip to main content
Version: main

ADR 012: Separate Releasing

+

Changelog

+
    +
  • 0.0202020202020202: Initial draft of idea in #801
  • +
  • 0.01652892561983471: Put idea in this ADR
  • +
  • 0.05: Reject this ADR
  • +
+

Status

+

Rejected

+

Context

+

Spike results

+

I explored the idea of #801 with this spike branch. Here's my conclusions:

+

Splitting this repo to have multiple go.mods is possible. However there are various intricacies involved in decoupling the package hierarchy to have x/ccv/types as the lowest level dep, with x/ccv/consumer and x/ccv/provider being one dep layer above, with high-level tests depending on all three of the mentioned packages. I'd estimate this decoupling would take 2-5 workdays to finish, and require significant review effort.

+

Why go.mod split is not the way to go

+

Let's take a step back and remember the issue we're trying to solve - We need a clean way to decouple semver/releasing for the consumer and provider modules. After more consideration, splitting up go.mods gives us little benefit in achieving this. Reasons:

+
    +
  • The go.mod dependency system is tied to git tags for the entire repo (ex: require github.com/cometbft/cometbft v0.37.2 refers to a historical tag for the entire cometbft repo).
  • +
  • It'd be an odd dev experience to allow modules to reference past releases of other modules in the same repo. When would we ever want the consumer module to reference a past release of the types module for example?
  • +
  • If we allow for go.mod replace statements to build from local source code, why split up the package deps at all?
  • +
  • Splitting go.mods adds a bunch of complexity with go.work files and all that shiz. VSCode does not play well with multiple module repos either.
  • +
+

Why separate repos is cool but also not the way to go

+

All this considered, the cleanest solution to decoupling semver/releasing for the consumer and provider modules would be to have multiple repos, each with their own go.mod (3-4 repos total including high level tests). With this scheme we could separately tag each repo as changes are merged, they could share some code from types being an external dep, etc.

+

I don't think any of us want to split up the monorepo, that's a lot of work and seems like bikeshedding. There's another solution that's very simple..

+

Decision

+

Slightly adapting the current semver ruleset:

+
    +
  • A library API breaking change to EITHER the provider or consumer module will result in an increase of the MAJOR version number for BOTH modules (X.y.z-provider AND X.y.z-consumer).
  • +
  • A state breaking change (change requiring coordinated upgrade and/or state migration) will result in an increase of the MINOR version number for the AFFECTED module(s) (x.Y.z-provider AND/OR x.Y.z-consumer).
  • +
  • Any other changes (including node API breaking changes) will result in an increase of the PATCH version number for the AFFECTED module(s) (x.y.Z-provider AND/OR x.y.Z-consumer).
  • +
+

Example release flow

+

We upgrade main to use a new version of SDK. This is a major version bump, triggering a new release for both the provider and consumer modules, v5.0.0-provider and v5.0.0-consumer.

+
    +
  • A state breaking change is merged to main for the provider module. We release only a v5.1.0-provider off main.
  • +
  • Another state breaking change is merged to main for the provider module. We release only a v5.2.0-provider off main.
  • +
  • At this point, the latest consumer version is still v5.0.0-consumer. We now merge a state breaking change for the consumer module to main, and consequently release v5.1.0-consumer. Note that v5.1.0-consumer is tagged off a LATER commit from main than v5.2.0-provider. This is fine, as the consumer module should not be affected by the provider module's state breaking changes.
  • +
  • Once either module sees a library API breaking change, we bump the major version for both modules. For example, we merge a library API breaking change to main for the provider module. We release v6.0.0-provider and v6.0.0-consumer off main. Note that most often, a library API breaking change will affect both modules simultaneously (example being bumping sdk version).
  • +
+

Consequences

+

Positive

+
    +
  • Consumer repos have clear communication of what tagged versions are relevant to them. Consumer devs should know to never reference an ICS version that starts with provider, even if it'd technically build.
  • +
  • Consumer and provider modules do not deviate as long as we continually release off a shared main branch. Backporting remains relatively unchanged besides being explicit about what module(s) your changes should affect.
  • +
  • No code changes, just changes in process. Very simple.
  • +
+

Negative

+
    +
  • ~~Slightly more complexity.~~Considerably more complex to manage the ICS library. +This is because ICS needs to support multiple versions of SDK (e.g., 0.45, 0.47, 0.50). +In addition, ICS needs to support a special fork of SDK (with LSM included) for the Cosmos Hub. +This means that instead of focusing on main the development team needs to manage multiple release +branches with different dependency trees.
  • +
  • This solution does not allow having provider and consumer on separate versions of e.g. the Cosmos SDK.
  • +
+

Neutral

+

References

+
+

Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!

+
+
+ + \ No newline at end of file diff --git a/adrs/adr-012-separate-releasing.html.html b/adrs/adr-012-separate-releasing.html.html new file mode 100644 index 0000000000..44c5ecc02d --- /dev/null +++ b/adrs/adr-012-separate-releasing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/adrs/adr-013-equivocation-slashing.html b/adrs/adr-013-equivocation-slashing.html new file mode 100644 index 0000000000..35e4fc73bc --- /dev/null +++ b/adrs/adr-013-equivocation-slashing.html @@ -0,0 +1,103 @@ + + + + + +Slashing on the provider for consumer equivocation | Interchain Security + + + + +
Skip to main content
Version: main

ADR 013: Slashing on the provider for consumer equivocation

+

Changelog

+
    +
  • 1st Sept. 2023: Initial draft
  • +
+

Status

+

Accepted

+

Context

+

This ADR presents some approaches on how to slash on the provider chain validators that performed equivocations on consumer chains. +Currently, the provider chain can receive and verify evidence of equivocation, but it cannot slash the misbehaving validator.

+

In the remainder of this section, we explain how slashing is performed on a single chain and show why slashing on the provider for equivocation on the consumer is challenging.

+

Note that future versions of the Cosmos SDK, CometBFT, and ibc-go could modify the way we slash, etc. Therefore, a future reader of this ADR, should note that when we refer to Cosmos SDK, CometBFT, and ibc-go we specifically refer to their v0.47, v0.37 and v7.3.0 versions respectively.

+

Single-chain slashing

+

Slashing is implemented across the slashing +and staking modules. +The slashing module's keeper calls the staking module's Slash() method, passing among others, the infractionHeight (i.e., the height when the equivocation occurred), the validator's power at the infraction height, and the slashFactor (currently set to 5% in case of equivocation on the Cosmos Hub).

+

Slashing undelegations and redelegations

+

To slash undelegations, Slash goes through all undelegations and checks whether they started before or after the infraction occurred. If an undelegation started before the infractionHeight, then it is not slashed, otherwise it is slashed by slashFactor.

+

The slashing of redelegations happens in a similar way, meaning that Slash goes through all redelegations and checks whether the redelegations started before or after the infractionHeight.

+

Slashing delegations

+

Besides undelegations and redelegations, the validator's delegations need to also be slashed. +This is performed by deducting the appropriate amount of tokens from the validator. Note that this deduction is computed based on the voting power the misbehaving validator had at the height of the equivocation. As a result of the tokens deduction, +the tokens per share +reduce and hence later on, when delegators undelegate or redelegate, the delegators retrieve back less +tokens, effectively having their tokens slashed. The rationale behind this slashing mechanism, as mentioned in the Cosmos SDK documentation

+
+

[...] is to simplify the accounting around slashing. Rather than iteratively slashing the tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, effectively reducing the value of each issued delegator share.

+
+

This approach of slashing delegations does not utilize the +infractionHeight in any way and hence the following scenario could occur:

+
    +
  1. a validator V performs an equivocation at a height Hi
  2. +
  3. a new delegator D delegates to V after height Hi
  4. +
  5. evidence of the equivocation by validator V is received
  6. +
  7. the tokens of delegator D are slashed
  8. +
+

In the above scenario, delegator D is slashed, even though D's voting power did not contribute to the infraction.

+

Old evidence

+

In the single-chain case, old evidence (e.g., from 3 years ago) is ignored. This is achieved through +CometBFT that ignores old evidence based on the parameters MaxAgeNumBlocks and MaxAgeDuration (see here). +Additionally, note that when the evidence is sent by CometBFT to the application, the evidence is rechecked in the evidence module of Cosmos SDK and if it is old, the evidence is ignored. +In Cosmos Hub, the MaxAgeNumBlocks is set to 1000000 (i.e., ~70 days if we assume we need ~6 sec per block) and MaxAgeDuration is set to 172800000000000 ns (i.e., 2 days). Because of this check, we can easily exclude old evidence.

+

Slashing for equivocation on the consumer

+

In the single-chain case, slashing requires both the infractionHeight and the voting power. +In order to slash on the provider for an equivocation on a consumer, we need to have both the provider's infractionHeight and voting power. +Note that the infractionHeight on the consumer chain must be mapped to a height on the provider chain. +Unless we have a way to find the corresponding infractionHeight and power on the provider chain, we cannot slash for equivocation on the consumer in the same way as we would slash in the single-chain case.

+

The challenge of figuring out the corresponding infractionHeight and power values on the provider chain is due to the following trust assumption:

+
    +
  • We trust the consensus layer and validator set of the consumer chains, but we do not trust the application layer.
  • +
+

As a result, we cannot trust anything that stems from the application state of a consumer chain.

+

Note that when a relayer or a user sends evidence through a MsgSubmitConsumerDoubleVoting message, the provider gets access to DuplicateVoteEvidence:

+
type DuplicateVoteEvidence struct {
VoteA *Vote `json:"vote_a"`
VoteB *Vote `json:"vote_b"`

// abci specific information
TotalVotingPower int64
ValidatorPower int64
Timestamp time.Time
}
+

The "abci specific information" fields cannot be trusted because they are not signed. Therefore, +we can use neither ValidatorPower for slashing on the provider chain, nor the Timestamp to check the evidence age. We can get the infractionHeight from the votes, but this infractionHeight corresponds to the infraction height on the consumer and not on the provider chain. +Similarly, when a relayer or a user sends evidence through a MsgSubmitConsumerMisbehaviour message, the provider gets access to Misbehaviour that we cannot use to extract the infraction height, power, or the time on the provider chain.

+

Proposed solution

+

As a first iteration, we propose the following approach. At the moment the provider receives evidence of equivocation on a consumer:

+
    +
  1. slash all the undelegations and redelegations using slashFactor;
  2. +
  3. slash all delegations using as voting power the sum of the voting power of the misbehaving validator and the power of all the ongoing undelegations and redelegations.
  4. +
+

Evidence expiration: Additionally, because we cannot infer the actual time of the evidence (i.e., the timestamp of the evidence cannot be trusted), we do not consider evidence expiration and hence old evidence is never ignored (e.g., the provider would act on 3 year-old evidence of equivocation on a consumer). +Additionally, we do not need to store equivocation evidence to avoid slashing a validator more than once, because we do not slash tombstoned validators and we tombstone a validator when slashed.

+

We do not act on evidence that was signed by a validator consensus key that is pruned when we receive the evidence. We prune a validator's consensus key if the validator has assigned a new consumer key (using MsgAssignConsumerKey) and an unbonding period on the consumer chain has elapsed (see key assignment ADR). Note that the provider chain is informed that the unbonding period has elapsed on the consumer when the provider receives a VSCMaturedPacket and because of this, if the consumer delays the sending of a VSCMaturedPacket, we would delay the pruning of the key as well.

+

Implementation

+

The following logic needs to be added to the HandleConsumerDoubleVoting and HandleConsumerMisbehaviour methods:

+
undelegationsInTokens := sdk.NewInt(0)
for _, v := range k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validatorAddress) {
for _, entry := range v.Entries {
if entry.IsMature(now) && !entry.OnHold() {
// undelegation no longer eligible for slashing, skip it
continue
}
undelegationsInTokens = undelegationsInTokens.Add(entry.InitialBalance)
}
}

redelegationsInTokens := sdk.NewInt(0)
for _, v := range k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validatorAddress) {
for _, entry := range v.Entries {
if entry.IsMature(now) && !entry.OnHold() {
// redelegation no longer eligible for slashing, skip it
continue
}
redelegationsInTokens = redelegationsInTokens.Add(entry.InitialBalance)
}
}

infractionHeight := 0
undelegationsAndRedelegationsInPower = sdk.TokensToConsensusPower(undelegationsInTokens.Add(redelegationsInTokens))
totalPower := validator's voting power + undelegationsAndRedelegationsInPower
slashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)

k.stakingKeeper.Slash(ctx, validatorConsAddress, infractionHeight, totalPower, slashFraction, DoubleSign)
+

Infraction height: We provide a zero infractionHeight to the Slash method in order to slash all ongoing undelegations and redelegations (see checks in Slash, SlashUnbondingDelegation, and SlashRedelegation).

+

Power: We pass the sum of the voting power of the misbehaving validator when the evidence was received (i.e., at evidence height) and the power of all the ongoing undelegations and redelegations. +If we assume that the slashFactor is 5%, then the voting power we pass is power + totalPower(undelegations) + totalPower(redelegations). +Hence, when the Slash method slashes all the undelegations and redelegations it would end up with 0.05 * power + 0.05 * totalPower(undelegations) + 0.05 * totalPower(redelegations) - 0.05 * totalPower(undelegations) - 0.05 * totalPower(redelegations) = 0.05 * power and hence it would slash 5% of the validator's power when the evidence is received.

+

Positive

+

With the proposed approach we can quickly implement slashing functionality on the provider chain for consumer chain equivocations. +This approach does not need to change the staking module and therefore does not change in any way how slashing is performed today for a single chain.

+

Negative

+
    +
  • We definitely slash more when it comes to undelegations and redelegations because we slash for all of them without considering an infractionHeight.
  • +
  • We potentially slash more than what we would have slashed if we knew the voting power at the corresponding infractionHeight in the provider chain.
  • +
  • We slash on old evidence of equivocation on a consumer.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/adrs/adr-013-equivocation-slashing.html.html b/adrs/adr-013-equivocation-slashing.html.html new file mode 100644 index 0000000000..b0c570ed7f --- /dev/null +++ b/adrs/adr-013-equivocation-slashing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/adrs/adr-014-epochs.html b/adrs/adr-014-epochs.html new file mode 100644 index 0000000000..95b8d75cc7 --- /dev/null +++ b/adrs/adr-014-epochs.html @@ -0,0 +1,72 @@ + + + + + +Epochs | Interchain Security + + + + +
Skip to main content
Version: main

ADR 014: Epochs

+

Changelog

+
    +
  • 2024-01-05: Proposed, first draft of ADR.
  • +
  • 2024-02-29: Updated so that it describes the implementation where we store the whole consumer validator set.
  • +
+

Status

+

Accepted

+

Context

+

In every block that the provider valset changes, a VSCPacket must be sent to every consumer and a corresponding VSCMaturedPacket sent back. +Given that the validator powers may change very often on the provider chain (e.g., the Cosmos Hub), this approach results in a large workload for the relayers. +Although the validator powers may change very often, these changes are usually small and have an insignificant impact on the chain's security. +In other words, the valset on the consumers can be slightly outdated without affecting security. +As a matter of fact, this already happens due to relaying delays.

+

As a solution, this ADR introduces the concept of epochs. +An epoch consists of multiple blocks. +The provider sends VSCPackets once per epoch. +A VSCPacket contains all the validator updates that are needed by a consumer chain.

+

Decision

+

The implementation of epochs requires the following changes:

+
    +
  • For each consumer chain, we store the consumer validator set that is currently (i.e., in this epoch) validating the +consumer chain. For each validator in the set we store i) its voting power, and ii) the public key that it is +using on the consumer chain during the current (i.e., ongoing) epoch. +The initial consumer validator set for a chain is set during the creation of the consumer genesis.
  • +
  • We introduce the BlocksPerEpoch param that sets the number of blocks in an epoch. By default, BlocksPerEpoch is +set to be 600 which corresponds to 1 hour, assuming 6 seconds per block. This param can be changed through +a governance proposal. In the provider EndBlock we check BlockHeight() % BlocksPerEpoch() == 0 +to decide when an epoch has ended.
  • +
  • At the end of every epoch, if there were validator set changes on the provider, then for every consumer chain, we +construct a VSCPacket with all the validator updates and add it to the list of PendingVSCPackets. We compute the +validator updates needed by a consumer chain by comparing the stored list of consumer validators with the current +bonded validators on the provider, with something similar to this:
  • +
+
// get the valset that has been validating the consumer chain during this epoch 
currentValidators := GetConsumerValSet(consumerChain)
// generate the validator updates needed to be sent through a `VSCPacket` by comparing the current validators
// in the epoch with the latest bonded validators
valUpdates := DiffValidators(currentValidators, stakingmodule.GetBondedValidators())
// update the current validators set for the upcoming epoch to be the latest bonded validators instead
SetConsumerValSet(stakingmodule.GetBondedValidators())
+

Note that a validator can change its consumer public key for a specific consumer chain an arbitrary amount of times during +a block and during an epoch. Then, when we generate the validator updates in DiffValidators, we have to check whether +the current consumer public key (retrieved by calling GetValidatorConsumerPubKey) is different from the consumer public +key the validator was using in the current epoch.

+

Consequences

+

Positive

+
    +
  • Reduce the cost of relaying.
  • +
  • Reduce the amount of IBC packets needed for ICS.
  • +
  • Simplifies key-assignment code because +we only need to check if the consumer_public_key has been modified since the last epoch to generate an update.
  • +
+

Negative

+
    +
  • Increase the delay in the propagation of validator set changes (but for reasonable epoch lengths on the order of ~hours or less, this is unlikely to be significant).
  • +
+

Neutral

+

N/A

+

References

+
+ + \ No newline at end of file diff --git a/adrs/adr-014-epochs.html.html b/adrs/adr-014-epochs.html.html new file mode 100644 index 0000000000..499c088432 --- /dev/null +++ b/adrs/adr-014-epochs.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/adrs/adr-015-partial-set-security.html b/adrs/adr-015-partial-set-security.html new file mode 100644 index 0000000000..856a27746b --- /dev/null +++ b/adrs/adr-015-partial-set-security.html @@ -0,0 +1,154 @@ + + + + + +Partial Set Security | Interchain Security + + + + +
Skip to main content
Version: main

ADR 015: Partial Set Security

+

Changelog

+
    +
  • 2024-01-22: Proposed, first draft of ADR.
  • +
+

Status

+

Accepted

+

Context

+

Currently, in Replicated Security, the entire validator set of the provider chain is used to secure consumer chains. There are at least three concerns with this approach. +First, a large number of validators might be forced to validate consumer chains they are not interested in securing. +Second, it is costly for small validators to secure additional chains. This concern is only partially addressed through soft opt-out that allows small validators to opt out from validating consumer chains. +Third and for the above reasons, it is challenging for a new consumer chain to join Replicated Security.

+

As a solution, we present Partial Set Security (PSS). As the name suggests, PSS allows for every consumer chain to be secured by only a subset of the provider validator set. +In what follows we propose the exact steps we need to take to implement PSS. This is a first iteration of PSS, and therefore we present the most minimal solution that make PSS possible.

+

Decision

+

In Replicated Security, all the provider validators have to secure every consumer chain (with the exception of those validators allowed to opt out through the soft opt-out feature).

+

In PSS, we allow validators to opt in and out of validating any given consumer chain. +This has one exception: we introduce a parameter N for each consumer chain and require that the validators in top N% of the provider's voting power have to secure the consumer chain. +Validators outside of the top N% can dynamically opt in if they want to validate on the consumer chain.

+

For example, if a consumer chain has N = 95%, then it ultimately receives the same security it receives today with Replicated Security (with a default SoftOptOutThreshold of 5%). +On the other hand, if a consumer chain has N = 0%, then no validator is forced to validate the chain, but validators can opt in to do so instead.

+

For the remainder of this ADR, we call a consumer chain Top N if it has joined as a Top N chain with N > 0 and Opt In chain otherwise. An Opt In consumer chain is secured only by the validators that have opted in to secure that chain.

+

We intend to implement PSS using a feature branch off v4.0.0 interchain security.

+

How do consumer chains join?

+

As a simplification and to avoid chain id squatting, a consumer chain can only join PSS through a governance proposal and not in a permissionless way.

+

However, this proposal type will be modified so that it requires a lower quorum percentage than normal proposal, and every validator who voted "YES" on the proposal will form the consumer chain's initial validator set.

+

Consumer chains join PSS the same way chains now join Replicated Security, namely through a ConsumerAdditionProposal proposal. +We extend ConsumerAdditionProposal with one optional field:

+

uint32 top_N: Corresponds to the percentage of validators that join under the Top N case. +For example, 53 corresponds to a Top 53% chain, meaning that the top 53% provider validators have to validate the proposed consumer chain. +top_N can be 0 or include any value in [50, 100]. A chain can join with top_N == 0 as an Opt In, or with top_N ∈ [50, 100] as a Top N chain.

+

In case of a Top N chain, we restrict the possible values of top_N from (0, 100] to [50, 100]. +By having top_N >= 50 we can guarantee that we cannot have a successful attack, assuming that at most 1/3 of provider validators can be malicious. +This is because, a Top N chain with N >= 50% would have at least 1/3 honest validators, which is sufficient to stop attacks. +Additionally, by having N >= 50% (and hence N > (VetoThreshold = 33.4%)) we enable the top N validators to Veto any ConsumerAdditionProposal for consumer chains they do not want to validate.

+

If a proposal has the top_N argument wrongly set, it should get rejected in [ValidateBasic] (https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/types/proposal.go#L86).

+

In the code, we distinguish whether a chain is Top N or Opt In by checking whether top_N is zero or not.

+

In a future version of PSS, we intend to introduce a ConsumerModificationProposal so that we can modify the parameters of a consumer chain, e.g, a chain that is Opt In to become Top N, etc.

+

State & Query

+

We augment the provider module’s state to keep track of the top_N value for each consumer chain. The key to store this information would be:

+
topNBytePrefix | len(chainID) | chainID
+

To create the above key, we can use ChainIdWithLenKey.

+

Then in the keeper we introduce methods as follows:

+
func (k Keeper) SetTopN(ctx sdk.Context, chainID string, topN uint32)
func (k Keeper) IsTopN(ctx sdk.Context, chainID string) bool
func (k Keeper) IsOptIn(ctx sdk.Context, chainID string) bool

// returns the N if Top N chain, otherwise an error
func (k Keeper) GetTopN(ctx sdk.Context, chainID string) (uint32, error)
+

We also extend the interchain-security-pd query provider list-consumer-chains query to return information on whether a consumer chain is an Opt In or a Top N chain and with what N. +This way, block explorers can present informative messages such as "This chain is secured by N% of the provider chain" for consumer chains.

+

How do validators opt in?

+

A validator can opt in by sending a new type of message that we introduce in tx.proto.

+
message MsgOptIn {
// the chain id of the consumer chain to opt in to
string chainID = 1;
// the provider address of the validator
string providerAddr = 2;
// (optional) the consensus public key to use on the consumer
optional string consumerKey = 3;
}
+

Note that in a Top N consumer chain, the top N% provider validators have to validate the consumer chain. +Nevertheless, validators in the bottom (100 - N)% can opt in to validate as well. +Provider validators that belong or enter the top N% validators are automatically opted in to validate a Top N consumer chain. +This means that if a validator V belongs to the top N% validators but later falls (e.g., due to undelegations) to the bottom (100 - N)%, V is still considered opted in and has to validate unless V sends a MsgOptOut message (see below). +By automatically opting in validators when they enter the top N% validators and by forcing top N% validators to explicitly opt out in case they fall to the (100 - N)% bottom validators we simplify the design of PSS.

+

Note that a validator can send a MsgOptIn message even if the consumer chain is not yet running. To do this we reuse the IsConsumerProposedOrRegistered. If the chainID does not exist, the MsgOptIn should fail, as well as if the provider address does not exist.

+

Optionally, a validator that opts in can provide a consumerKey so that it assigns a different consumer key (from the provider) to the consumer chain. +Naturally, a validator can always change the consumer key on a consumer chain by sending a MsgAssignConsumerKey message at a later point in time, as is done in Replicated Security.

+

State & Query

+

For each validator, we store a pair (blockHeight, isOptedIn) that contains the block height the validator opted in and whether the validator is currently opted in or not, under the key:

+
optedInBytePrefix | len(chainID) | chainID | addr
+

By using a prefix iterator on optedInBytePrefix | len(chainID) | chainID we retrieve all the opted in validators.

+

We introduce the following Keeper methods.

+
// returns all the validators that have opted in on chain `chainID`
func (k Keeper) GetOptedInValidators(ctx sdk.Context, chainID string) []Validators

func (k Keeper) IsValidatorOptedIn(ctx sdk.Context, chainID string, val Validator) bool
+

We introduce the following two queries:

+
interchain-security-pd query provider optedInValidators $chainID
interchain-security-pd query provider hasToValidate $providerAddr
+

One query to retrieve the validators that are opted in and hence the validators that need to validate the consumer chain and one query that given a validator's address returns all the chains this validator has to validate.

+

When do validators opt in?

+

As described earlier, validators can manually opt in by sending a MsgOptIn message. +Additionally, in a Top N chain, a validator is automatically opted in when it moves from the bottom (100 - N)% to the top N% validators.

+

Lastly, validators can also opt in if they vote Yes during the ConsumerAdditionProposal that introduces a consumer chain. +This simplifies validators operations because they do not have to send an additional message to opt in.

+

Because the Tally method deletes the votes after reading them, we cannot check the votes of the validators after the votes have been tallied. +To circumvent this, we introduce a hook for AfterProposalVote and keep track of all the votes cast by a validator. +If a validator casts more than one vote, we only consider the latest vote. +Finally, we only consider a validator has opted in if it casts a 100% Yes vote in case of a weighted vote.

+

How do validators opt out?

+

Validators that have opted in on a chain can opt out by sending the following message:

+
message MsgOptOut {
// the chain id of the consumer chain to opt out from
string chainID = 1;
// the provider address of the validator
string providerAddr = 2;
}
+

Validators can only opt out after a consumer chain has started and hence the above message returns an error if the chain with chainID is not running. +Additionally, a validator that belongs to the top N% validators cannot opt out from a Top N chain and hence a MsgOptOut would error in such a case.

+

State & Query

+

We also update the state of the opted-in validators when a validator has opted out by removing the opted-out validator.

+

Note that only opted-in validators can be punished for downtime on a consumer chain. +For this, we use historical info of all the validators that have opted in; We can examine the blockHeight stored under the key optedInBytePrefix | len(chainID) | chainID | addr to see if a validator was opted in. +This way we can jail validators for downtime knowing that indeed the validators have opted in at some point in the past. +Otherwise, we can think of a scenario where a validator V is down for a period of time, but before V gets punished for downtime, validator V opts out, and then we do not know whether V should be punished or not.

+

When does a consumer chain start?

+

A Top N consumer chain always starts at the specified date (spawn_time) if the ConsumerAdditionProposal has passed. +An Opt In consumer chain only starts if at least one validator has opted in. We check this in BeginBlockInit:

+
func (k Keeper) BeginBlockInit(ctx sdk.Context) {
propsToExecute := k.GetConsumerAdditionPropsToExecute(ctx)

for _, prop := range propsToExecute {
chainID := prop.ChainId
if !k.IsTopN(ctx, chainID) && len(k.GetOptedInValidators(ctx, chainID)) == 0 {
// drop the proposal
ctx.Logger().Info("could not start chain because no validator has opted in")
continue
}
...
+

How do we send the partial validator sets to the consumer chains?

+

A consumer chain should only be validated by opted in validators. +We introduce logic to do this when we queue the VSCPackets. +The logic behind this, is not as straightforward as it seems because CometBFT does not receive the validator set that has to validate a chain, but rather a delta of validator updates. +For example, to remove an opted-out validator from a consumer chain, we have to send a validator update with a power of 0, similarly to what is done in the assignment of consumer keys. +We intend to update this ADR at a later stage on how exactly we intend to implement this logic.

+

How do we distribute rewards?

+

Currently, rewards are distributed as follows: The consumer periodically sends rewards on the provider ConsumerRewardsPool address. +The provider then transfers those rewards to the fee collector address and those transferred rewards are distributed to validators and delegators.

+

In PSS, we distribute rewards only to validators that actually validate the consumer chain. +To do this, we have a pool associated with each consumer chain and consumers IBC transfer the rewards to this pool. +We then extract the rewards from each consumer pool and distribute them to the opted in validators.

+

Note that we only distribute rewards to validators that have been opted in for some time (e.g., 10000 blocks) to avoid cases where validators opt in just to receive rewards and then opt out immediately afterward.

+

Misbehaviour

+

Fraud votes

+

In an Opt In chain, a set of validators might attempt to perform an attack. To deter such potential attacks, PSS allows for the use of fraud votes. +A fraud vote is a governance proposal that enables the slashing of validators that performed an attack. +Due to their inherent complexity, we intend to introduce fraud votes in a different ADR and at a future iteration of PSS.

+

Double signing

+

We do not change the way slashing for double signing and light client attacks functions. +If a validator misbehaves on a consumer, then we slash that validator on the provider.

+

Downtime

+

We do not change the way downtime jailing functions. +If a validator is down on a consumer chain for an adequate amount of time, we jail this validator on the provider but only if the validator was opted in on this consumer chain in the recent past.

+

Consequences

+

Positive

+
    +
  • +

    Easier for new consumer chains to consume the provider's chain economic security because proposals are more likely to pass if not everyone is forced to validate.

    +
  • +
  • +

    Smaller validators are not forced to validate chains anymore if they do not want to.

    +
  • +
  • +

    We can deprecate the soft opt-out implementation.

    +
  • +
+

Negative

+
    +
  • A consumer chain does not receive the same economic security as with Replicated Security (assuming the value of SoftOptOutThreshold is 5%), unless it is a Top N chain with N >= 95%.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/adrs/adr-015-partial-set-security.html.html b/adrs/adr-015-partial-set-security.html.html new file mode 100644 index 0000000000..9a6b436ff3 --- /dev/null +++ b/adrs/adr-015-partial-set-security.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/adrs/adr-016-securityaggregation.html b/adrs/adr-016-securityaggregation.html new file mode 100644 index 0000000000..852f8cdc46 --- /dev/null +++ b/adrs/adr-016-securityaggregation.html @@ -0,0 +1,115 @@ + + + + + +Security aggregation | Interchain Security + + + + +
Skip to main content
Version: main

ADR 016: Security aggregation

+

Changelog

+
    +
  • 2024-04-24: Initial draft of ADR
  • +
+

Status

+

Proposed

+

Context

+

Security Aggregation enables staking of tokens from external sources such as Ethereum or Bitcoin to Cosmos blockchains. By integrating Security Aggregation, a Cosmos blockchain can be secured by both native tokens and external tokens (e.g. ETH, BTC).

+

Security Aggregation consists of the following parts:

+
    +
  • A mechanism for delegating external tokens to Cosmos validators, such as Babylon or EigenLayer AVS contract.
  • +
  • An oracle that tracks how much external stake has been delegated to each Cosmos validator and provides price feeds for external tokens.
  • +
  • Power mixing: a mechanism to combine external and native stake to derive the power of each validator.
  • +
  • A reward distribution protocol that enables sending back rewards to the external source.
  • +
+

External staking information is received from an oracle together with price information of related stakes. +The CosmosLayer derives validator powers based on external and native staking information and initiates rewarding of external depositors.

+

This ADR describes the Cosmos modules of the solution.

+

Alternative Approaches

+

Rewards

+

As an alternative to sending rewards back to the external chains, stakers could be rewarded on the Cosmos chain. +This would require a mapping of external addresses to addresses on Cosmos chain for each staker on external source. +In addition detailed external staking information such as staking addresses, amount of stakes per staker and validator, etc. have to be provided by the oracle.

+

Decision

+

Rewards will be sent back to external chains instead of paying rewards for external stakers on Cosmos chain

+

Rewards will be sent back to external chains instead of paying rewards for external stakers on Cosmos chain

+
    +
  • due to amount of additional staking information to be sent and tracked by the oracle
  • +
  • due to the additional complexity of managing external and Cosmos addresses
  • +
+

Detailed Design

+

The Power Mixing feature and Reward Distribution protocol are an integral part of the Security Aggregation solution. +The Power Mixing module provides the capability of deriving validator power based on stake originated from external sources such as Ethereum/Bitcoin and the native staking module. +The Reward Distribution manages the process of sending rewards to external stakers.

+

Power Mixing

+

Power Mixing provides the final validator powers based on staking information of the native chain and the external stakes. The information about external staking and related price feeds are received from an oracle. +Once the final validator powers are determined the result is submitted to the underlying CometBFT consensus layer by updating the validator set.

+

Requirements:

+
    +
  • validator updates are performed on each EndBlock
  • +
  • a validator's power is determined based on its native on-chain stakes and external stakes
  • +
  • price information of staked tokens is used to determine a validator’s power, e.g. price ratio (price of native on-chain token / price of external stake)
  • +
  • price information of native/external tokens are received from an oracle
  • +
  • staking information from external sources received from the oracle
  • +
  • native staking information are received from the Cosmos SDK Staking Module
  • +
  • set of validator stakes from oracle always have the current price, full set of validators, and current stakes
  • +
+

The Power Mixing implementation

+
    +
  • queries current validators and their powers from x/staking +and from oracle (see below).
  • +
  • calculates power updates by mixing power values of external and internal sources +Following pseudocode snippet shows a possible implementation of how power mixing +feature works.
  • +
+
// PowerSource is an abstract entity providing validator powers which
// are used by the mixer. This can be an oracle, staking module or an
// IBC connected bridge.
type PowerSource interface {
GetValidatorUpdates() []abci.ValidatorUpdate
}

// MixPowers calculates power updates by mixing validator powers from different sources
func (k *Keeper) MixPowers(source ...PowerSource) []abci.ValidatorUpdate {
var valUpdate []abci.ValidatorUpdate
for _, ps := range source {
// mix powers from two sets of validator updates an return set of validator updates
// with aggregated powers
valUpdate = mixPower(valUpdate, ps.GetValidatorUpdates())
}
return valUpdate
}

func (k *keeper) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
// GetPowerSources (including local staking module)
registeredPowerSource := GetPowerSources()
return k.MixPowers(registeredPowerSource...)
}
+

Integration with ICS provider

+

The provider module updates the validator set on CometBFT instead of the SDK staking module (x/staking). The provider implementation will intervene in this behavior and ensure that the validator updates are taken from the Power Mixing feature.

+

External power sources are managed by the provider module. Only registered power sources can provide input to the Power Mixing feature. +Power sources will be assigned a unique identifier which will be used by the oracle, provider module and the power mixing and rewarding feature.

+

Updates with the next validator set are sent to consumer chains on each epoch (see EndBlockVSU()). +When collecting the validator updates for each consumer chain (see QueueVSCPackets()), the validator powers of the bonded validators will be updated with the validator powers from the external sources using the Power Mixing module. +These updates are sent as part of the VSC packets to all registered consumer chains.

+

Integration with ICS consumer

+

Consumer chains receive validator updates as part of VSC packets from the provider. +These packets contain validator powers which were already mixed with external staked powers.

+

Queries

+
// GetValidatorUpdates returns the power mixed validator results from the provided sources
service Query {
rpc GetValidatorUpdates(PowerMixedValUpdateRequest) PowerMixedValUpdateResponse {};
}

// PowerMixedValUpdateRequest contains the list of power sources on which the
// power mixing should be based on
message PowerMixedValUpdateRequest {
repeated PowerSource sources;
}

// PowerMixedValUpdateResponse returns the validator set with the updated powers
// from the power mixing feature
message PowerMixedValUpdateResponse {
repeated abci.ValidatorUpdate val_set
}
+

The following queries will be provided by the oracle

+
service Query {
rpc GetExtValidators(GetExtValidatorRequest) returns (ExtValidatorsResponse) {
option (google.api.http).get = "oracle/v1/get_validators";
};
}

message GetExtValidatorRequest {}

// ExtValidatorsResponse is the response from GetExtValidators queries
message ExtValidatorsResponse {
repeated ExtValPower powers;
}

// ExtValPower represents a validator with its staking and token information,
// where:
// `power_source_identifier` is the identifier of the registered power source
// `validator_address` is the address of the validator
// `stakes` is the total amount of stakes for a validator
// `denom` is the source token of the stake e.g. ETH,BTC
// `price_ratio` is the ratio of price of the external token to the price of the 'local' token
message ExtValPower {
string power_source_identifier;
string validator_address;
uint64 stakes;
string denom;
float price_ratio;
}

// GetPrice returns a price feed for a given token
service Query {
rpc GetPrice(GetPriceRequest) returns (GetPriceResponse) {
option (google.api.http).get = "/oracle/v1/get_price";
};
}
+

For security reasons the amount of external stakes needs to be limited. Limitation of external staking could be driven by governance and is not subject of this version of the ADR.

+

Reward Handler

+

For native staked tokens the Distribution Module of the Cosmos SDK is taking care of sending the rewards to stakers. +For stakes originated from external chains (Ethereum/Bitcoin) the Reward Handler module sends rewards to EigenLayer/Babylon. +The transfer of rewards is done using a bridge between the Cosmos chain and the external provider chain.

+

Note: currently there's no support paying rewards on EigenLayer (see here)

+

Consequences

+

Positive

+
    +
  • Allow external depositors to stake their tokens to secure a Cosmos chain
  • +
+

Negative

+
    +
  • Dependency to external sources e.g (price feeds) for validator power calculation
  • +
  • Security impact
  • +
+

Neutral

+
    +
  • Additional complexity for staking
  • +
+

Questions:

+
    +
  • Slashing: subject of this ADR? (Defined but not activated currently on EigenLayer).
  • +
+

References

+
+ + \ No newline at end of file diff --git a/adrs/adr-016-securityaggregation.html.html b/adrs/adr-016-securityaggregation.html.html new file mode 100644 index 0000000000..ef25625a6a --- /dev/null +++ b/adrs/adr-016-securityaggregation.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/adrs/adr-017-allowing-inactive-validators.html b/adrs/adr-017-allowing-inactive-validators.html new file mode 100644 index 0000000000..22683dc422 --- /dev/null +++ b/adrs/adr-017-allowing-inactive-validators.html @@ -0,0 +1,99 @@ + + + + + +ICS with Inactive Provider Validators | Interchain Security + + + + +
Skip to main content
Version: main

ADR 017: ICS with Inactive Provider Validators

+

Changelog

+
    +
  • 15th May 2024: Initial draft
  • +
+

Status

+

Proposed

+

Context

+

Currently, only validators in the active set on the provider can validate on consumer chains, which limits the number of validators that can participate in Interchain Security (ICS). +Validators outside of the active set might be willing +to validate on consumer chains, but we might not want to make the provider validator set larger, e.g. to not put more strain on the consensus engine. +This runs the risk of leaving consumer chains with too few validators.

+

The purpose of this ADR is to allow validators that are not part of the consensus process on the provider chain (because they are inactive) +to validate on consumer chains.

+

In the context of this ADR, "consensus validator set" is the set of validators participating in the consensus protocol, and "staking validator set" is the set of validators viewed as active by the staking module.

+

Currently, the staking module, provider module, and CometBFT interact in this way:

+

inactivevals_before.png

+

The staking module keeps a list of validators. The MaxValidators validators with the largest amount of stake are "active" validators. MaxValidators is a parameter of the staking module. The staking module sends these validators to CometBFT to inform which validators make up the next consensus validators, that is, the set of validators participating in the consensus process. Separately, the provider module reads the list of bonded validators and sends this to the consumer chain, after shaping it according to which validators are opted in and the parameters set by the consumer chain for allowlist, denylist, etc.

+

Decision

+

The proposed solution to allow validators that are not participating in the consensus process on the provider (inactive validators) is to change 3 main things:

+

a) increase the MaxValidators parameter of the staking module

+

b) do not take the updates for CometBFT directly from the bonded validators in the staking module, by wrapping the staking modules EndBlocker with a dummy EndBlocker that doesn't return any validator updates. Instead, we adjust the provider module to return validator updates on its EndBlocker. These validator updates are obtained by filtering the bonded validators to send only the first MaxProviderConsensusValidators (sorted by largest amount of stake first) many validators to CometBFT

+

c) use the enlarged list of bonded validators from the staking module as basis for the validator set that the provider module sends to consumer chains (again after applying power shaping and filtering out validatiors that are not opted in).

+

In consequence, the provider chain can keep a reasonably-sized consensus validator set, while giving consumer chains a much larger pool of potential validators.

+

inactivevals_after.png

+

Some additional considerations:

+
    +
  • Migration: In the migration, the last consensus validator set will be set to the last active validator set from the view of the staking module. Existing consumer chains are migrated to have a validator set size cap (otherwise, they could end up with a huge validator set including all the staking-but-not-consensus-active validators from the provider chain)
  • +
  • Slashing: Validators that are not part of the active set on the provider chain can still be jailed for downtime on a consumer chain (via an Interchain Security SlashPacket sent to the provider, who will then jail the validator), but they are not slashed for downtime on the provider chain. +This is achieved without any additional changes to the slashing module, because the slashing module checks for downtime by looking at the consensus participants reported by CometBFT, and thus with the proposed solution, validators that are not part of the consensus validators on the provider chain are not considered for downtime slashing (see https://github.com/cosmos/cosmos-sdk/blob/v0.47.11/x/slashing/abci.go#L22).
  • +
  • Rewards: Validators that are not part of the active set on the provider chain can still receive rewards on the consumer chain, but they do not receive rewards from the provider chain. This change is +achieved without further changes to staking or reward distributions, because similar to downtime, rewards are based on the consensus validator set (see https://github.com/cosmos/cosmos-sdk/blob/v0.47.11/x/distribution/abci.go#L28)
  • +
+

Changes to the state

+

The following changes to the state are required:

+
    +
  • Introduce the MaxProviderConsensusValidators parameter to the provider module, which is the number of validators that the provider module will send to consumer chains.
  • +
  • Store the provider consensus validator set in the provider module state under the LastProviderConsensusValsPrefix key. This is the last set of validators that the provider sent to the consensus engine. This is needed to compute the ValUpdates to send to the consensus engine (by diffing the current set with this last sent set).
  • +
  • Increase the MaxValidators parameter of the staking module to the desired size of the potential validator +set of consumer chains.
  • +
+

Risk Mitigations

+

To mitigate risks from validators with little stake, we introduce a minimum stake requirement for validators to be able to validate on consumer chains, which can be set by each consumer chain independently, with a default value set by the provider chain.

+

Additionally, we independently allow individual consumer chains to disable this feature, which will disallow validators from outside the provider active set from validating on the consumer chain and revert them to the previous behaviour of only considering validators of the provider that are part of the active consensus validator set.

+

Additional risk mitigations are to increase the active set size slowly, and to monitor the effects on the network closely. For the first iteration, we propose to increase the active set size to 200 validators (while keeping the consensus validators to 180), thus letting the 20 validators with the most stake outside of the active set validate on consumer chains.

+

Consequences

+

Positive

+
    +
  • Validators outside of the active set can validate on consumer chains without having an impact on the consensus engine of the provider chain
  • +
  • Consumer chains can have a much larger validator set than the provider chain if they prefer this e.g. for decentralization reasons
  • +
  • Consumer chain teams can, with much less cost than today, start up their own consumer chain node to keep the chain running (in a centralized manner) even if no hub validators have opted in to validate on the chain. This is useful to stop the chain from ending up with an empty validator set and becoming recoverable only with a hardfork
  • +
+

Negative

+

Allowing validators from the inactive set brings with it some additional risks. +In general, consumer chains will now face some of the problems also faced by standalone chains. It’s reasonable to assume that the validator set on the hub has a minimum amount of operational quality due to being battle tested and decentralized, and consumer chains with validators from outside the hub active set cannot rely on this as much anymore.

+

Sybil attacks

+

With the restricted size of the active set today, it’s clear that the set is at least minimally competitive and it is not trivial to spin up multiple nodes as a validator.

+

When we make the “potential validator set” much larger, we should assume that it becomes much less competitive to be part of that set, and thus trivial for single entities to control many of those validators.

+

Reputational damage is not a deterrent

+

For validators in the active set, we typically assume that if they would misbehave, they pay a large reputational cost. This represents delegators deciding to switch validators (potentially even on chains other than the one the misbehaviour happened on), and loss of credibility in the ecosystem. With the much larger active set, it seems prudent to assume that reputational damage is not a deterrent for many validators. They might only have minimal amounts of delegated stake and control most of it themselves, so they might not be deterred from performing actions that would usually bring reputational damage.

+

Additional negative consequences

+
    +
  • The provider keeper will need to implement the staking keeper interface, and modules need to be wired up to either the staking or provider keeper, depending on whether they need the consensus or staking validator set
  • +
  • This will impact how future modules are integrated, since we will need to consider whether those modules should consider the consensus validators or the bonded validators (which other modules might assume to be the same)
  • +
+

Neutral

+
    +
  • There might be validators that are bonded, but not validating on any chain at all. This is not a problem, but it might be a bit confusing.
  • +
+

Alternative considerations

+

Modifying the staking module

+

We could instead adapt the staking module with a similar change. +This might be better if it turns out that the staking module active set is used in many other places.

+

Allowing unbonding validators to validate

+

Instead of increasing the active set size, we could allow validators that are unbonded (but still exist on the provider) to validate consumer chains. +For this, we would need to:

+
    +
  • Modify the VSC updates to consider the set of all validators, even unbonded ones, instead of just active ones
  • +
  • Adjust our downtime jailing/equivocation slashing logic to work correctly with unbonded validators. This is very hard, because redelegations are not usually tracked for unbonded validators.
  • +
+

References

+
    +
  • Security Aggregation has similar concerns where the staking validator set will differ from the consensus validator set
  • +
+ + \ No newline at end of file diff --git a/adrs/adr-017-allowing-inactive-validators.html.html b/adrs/adr-017-allowing-inactive-validators.html.html new file mode 100644 index 0000000000..e0564c27f0 --- /dev/null +++ b/adrs/adr-017-allowing-inactive-validators.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/adrs/intro.html b/adrs/intro.html new file mode 100644 index 0000000000..66d39b2934 --- /dev/null +++ b/adrs/intro.html @@ -0,0 +1,62 @@ + + + + + +Overview | Interchain Security + + + + +
Skip to main content
Version: main

Overview

+

This is a location to record all high-level architecture decisions in the Interchain Security project.

+

You can read more about the Architecture Decision Record (ADR) concept in this blog post.

+

An ADR should provide:

+
    +
  • Context on the relevant goals and the current state
  • +
  • Proposed changes to achieve the goals
  • +
  • Summary of pros and cons
  • +
  • References
  • +
  • Changelog
  • +
+

Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and +justification for a change in architecture, or for the architecture of something +new. The spec is much more compressed and streamlined summary of everything as +it is or should be.

+

If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match.

+

Note the context/background should be written in the present tense.

+

To suggest an ADR, please make use of the ADR template provided.

+

Table of Contents

+

Accepted

+ +

Proposed

+ +

Rejected

+ +

Deprecated

+
+ + \ No newline at end of file diff --git a/adrs/intro.html.html b/adrs/intro.html.html new file mode 100644 index 0000000000..ccd2f19f7b --- /dev/null +++ b/adrs/intro.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/assets/css/styles.7c672362.css b/assets/css/styles.7c672362.css new file mode 100644 index 0000000000..4b32ac69ed --- /dev/null +++ b/assets/css/styles.7c672362.css @@ -0,0 +1 @@ +.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500);--docsearch-searchbox-shadow:inset 0 0 0 1px var(--docsearch-primary-color)}*,:after,:before{box-sizing:border-box}.antialiased,html{-moz-osx-font-smoothing:grayscale}html .menu__link:hover,html .table-of-contents__link--active,html .table-of-contents__link:hover{text-shadow:.1px .1px 0 var(--ifm-font-color-base),-.1px -.1px 0 var(--ifm-font-color-base),.1px -.1px 0 var(--ifm-font-color-base),-.1px .1px 0 var(--ifm-font-color-base),-.1px 0 0 var(--ifm-font-color-base),.1px 0 0 var(--ifm-font-color-base),0 .1px 0 var(--ifm-font-color-base),0 -.1px 0 var(--ifm-font-color-base)}.markdown,html .markdown{--ifm-heading-vertical-rhythm-bottom:1}.hover\:underline:hover,.underline,html .footer__link-item:hover,html .theme-doc-markdown a{text-decoration-line:underline}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}.clean-list,.containsTaskList_mC6p,.details_lb9f>summary,.dropdown__menu,.menu__list{list-style:none}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}html{-webkit-font-smoothing:antialiased;color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);text-rendering:optimizelegibility}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width);padding:0 var(--ifm-spacing-horizontal);width:100%}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.px-0,.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.items-center,.menuExternalLink_NmtK,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width);padding:0 var(--ifm-spacing-horizontal);width:100%}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size)}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}html,html .navbar{background-color:var(--ifm-background-color)}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_EoeP .wordWrapButtonIcon_Bwma{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.admonitionHeading_Gvgb,.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);color:var(--ifm-font-color-base);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}.button.button--secondary.button--outline:not(.button--active):not(:hover),.text-docusaurusColorBase,html .DocSearch-Button .DocSearch-Search-Icon,html .DocSearch-Hits mark{color:var(--ifm-font-color-base)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card--full-height{height:100%}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child),.pb-0{padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}#nprogress,.dropdown__menu,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);text-decoration:none}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}.footer__links,.mb-5{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item{margin-top:0}.admonitionContent_BuS1>:last-child,.collapsibleContent_i85q p:last-child,.details_lb9f>summary>p:last-child,.footer__items,html .theme-doc-markdown li:last-child li:last-child{margin-bottom:0}.codeBlockStandalone_MEMb,.p-0,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.navbar-sidebar,.navbar-sidebar__backdrop{opacity:0;top:0;transition-duration:var(--ifm-transition-fast);transition-timing-function:ease-in-out;bottom:0;left:0;visibility:hidden}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color);text-decoration:none}.menu__caret:before,.menu__link--sublist-caret:after{height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;content:"";filter:var(--ifm-menu-link-sublist-icon-filter)}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.flex,.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.h-full,.navbar__logo img,body,html{height:100%}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand,html .theme-doc-sidebar-container>div:first-child>a{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{-webkit-appearance:none;appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);position:fixed;transform:translate3d(-100%,0,0);transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;position:fixed;right:0;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.hover\:shadow-lg:hover,.shadow,.shadow-none,html .navbar,html .pagination-nav>a:hover,html[data-theme=dark] .navbar-sidebar__brand{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.transform,html .theme-back-to-top-button{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination__link:hover{text-decoration:none}.pagination-nav{grid-gap:var(--ifm-spacing-horizontal);display:grid;gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover);text-decoration:none}.pagination-nav__link--next{grid-column:2/3;text-align:right}.col-span-2,html .pagination-nav>a{grid-column:span 2/span 2}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0;overflow-x:auto;padding-left:0}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.transition,.transition-all{transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec;--ifm-color-primary:#fff;--ifm-color-primary-dark:#e6e6e6;--ifm-color-primary-darker:#d9d9d9;--ifm-color-primary-darkest:#b3b3b3;--ifm-color-primary-light:#fff;--ifm-color-primary-lighter:#fff;--ifm-color-primary-lightest:#fff;--ifm-background-color:#000;--docusaurus-highlighted-code-line-bg:#00000054;--docsearch-modal-background:#000!important;--docsearch-highlight-color:#ffffff70!important;--docsearch-hit-background:#181818ab!important;--docsearch-key-gradient:linear-gradient(-26.5deg,#5d5d5d,#3c3c3c)!important;--docsearch-key-shadow:inset 0 -2px 0 0 #353535,inset 0 0 1px 1px #7a7a7b,0 2px 2px 0 #2d2d2d4d!important}:root{--docusaurus-progress-bar-color:var(--ifm-color-primary);--ifm-color-primary:#1a45f0;--ifm-color-primary-dark:#000;--ifm-color-primary-darker:#000;--ifm-color-primary-darkest:#000;--ifm-color-primary-light:#000;--ifm-color-primary-lighter:#000;--ifm-color-primary-lightest:#000;--ifm-code-font-size:95%;--ifm-breadcrumb-item-background-active:#0000;--ifm-breadcrumb-padding-horizontal:0;--ifm-list-paragraph-margin:0;--ifm-spacing-horizontal:2rem;--ifm-blockquote-border-color:#000;--ifm-menu-link-padding-vertical:0.6rem;--ifm-background-color:#fff;--ifm-footer-link-color:var(--ifm-font-color-base);--ifm-menu-link-sublist-icon:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtMSAxIDQgNCA0LTQiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLW9wYWNpdHk9Ii42NjciIHN0cm9rZS1saW5lY2FwPSJzcXVhcmUiLz48L3N2Zz4=);--docsearch-searchbox-background:#f7f7f7;--docsearch-modal-background:#f7f7f7!important;--ifm-navbar-height:5.563rem;--ifm-navbar-sidebar-width:100vw;--docsearch-highlight-color:#181818ab!important;--aa-primary-color-rgb:0,0,0;--ifm-menu-color-background-active:none;--ifm-menu-color-background-hover:none;--docusaurus-highlighted-code-line-bg:#0000001a;--docusaurus-announcement-bar-height:auto;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300);--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}html{font-feature-settings:"kern","liga","calt","zero" 0;-webkit-font-feature-settings:"kern","liga","calt","zero" 0;-webkit-text-size-adjust:100%;text-size-adjust:100%;font-smoothing:antialiased;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-kerning:normal;font-variant-ligatures:contextual common-ligatures;text-rendering:optimizeLegibility}@supports (font-variation-settings:normal){html{font-family:Inter var,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}}*,:after,:before{margin:0}.inline,.tags_jXut,svg{display:inline}::selection{background-color:var(--ifm-color-primary);color:#fff}.text-gray-1000,html #__docusaurus>div[role=banner],html[data-theme=dark] .footer__copyright,html[data-theme=dark] .footer__link-item,html[data-theme=dark] .footer__title,html[data-theme=light] .pagination-nav__sublabel{color:rgb(0 0 0/var(--tw-text-opacity));--tw-text-opacity:1}&[data-theme=dark] ::selection{color:#000}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }@font-face{font-display:swap;font-family:Inter;font-style:normal;font-weight:400;src:url(/interchain-security/assets/fonts/Inter-Regular-c8ba52b05a9ef10f47584d08ece2ec5c.woff2) format("woff2"),url(/interchain-security/assets/fonts/Inter-Regular-8c206db99195777c67691cbba9d64393.woff) format("woff")}@font-face{font-display:swap;font-family:Inter;font-style:normal;font-weight:500;src:url(/interchain-security/assets/fonts/Inter-Medium-293fd13dbca5a3e450ef1ebfb232a299.woff2) format("woff2"),url(/interchain-security/assets/fonts/Inter-Medium-9053572c46aeb4b16caafd643a543b8d.woff) format("woff")}@font-face{font-display:swap;font-family:Inter;font-style:normal;font-weight:700;src:url(/interchain-security/assets/fonts/Inter-Bold-ec64ea577b0349e055ad6646c1d8797a.woff2) format("woff2"),url(/interchain-security/assets/fonts/Inter-Bold-93c1301bd9f486c573b3d9001c6ec0e4.woff) format("woff")}@font-face{font-display:swap;font-family:Inter;font-style:normal;font-weight:900;src:url(/interchain-security/assets/fonts/Inter-Black-15ca31c0a2a68f76d2d12055bdf97bd0.woff2) format("woff2"),url(/interchain-security/assets/fonts/Inter-Black-c6938660eec019fefd684894b6d00900.woff) format("woff")}@font-face{font-display:swap;font-family:Inter var;font-style:oblique 0deg 10deg;font-weight:100 900;src:url(/interchain-security/assets/fonts/Inter.var-c2fe3cb2b7c746f7966a973d869d21c3.woff2) format("woff2")}@font-face{font-family:JetBrains Mono;font-style:normal;font-weight:400;src:url(/interchain-security/assets/fonts/JetBrainsMono-Regular-1e66c47aca088de94ae789a48719cb00.woff2) format("woff2")}.absolute{position:absolute}.relative{position:relative}.-left-\[calc\(theme\(space\.5\)\*1\+theme\(space\.7\)-theme\(space\.3\)\)\],html .theme-doc-sidebar-menu li li li .menu__link--active:not(.menu__link--sublist):before{left:-2.5rem}.-left-\[calc\(theme\(space\.5\)\*2\+theme\(space\.7\)-theme\(space\.3\)\)\],html .theme-doc-sidebar-menu li li li li .menu__link--active:not(.menu__link--sublist):before{left:-3.5rem}.-left-\[calc\(theme\(space\.5\)\*3\+theme\(space\.7\)-theme\(space\.3\)\)\],html .theme-doc-sidebar-menu li li li li li .menu__link--active:not(.menu__link--sublist):before{left:-4.5rem}.-left-\[calc\(theme\(space\.5\)\*4\+theme\(space\.7\)-theme\(space\.3\)\)\],html .theme-doc-sidebar-menu li li li li li li .menu__link--active:not(.menu__link--sublist):before{left:-5.5rem}.-left-\[calc\(theme\(space\.5\)\*5\+theme\(space\.7\)-theme\(space\.3\)\)\],html .theme-doc-sidebar-menu li li li li li li li .menu__link--active:not(.menu__link--sublist):before{left:-6.5rem}.-left-\[calc\(theme\(space\.7\)-theme\(space\.3\)\)\]{left:-1.5rem}.bottom-0{bottom:0}.left-0{left:0}.left-3{left:.5rem}.right-3{right:.5rem}.right-8{right:3rem}.top-0{top:0}.top-\[\.2rem\]{top:.2rem}.order-2{order:2}.order-first{order:-9999}.order-last{order:9999}.my-5,html .theme-doc-markdown li>ol,html .theme-doc-markdown li>ul{margin-bottom:1rem;margin-top:1rem}.mb-3{margin-bottom:.5rem}.mb-3\.5{margin-bottom:.625rem}.mb-4{margin-bottom:.75rem}.ml-0{margin-left:0}.ml-4{margin-left:.75rem}.mt-7{margin-top:2rem}.mt-9{margin-top:4rem}.block,.tocCollapsibleContent_vkbj a{display:block}.grid{display:grid}.hidden,html .DocSearch-Button .DocSearch-Button-Keys,html .breadcrumbs__item:first-child>a>svg{display:none}.h-8{height:3rem}.h-auto,.img_ev3q{height:auto}.h-px{height:1px}.w-8{width:3rem}.w-\[2px\]{width:2px}.w-auto{width:auto}.w-full,html .navbar-sidebar{width:100%}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.justify-start{justify-content:flex-start}.justify-center{justify-content:center}.gap-4{gap:.75rem}.rounded{border-radius:1rem}.rounded-s{border-radius:.5rem}.rounded-sm{border-radius:.625rem}.rounded-s{border-end-start-radius:1rem;border-start-start-radius:1rem}.border{border-width:1px}.border-0{border-width:0}.border-t,html .footer{border-top-width:1px}.border-b,html .navbar{border-bottom-width:1px}.border-r{border-right-width:1px}.border-stone-200{--tw-border-opacity:1;border-color:rgb(231 229 228/var(--tw-border-opacity))}.border-transparent{border-color:#0000}.border-b-docusaurusColorBorder,html .navbar{border-bottom-color:var(--ifm-color-emphasis-200)}.border-t-docusaurusColorBorder{border-top-color:var(--ifm-color-emphasis-200)}.bg-card{--tw-bg-opacity:1;background-color:rgb(247 247 247/var(--tw-bg-opacity))}.bg-fg,html[data-theme=dark] .navbar__toggle,html[data-theme=dark] .theme-doc-toc-mobile{background-color:#181818ab}.bg-gray-1000,html[data-theme=dark] .DocSearch-Footer,html[data-theme=dark] .DocSearch-Modal,html[data-theme=dark] .navbar-sidebar{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}.bg-gray-30{background-color:#00000008}.bg-linkHover{--tw-bg-opacity:1;background-color:rgb(85 85 85/var(--tw-bg-opacity))}.p-6{padding:1.5rem}.px-3{padding-left:.5rem;padding-right:.5rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-5{padding-bottom:1rem;padding-top:1rem}.py-5\.5{padding-bottom:1.25rem;padding-top:1.25rem}.pb-2,html .navbar{padding-bottom:.375rem}.pt-5,.pt-\[calc\(theme\(spacing\.7\)-1rem\)\],html .navbar{padding-top:1rem}.pb-5{padding-bottom:1rem}.pb-5\.5{padding-bottom:1.25rem}.pb-7{padding-bottom:2rem}.pb-8{padding-bottom:3rem}.pb-8\.5{padding-bottom:3.25rem}.pl-0,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.pl-6{padding-left:1.5rem}.pl-8{padding-left:3rem}.pt-6{padding-top:1.5rem}.text-center{text-align:center}.font-intervar{font-family:Inter var,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.font-jetbrain,html .theme-code-block{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-3,.text-\[1rem\],html .theme-doc-markdown blockquote,html .theme-doc-markdown ol,html .theme-doc-markdown p,html .theme-doc-markdown ul{font-size:1rem}.text-4{font-size:1.3125rem}.text-6{font-size:2rem}.text-7{font-size:2.375rem}.font-bold{font-weight:700}.font-semibold{font-weight:600}.leading-10{line-height:2.5rem}.leading-6{line-height:1.5rem}.leading-7{line-height:1.75rem}.leading-8{line-height:2rem}.leading-9{line-height:2.25rem}.text-inactive{color:#00000054}.text-inactiveLight{color:#ffffff70}.no-underline,html .theme-doc-markdown .card-section a{text-decoration-line:none}.antialiased{-webkit-font-smoothing:antialiased}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow-none,html .navbar,html .pagination-nav>a:hover,html[data-theme=dark] .navbar-sidebar__brand{--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000}.grayscale{--tw-grayscale:grayscale(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter}.transition-all{transition-property:all}.duration-200{transition-duration:.2s}html #__docusaurus>div[role=banner]{background-color:#00000008;font-weight:400}html #__docusaurus>div[role=banner] a{font-size:.8125rem;text-decoration-line:none;width:100%}html .navbar{height:auto}html .DocSearch-Button,html .navbar__toggle{background-color:rgb(247 247 247/var(--tw-bg-opacity));height:3rem;width:3rem;--tw-bg-opacity:1}html .navbar__toggle{align-items:center;border-end-start-radius:1rem;border-radius:.5rem;border-start-start-radius:1rem;display:flex;justify-content:center}html .navbar__brand+*{margin-left:auto}html .menu__link,html .navbar__link--active{--tw-text-opacity:1;color:rgb(85 85 85/var(--tw-text-opacity))}html .navbar__items:not(:last-child){justify-content:space-between}html .navbar__items:not(:last-child) button{margin-right:0;order:2}html .navbar__items--right>:last-child{right:3.25rem}html[data-theme=dark] .menu__link,html[data-theme=dark] .navbar__item{color:#ffffffab}html .github-icon:hover{opacity:.5}html .DocSearch-Button{border-radius:.625rem;color:#00000054;justify-content:center;margin-right:.5rem}html .DocSearch-Button .DocSearch-Button-Placeholder{padding-right:6rem}html .DocSearch-Logo path{fill:var(--ifm-font-color-base)}html .navbar-sidebar__brand{height:auto;padding-left:1.5rem;padding-right:1.5rem}html .navbar-sidebar__item{padding-left:1.5rem;padding-right:1.5rem;width:100%}html .navbar-sidebar__back{display:none;padding-left:0;padding-right:0}html .navbar-sidebar__close{--tw-bg-opacity:1;align-items:center;background-color:rgb(0 0 0/var(--tw-bg-opacity));border-end-start-radius:1rem;border-radius:.5rem;border-start-start-radius:1rem;display:flex;height:3rem;justify-content:center;margin-left:0;width:3rem}html .navbar-sidebar__close>svg>g{stroke:#fff}html[data-theme=dark] .navbar-sidebar__brand{position:relative}html[data-theme=dark] .navbar-sidebar__brand:after{--tw-bg-opacity:1;background-color:rgb(85 85 85/var(--tw-bg-opacity));bottom:0;content:"";display:block;height:1px;left:0;margin-left:1.5rem;margin-right:1.5rem;position:absolute;right:.5rem}html[data-theme=dark] .navbar-sidebar__close{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}html[data-theme=dark] .navbar-sidebar__close>svg>g{stroke:#000}html[data-theme=dark] .DocSearch-Button{background-color:#181818ab;color:#ffffff70}html[data-theme=dark] .DocSearch-Button-Key{border-color:#ffffff70;color:#ffffff70}html .breadcrumbs__item:first-child>a:after{content:"Docs"}html .breadcrumbs__item:not(:last-child):after{background-image:none;content:">"}html .theme-doc-toc-mobile{--tw-bg-opacity:1;background-color:rgb(247 247 247/var(--tw-bg-opacity));border-radius:1rem;padding:1.25rem 1.5rem 0}html .theme-doc-toc-mobile>button{display:flex;justify-content:space-between;padding:0 0 1.25rem}html .theme-doc-toc-mobile>button:after{background-image:var(--ifm-menu-link-sublist-icon);background-size:70%;margin-left:1rem;order:9999}html .theme-doc-toc-mobile ul li{margin:1rem 0}html[data-theme=dark] .theme-doc-sidebar-menu .menu__list:before{background-color:#ffffff70}html .theme-doc-sidebar-menu{font-weight:400}html .theme-doc-sidebar-menu .menu__list{padding-left:0;position:relative}html .theme-doc-sidebar-menu .menu__list:before{background-color:#00000012;content:"";display:block;height:100%;left:.5rem;position:absolute;top:0;width:2px}#__docusaurus-base-url-issue-banner-container,.themedComponent_mlkZ,[data-theme=dark] .lightToggleIcon_pyhR,[data-theme=light] .darkToggleIcon_wfgR,html .footer__col:first-child .footer__title,html .footer__link-item>svg,html .menu__caret,html .menu__link>svg,html .theme-doc-sidebar-menu .menu__list ul:before,html li li .menu__link--sublist-caret:after,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j{display:none}html .theme-doc-sidebar-menu .menu__link{padding-left:0;padding-right:1rem}html .theme-doc-sidebar-menu .menu__link--active:not(.menu__link--sublist){color:var(--ifm-font-color-base);font-weight:500}html .theme-doc-sidebar-menu li li{padding-left:2rem}html .theme-doc-sidebar-menu li li .menu__link--active:not(.menu__link--sublist){color:var(--ifm-font-color-base);font-weight:500;position:relative}html .theme-doc-sidebar-menu li li .menu__link--active:not(.menu__link--sublist):before{background-color:var(--ifm-font-color-base);content:"";display:block;height:100%;left:-1.5rem;position:absolute;top:0;width:2px}html .theme-doc-sidebar-menu li li li{padding-left:1rem}html .theme-doc-sidebar-item-link .menu__link[target=_blank]:after{content:"\2197";margin-left:.25rem}html .menu__link:hover{color:var(--ifm-font-color-base)}html .menu__link--sublist-caret{display:flex}html .menu__link--sublist-caret:after{background-repeat:no-repeat;background-size:16px;margin-left:0;margin-right:.75rem;order:-9999}html .menu__list-item--collapsed .menu__caret:before,html .menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(0)}html[data-theme=dark] .pagination-nav>a{--tw-border-opacity:1;background-color:#181818ab;border-color:rgb(41 37 36/var(--tw-border-opacity))}html .pagination-nav{margin-top:4rem;padding-bottom:2rem}html .pagination-nav>a{border-color:#0000;border-radius:1rem;box-shadow:0 0 80px #00000012;padding:1.5rem 1.5rem 3.25rem}html .pagination-nav .pagination-nav__link--next{text-align:left}html .pagination-nav .pagination-nav__sublabel{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity));font-size:1rem;margin-bottom:.625rem}:is([data-theme=dark] html .pagination-nav .pagination-nav__sublabel){color:var(--ifm-font-color-base)}html .pagination-nav .pagination-nav__label{font-size:1.3125rem;font-weight:600}html[data-theme=dark] .pagination-nav__sublabel,html[data-theme=light] .footer__copyright,html[data-theme=light] .footer__link-item,html[data-theme=light] .footer__title{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}html .footer{background-color:var(--ifm-font-color-base);border-top-color:var(--ifm-color-emphasis-200);padding-top:6rem}html .footer__bottom{margin:0 calc(var(--ifm-spacing-horizontal)*-1)}html .footer__copyright{font-size:.8125rem;margin-top:4rem;text-align:center}html .footer__col:not(:first-child){flex-basis:50%}html .theme-back-to-top-button{--tw-rotate:180deg}html .theme-back-to-top-button:after{width:50%}html .theme-code-block{margin-top:.5rem}html .markdown{--ifm-h1-vertical-rhythm-bottom:1}html .theme-doc-markdown{border-bottom-color:#00000012;border-bottom-width:1px;margin-top:2rem;padding-bottom:3rem}.before\:border-current:before,html .theme-doc-markdown ul li li:before{border-color:currentColor;content:var(--tw-content)}html .theme-doc-markdown h1{font-size:2.375rem;font-weight:700;letter-spacing:-.025em;line-height:2.5rem}html .theme-doc-markdown h2{font-size:2rem;font-weight:700;letter-spacing:-.025em;line-height:2.25rem}html .theme-doc-markdown h3{font-size:1.3125rem;font-weight:600;letter-spacing:-.025em;line-height:2rem}html .theme-doc-markdown h4{font-size:1rem;font-weight:600;letter-spacing:-.025em;line-height:1.75rem}html .theme-doc-markdown h5{font-size:1rem;font-weight:600;letter-spacing:.025em;line-height:1.5rem}html .theme-doc-markdown p{line-height:1.625}html .theme-doc-markdown code{border-width:0;padding-left:.5rem;padding-right:.5rem;vertical-align:initial}html .theme-doc-markdown blockquote{margin-bottom:2rem;margin-top:2rem}html .theme-doc-markdown a{color:var(--ifm-color-primary)}html .theme-doc-markdown ol,html .theme-doc-markdown ul{margin-bottom:1.5rem;margin-top:1.5rem}html .theme-doc-markdown ul li{margin-bottom:.75rem;padding-left:1.5rem;position:relative}html .theme-doc-markdown ul li:before{background-color:currentColor;content:var(--tw-content);display:block;height:4px;left:0;position:absolute;top:.5em;width:4px}html .theme-doc-markdown ul li li:before{background-color:initial;border-width:1px}.last\:mb-6:last-child,html .theme-doc-markdown ul li li:last-child{margin-bottom:1.5rem}html .theme-doc-markdown ol{counter-reset:a;list-style-type:none}html .theme-doc-markdown ol>li{margin-bottom:1.25rem;padding-left:3rem;position:relative}html .theme-doc-markdown ol>li:before{content:counters(a,".",decimal-leading-zero) ".";counter-increment:a;display:flex;font-size:1rem;font-weight:600;left:0;letter-spacing:-.025em;position:absolute;top:.2rem}html .theme-doc-markdown ol ol{counter-reset:b}html .theme-doc-markdown ol ol>li:before{content:counters(b,".",decimal-leading-zero) ".";counter-increment:b}html .main-wrapper{min-height:100vh}.before\:absolute:before{content:var(--tw-content);position:absolute}.before\:left-0:before{content:var(--tw-content);left:0}.before\:top-\[calc\(1em\/2\)\]:before{content:var(--tw-content);top:.5em}.before\:block:before{content:var(--tw-content);display:block}.before\:h-\[4px\]:before{content:var(--tw-content);height:4px}.before\:w-\[4px\]:before{content:var(--tw-content);width:4px}.before\:border:before{border-width:1px;content:var(--tw-content)}.before\:bg-current:before{background-color:currentColor;content:var(--tw-content)}.hover\:border-stone-300:hover{--tw-border-opacity:1;border-color:rgb(214 211 209/var(--tw-border-opacity))}.hover\:shadow-lg:hover{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}:is([data-theme=dark] .dark\:border-stone-800){--tw-border-opacity:1;border-color:rgb(41 37 36/var(--tw-border-opacity))}:is([data-theme=dark] .dark\:bg-neutral-900){--tw-bg-opacity:1;background-color:rgb(23 23 23/var(--tw-bg-opacity))}:is([data-theme=dark] .dark\:text-docusaurusColorBase){color:var(--ifm-font-color-base)}:is([data-theme=dark] .dark\:hover\:border-stone-200:hover){--tw-border-opacity:1;border-color:rgb(231 229 228/var(--tw-border-opacity))}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit;text-decoration:underline}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.toggleButton_gllP{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_aARS{cursor:not-allowed}.darkNavbarColorModeToggle_X3D1:hover{background:var(--ifm-color-gray-800)}[data-theme=dark] .themedComponent--dark_xIcU,[data-theme=light] .themedComponent--light_NVdE,html:not([data-theme]) .themedComponent--light_NVdE{display:initial}.iconExternalLink_nPIU{margin-left:.3rem}.dropdownNavbarItemMobile_S0Fm{cursor:pointer}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}@supports selector(:has(*)){.navbarSearchContainer_Bca1:not(:has(>*)){display:none}}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}.errorBoundaryError_a6uf{color:red;white-space:pre-wrap}.errorBoundaryFallback_VBag{color:red;padding:.55rem}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.footerLogoLink_BH7S:hover,.hash-link:focus,:hover>.hash-link{opacity:1}.anchorWithStickyNavbar_LWe7{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_WYt5{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.mainWrapper_z2l0{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color);text-decoration:none}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.lastUpdated_vwxv{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem);overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup__atx button{opacity:.4}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:c;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(c);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{fill:currentColor;height:inherit;left:0;opacity:inherit;position:absolute;top:0;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.admonition_xJq3{margin-bottom:1em}.admonitionHeading_Gvgb{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family)}.admonitionHeading_Gvgb:not(:last-child){margin-bottom:.3rem}.admonitionHeading_Gvgb code{text-transform:none}.admonitionIcon_Rf37{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_Rf37 svg{fill:var(--ifm-alert-foreground-color);display:inline-block;height:1.6em;width:1.6em}.breadcrumbHomeIcon_YNFT{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.collapseSidebarButton_PEFL{display:none;margin:0}.docSidebarContainer_YfHR,.sidebarLogo_isFc{display:none}.docMainContainer_TBSr,.docRoot_UBD9{display:flex;width:100%}.docsWrapper_hBAB{display:flex;flex:1 0 auto}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_TmdG{background-color:var(--docusaurus-collapse-button-bg)}.tocMobile_ITEo,html .navbar__toggle{display:none}html .navbar__items:not(:last-child){justify-content:flex-start;padding-left:.5rem;padding-right:.5rem}html .DocSearch-Button{justify-content:space-between;width:auto}html .theme-doc-breadcrumbs{padding-top:1rem}html .theme-doc-sidebar-container{border-right-color:var(--ifm-color-emphasis-200);border-right-width:1px;margin-left:.75rem}html .pagination-nav>a{grid-column:span 1/span 1}.lastUpdated_vwxv,html .pagination-nav .pagination-nav__link--next{text-align:right}html .footer__col:not(:first-child){flex-basis:0}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.navbarSearchContainer_Bca1{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.docItemCol_VOVn{max-width:75%!important}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_i1dp,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_TmdG:focus,.expandButton_TmdG:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{opacity:0;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_TmdG{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_i1dp{transform:rotate(180deg)}.docSidebarContainer_YfHR{border-right:1px solid var(--ifm-toc-border-color);-webkit-clip-path:inset(0);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_DPk8{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_aRkj{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_TBSr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_lQrH{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_JWYK{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}}@media (min-width:1024px){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.navbarSearchContainer_Bca1{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.docItemContainer_F8PC{padding:0 .3rem}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media screen and (prefers-reduced-motion){:root{transition:none}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file diff --git a/assets/fonts/Inter-Black-15ca31c0a2a68f76d2d12055bdf97bd0.woff2 b/assets/fonts/Inter-Black-15ca31c0a2a68f76d2d12055bdf97bd0.woff2 new file mode 100644 index 0000000000..68f64c9ed9 Binary files /dev/null and b/assets/fonts/Inter-Black-15ca31c0a2a68f76d2d12055bdf97bd0.woff2 differ diff --git a/assets/fonts/Inter-Black-c6938660eec019fefd684894b6d00900.woff b/assets/fonts/Inter-Black-c6938660eec019fefd684894b6d00900.woff new file mode 100644 index 0000000000..a18593a096 Binary files /dev/null and b/assets/fonts/Inter-Black-c6938660eec019fefd684894b6d00900.woff differ diff --git a/assets/fonts/Inter-Bold-93c1301bd9f486c573b3d9001c6ec0e4.woff b/assets/fonts/Inter-Bold-93c1301bd9f486c573b3d9001c6ec0e4.woff new file mode 100644 index 0000000000..eaf3d4bfd7 Binary files /dev/null and b/assets/fonts/Inter-Bold-93c1301bd9f486c573b3d9001c6ec0e4.woff differ diff --git a/assets/fonts/Inter-Bold-ec64ea577b0349e055ad6646c1d8797a.woff2 b/assets/fonts/Inter-Bold-ec64ea577b0349e055ad6646c1d8797a.woff2 new file mode 100644 index 0000000000..2846f29cc8 Binary files /dev/null and b/assets/fonts/Inter-Bold-ec64ea577b0349e055ad6646c1d8797a.woff2 differ diff --git a/assets/fonts/Inter-Medium-293fd13dbca5a3e450ef1ebfb232a299.woff2 b/assets/fonts/Inter-Medium-293fd13dbca5a3e450ef1ebfb232a299.woff2 new file mode 100644 index 0000000000..f92498a2ec Binary files /dev/null and b/assets/fonts/Inter-Medium-293fd13dbca5a3e450ef1ebfb232a299.woff2 differ diff --git a/assets/fonts/Inter-Medium-9053572c46aeb4b16caafd643a543b8d.woff b/assets/fonts/Inter-Medium-9053572c46aeb4b16caafd643a543b8d.woff new file mode 100644 index 0000000000..d546843f28 Binary files /dev/null and b/assets/fonts/Inter-Medium-9053572c46aeb4b16caafd643a543b8d.woff differ diff --git a/assets/fonts/Inter-Regular-8c206db99195777c67691cbba9d64393.woff b/assets/fonts/Inter-Regular-8c206db99195777c67691cbba9d64393.woff new file mode 100644 index 0000000000..62d3a61871 Binary files /dev/null and b/assets/fonts/Inter-Regular-8c206db99195777c67691cbba9d64393.woff differ diff --git a/assets/fonts/Inter-Regular-c8ba52b05a9ef10f47584d08ece2ec5c.woff2 b/assets/fonts/Inter-Regular-c8ba52b05a9ef10f47584d08ece2ec5c.woff2 new file mode 100644 index 0000000000..6c2b6893d5 Binary files /dev/null and b/assets/fonts/Inter-Regular-c8ba52b05a9ef10f47584d08ece2ec5c.woff2 differ diff --git a/assets/fonts/Inter.var-c2fe3cb2b7c746f7966a973d869d21c3.woff2 b/assets/fonts/Inter.var-c2fe3cb2b7c746f7966a973d869d21c3.woff2 new file mode 100644 index 0000000000..365eedc50c Binary files /dev/null and b/assets/fonts/Inter.var-c2fe3cb2b7c746f7966a973d869d21c3.woff2 differ diff --git a/assets/fonts/JetBrainsMono-Regular-1e66c47aca088de94ae789a48719cb00.woff2 b/assets/fonts/JetBrainsMono-Regular-1e66c47aca088de94ae789a48719cb00.woff2 new file mode 100644 index 0000000000..8c862e334d Binary files /dev/null and b/assets/fonts/JetBrainsMono-Regular-1e66c47aca088de94ae789a48719cb00.woff2 differ diff --git a/assets/images/cometmock_matrix_test-714f36252aff9df4214823e3145d0ef5.png b/assets/images/cometmock_matrix_test-714f36252aff9df4214823e3145d0ef5.png new file mode 100644 index 0000000000..740005aed1 Binary files /dev/null and b/assets/images/cometmock_matrix_test-714f36252aff9df4214823e3145d0ef5.png differ diff --git a/assets/images/hypha-consumer-start-process-2141109f76c584706dd994d7965fd692.svg b/assets/images/hypha-consumer-start-process-2141109f76c584706dd994d7965fd692.svg new file mode 100644 index 0000000000..1be7b61b7d --- /dev/null +++ b/assets/images/hypha-consumer-start-process-2141109f76c584706dd994d7965fd692.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/ics_changeover_timeline_stride-9bcad1834fef24a0fea7f2c80c9ccd71.png b/assets/images/ics_changeover_timeline_stride-9bcad1834fef24a0fea7f2c80c9ccd71.png new file mode 100644 index 0000000000..2cec12a6be Binary files /dev/null and b/assets/images/ics_changeover_timeline_stride-9bcad1834fef24a0fea7f2c80c9ccd71.png differ diff --git a/assets/images/inactivevals_after-ac23b4c6474ed6bb2105369cdf8482a0.png b/assets/images/inactivevals_after-ac23b4c6474ed6bb2105369cdf8482a0.png new file mode 100644 index 0000000000..fb9e862c02 Binary files /dev/null and b/assets/images/inactivevals_after-ac23b4c6474ed6bb2105369cdf8482a0.png differ diff --git a/assets/images/inactivevals_before-a963b865d2029f6629845f7b1beb215b.png b/assets/images/inactivevals_before-a963b865d2029f6629845f7b1beb215b.png new file mode 100644 index 0000000000..ffbcd584b8 Binary files /dev/null and b/assets/images/inactivevals_before-a963b865d2029f6629845f7b1beb215b.png differ diff --git a/assets/images/matrix_e2e_tests-30681305077301daaf3097e1952b54bb.png b/assets/images/matrix_e2e_tests-30681305077301daaf3097e1952b54bb.png new file mode 100644 index 0000000000..4c94db81a3 Binary files /dev/null and b/assets/images/matrix_e2e_tests-30681305077301daaf3097e1952b54bb.png differ diff --git a/assets/js/00147ff4.0b3ca866.js b/assets/js/00147ff4.0b3ca866.js new file mode 100644 index 0000000000..9fb14c102a --- /dev/null +++ b/assets/js/00147ff4.0b3ca866.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2110],{9075:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>h,contentTitle:()=>s,default:()=>l,frontMatter:()=>o,metadata:()=>r,toc:()=>c});var a=i(5893),t=i(1151);const o={sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},s=void 0,r={id:"frequently-asked-questions",title:"Frequently Asked Questions",description:"What is a consumer chain?",source:"@site/docs/frequently-asked-questions.md",sourceDirName:".",slug:"/faq",permalink:"/interchain-security/faq",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:5,frontMatter:{sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},sidebar:"tutorialSidebar",previous:{title:"Partial Set Security",permalink:"/interchain-security/validators/partial-set-security-for-validators"},next:{title:"Overview",permalink:"/interchain-security/adrs/intro"}},h={},c=[{value:"What is a consumer chain?",id:"what-is-a-consumer-chain",level:2},{value:"What happens to consumer if provider is down?",id:"what-happens-to-consumer-if-provider-is-down",level:2},{value:"What happens to provider if consumer is down?",id:"what-happens-to-provider-if-consumer-is-down",level:2},{value:"Can I run the provider and consumer chains on the same machine?",id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine",level:2},{value:"Can the consumer chain have its own token?",id:"can-the-consumer-chain-have-its-own-token",level:2},{value:"How are Tx fees paid on consumer?",id:"how-are-tx-fees-paid-on-consumer",level:2},{value:"Are there any restrictions the consumer chains need to abide by?",id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by",level:2},{value:"What's in it for the validators and stakers?",id:"whats-in-it-for-the-validators-and-stakers",level:2},{value:"Can the consumer chain have its own governance?",id:"can-the-consumer-chain-have-its-own-governance",level:2},{value:"Can validators opt out of validating a consumer chain?",id:"can-validators-opt-out-of-validating-a-consumer-chain",level:2},{value:"How does Slashing work?",id:"how-does-slashing-work",level:2},{value:"Can Consumer Chains perform Software Upgrades?",id:"can-consumer-chains-perform-software-upgrades",level:2},{value:"How can I connect to the testnets?",id:"how-can-i-connect-to-the-testnets",level:2},{value:"How do I start using ICS?",id:"how-do-i-start-using-ics",level:2},{value:"Which relayers are supported?",id:"which-relayers-are-supported",level:2},{value:"How does key delegation work in ICS?",id:"how-does-key-delegation-work-in-ics",level:2},{value:"How does Partial Set Security work?",id:"how-does-partial-set-security-work",level:2},{value:"How does a validator know which consumers chains it has to validate?",id:"how-does-a-validator-know-which-consumers-chains-it-has-to-validate",level:2},{value:"How many chains can a validator opt in to?",id:"how-many-chains-can-a-validator-opt-in-to",level:2},{value:"Can validators assign a consensus keys while a consumer-addition proposal is in voting period?",id:"can-validators-assign-a-consensus-keys-while-a-consumer-addition-proposal-is-in-voting-period",level:2},{value:"Can validators assign a consensus key during the voting period for a consumer-addition proposal if they are not in the top N?",id:"can-validators-assign-a-consensus-key-during-the-voting-period-for-a-consumer-addition-proposal-if-they-are-not-in-the-top-n",level:2},{value:"Can validators opt in to an Opt-in or Top N chain after its consumer-addition proposal voting period is over but before the spawn time?",id:"can-validators-opt-in-to-an-opt-in-or-top-n-chain-after-its-consumer-addition-proposal-voting-period-is-over-but-before-the-spawn-time",level:2},{value:"Can validators opt in to an Opt-in chain after the spawn time if nobody else opted in?",id:"can-validators-opt-in-to-an-opt-in-chain-after-the-spawn-time-if-nobody-else-opted-in",level:2},{value:"Can all validators opt out of an Opt-in chain?",id:"can-all-validators-opt-out-of-an-opt-in-chain",level:2},{value:"Can validators set a commission rate for chains they have not opted in to?",id:"can-validators-set-a-commission-rate-for-chains-they-have-not-opted-in-to",level:2},{value:"Can a consumer chain modify its power shaping parameters?",id:"can-a-consumer-chain-modify-its-power-shaping-parameters",level:2},{value:"Can a Top N consumer chain become Opt-In or vice versa?",id:"can-a-top-n-consumer-chain-become-opt-in-or-vice-versa",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h2:"h2",li:"li",p:"p",strong:"strong",ul:"ul",...(0,t.a)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.h2,{id:"what-is-a-consumer-chain",children:"What is a consumer chain?"}),"\n",(0,a.jsx)(n.p,{children:"Consumer chain is a blockchain operated by (a subset of) the validators of the provider chain. The ICS protocol ensures that the consumer chain gets information about which validators should run it (informs consumer chain about the current state of the validator set and the opted in validators for this consumer chain on the provider)."}),"\n",(0,a.jsx)(n.p,{children:"Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements."}),"\n",(0,a.jsx)(n.h2,{id:"what-happens-to-consumer-if-provider-is-down",children:"What happens to consumer if provider is down?"}),"\n",(0,a.jsx)(n.p,{children:"In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set."}),"\n",(0,a.jsx)(n.p,{children:"The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness."}),"\n",(0,a.jsxs)(n.p,{children:["However, if the ",(0,a.jsx)(n.code,{children:"trusting_period"})," (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain.\nThis means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about."]}),"\n",(0,a.jsx)(n.p,{children:'Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point.\nAt the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.'}),"\n",(0,a.jsx)(n.h2,{id:"what-happens-to-provider-if-consumer-is-down",children:"What happens to provider if consumer is down?"}),"\n",(0,a.jsx)(n.p,{children:"Consumer chains do not impact the provider chain.\nThe ICS protocol is concerned only with validator set management, and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events)."}),"\n",(0,a.jsx)(n.h2,{id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine",children:"Can I run the provider and consumer chains on the same machine?"}),"\n",(0,a.jsx)(n.p,{children:"Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation."}),"\n",(0,a.jsx)(n.h2,{id:"can-the-consumer-chain-have-its-own-token",children:"Can the consumer chain have its own token?"}),"\n",(0,a.jsx)(n.p,{children:"As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees."}),"\n",(0,a.jsx)(n.h2,{id:"how-are-tx-fees-paid-on-consumer",children:"How are Tx fees paid on consumer?"}),"\n",(0,a.jsx)(n.p,{children:"The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations."}),"\n",(0,a.jsx)(n.h2,{id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by",children:"Are there any restrictions the consumer chains need to abide by?"}),"\n",(0,a.jsx)(n.p,{children:"No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way.\nThe only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain."}),"\n",(0,a.jsx)(n.h2,{id:"whats-in-it-for-the-validators-and-stakers",children:"What's in it for the validators and stakers?"}),"\n",(0,a.jsxs)(n.p,{children:["The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by ",(0,a.jsx)(n.code,{children:"ConsumerRedistributionFraction"}),". The rewards are distributed (sent to the provider) every ",(0,a.jsx)(n.code,{children:"BlocksPerDistributionTransmission"}),"."]}),"\n",(0,a.jsx)(n.admonition,{type:"note",children:(0,a.jsxs)(n.p,{children:[(0,a.jsx)(n.code,{children:"ConsumerRedistributionFraction"})," and ",(0,a.jsx)(n.code,{children:"BlocksPerDistributionTransmission"})," are parameters defined in the ",(0,a.jsx)(n.code,{children:"ConsumerAdditionProposal"})," used to create the consumer chain. These parameters can be changed via consumer chain governance."]})}),"\n",(0,a.jsx)(n.h2,{id:"can-the-consumer-chain-have-its-own-governance",children:"Can the consumer chain have its own governance?"}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"Yes."})}),"\n",(0,a.jsx)(n.p,{children:'In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.'}),"\n",(0,a.jsx)(n.p,{children:"Validators can also be representatives but representatives are not required to run validator nodes."}),"\n",(0,a.jsx)(n.p,{children:"This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance."}),"\n",(0,a.jsx)(n.h2,{id:"can-validators-opt-out-of-validating-a-consumer-chain",children:"Can validators opt out of validating a consumer chain?"}),"\n",(0,a.jsx)(n.p,{children:"A validator can always opt out from an Opt-In consumer chain.\nA validator can only opt out from a Top N chain if the validator does not belong to the top N% validators."}),"\n",(0,a.jsx)(n.h2,{id:"how-does-slashing-work",children:"How does Slashing work?"}),"\n",(0,a.jsxs)(n.p,{children:["Validators that perform an equivocation or a light-client attack on a consumer chain are slashed on the provider chain.\nWe achieve this by submitting the proof of the equivocation or the light-client attack to the provider chain (see ",(0,a.jsx)(n.a,{href:"/interchain-security/features/slashing",children:"slashing"}),")."]}),"\n",(0,a.jsx)(n.h2,{id:"can-consumer-chains-perform-software-upgrades",children:"Can Consumer Chains perform Software Upgrades?"}),"\n",(0,a.jsx)(n.p,{children:"Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM)."}),"\n",(0,a.jsx)(n.p,{children:"Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module."}),"\n",(0,a.jsx)(n.h2,{id:"how-can-i-connect-to-the-testnets",children:"How can I connect to the testnets?"}),"\n",(0,a.jsxs)(n.p,{children:["Check out the ",(0,a.jsx)(n.a,{href:"/interchain-security/validators/joining-testnet",children:"Joining Interchain Security testnet"})," section."]}),"\n",(0,a.jsx)(n.h2,{id:"how-do-i-start-using-ics",children:"How do I start using ICS?"}),"\n",(0,a.jsxs)(n.p,{children:["To become a consumer chain use this ",(0,a.jsx)(n.a,{href:"/interchain-security/consumer-development/onboarding",children:"checklist"})," and check the ",(0,a.jsx)(n.a,{href:"/interchain-security/consumer-development/app-integration",children:"App integration section"})]}),"\n",(0,a.jsx)(n.h2,{id:"which-relayers-are-supported",children:"Which relayers are supported?"}),"\n",(0,a.jsx)(n.p,{children:"Currently supported versions:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"Hermes 1.8.0"}),"\n"]}),"\n",(0,a.jsx)(n.h2,{id:"how-does-key-delegation-work-in-ics",children:"How does key delegation work in ICS?"}),"\n",(0,a.jsxs)(n.p,{children:["You can check the ",(0,a.jsx)(n.a,{href:"/interchain-security/features/key-assignment",children:"Key Assignment Guide"})," for specific instructions."]}),"\n",(0,a.jsx)(n.h2,{id:"how-does-partial-set-security-work",children:"How does Partial Set Security work?"}),"\n",(0,a.jsx)(n.p,{children:"Partial Set Security allows a provider chain to share only a subset of its validator set with a consumer chain. This subset can be determined by the top N% validators by voting power, or by validators opting in to validate the consumer chain. Partial Set Security allows for flexible tradeoffs between security, decentralization, and the budget a consumer chain spends on rewards to validators."}),"\n",(0,a.jsxs)(n.p,{children:["See the ",(0,a.jsx)(n.a,{href:"/interchain-security/features/partial-set-security",children:"Partial Set Security"})," section for more information."]}),"\n",(0,a.jsx)(n.h2,{id:"how-does-a-validator-know-which-consumers-chains-it-has-to-validate",children:"How does a validator know which consumers chains it has to validate?"}),"\n",(0,a.jsxs)(n.p,{children:["In order for a validator to keep track of all the chains it has to validate, the validator can use the\n",(0,a.jsxs)(n.a,{href:"/interchain-security/validators/partial-set-security-for-validators#which-chains-does-a-validator-have-to-validate",children:[(0,a.jsx)(n.code,{children:"has-to-validate"})," query"]}),"."]}),"\n",(0,a.jsx)(n.h2,{id:"how-many-chains-can-a-validator-opt-in-to",children:"How many chains can a validator opt in to?"}),"\n",(0,a.jsxs)(n.p,{children:["There is ",(0,a.jsx)(n.strong,{children:"no"})," limit in the number of consumers chains a validator can choose to opt in to."]}),"\n",(0,a.jsx)(n.h2,{id:"can-validators-assign-a-consensus-keys-while-a-consumer-addition-proposal-is-in-voting-period",children:"Can validators assign a consensus keys while a consumer-addition proposal is in voting period?"}),"\n",(0,a.jsxs)(n.p,{children:["Yes, see the ",(0,a.jsx)(n.a,{href:"/interchain-security/features/key-assignment",children:"Key Assignment Guide"})," for more information."]}),"\n",(0,a.jsx)(n.h2,{id:"can-validators-assign-a-consensus-key-during-the-voting-period-for-a-consumer-addition-proposal-if-they-are-not-in-the-top-n",children:"Can validators assign a consensus key during the voting period for a consumer-addition proposal if they are not in the top N?"}),"\n",(0,a.jsx)(n.p,{children:"Yes."}),"\n",(0,a.jsx)(n.h2,{id:"can-validators-opt-in-to-an-opt-in-or-top-n-chain-after-its-consumer-addition-proposal-voting-period-is-over-but-before-the-spawn-time",children:"Can validators opt in to an Opt-in or Top N chain after its consumer-addition proposal voting period is over but before the spawn time?"}),"\n",(0,a.jsx)(n.p,{children:"Yes."}),"\n",(0,a.jsx)(n.h2,{id:"can-validators-opt-in-to-an-opt-in-chain-after-the-spawn-time-if-nobody-else-opted-in",children:"Can validators opt in to an Opt-in chain after the spawn time if nobody else opted in?"}),"\n",(0,a.jsx)(n.p,{children:"No, the consumer chain will not be added if nobody opted in by the spawn time. At least one validator, regardless of its voting power, must opt in before the spawn time arrives in order for the chain can start."}),"\n",(0,a.jsx)(n.h2,{id:"can-all-validators-opt-out-of-an-opt-in-chain",children:"Can all validators opt out of an Opt-in chain?"}),"\n",(0,a.jsx)(n.p,{children:"Yes, the consumer chain will halt with an ERR CONSENSUS FAILURE error after the opt-out message for the last validator is received."}),"\n",(0,a.jsx)(n.h2,{id:"can-validators-set-a-commission-rate-for-chains-they-have-not-opted-in-to",children:"Can validators set a commission rate for chains they have not opted in to?"}),"\n",(0,a.jsx)(n.p,{children:"Yes, and this is useful for validators that are not in the top N% of the provider chain, but might move into the top N% in the future.\nBy setting the commission rate ahead of time, they can make sure that they immediately have a commission rate of their choosing as soon as they are in the top N%."}),"\n",(0,a.jsx)(n.h2,{id:"can-a-consumer-chain-modify-its-power-shaping-parameters",children:"Can a consumer chain modify its power shaping parameters?"}),"\n",(0,a.jsxs)(n.p,{children:["Yes, by issuing a ",(0,a.jsx)(n.a,{href:"/interchain-security/features/proposals#consumermodificationproposal",children:(0,a.jsx)(n.code,{children:"ConsumerModificationProposal"})}),"."]}),"\n",(0,a.jsx)(n.h2,{id:"can-a-top-n-consumer-chain-become-opt-in-or-vice-versa",children:"Can a Top N consumer chain become Opt-In or vice versa?"}),"\n",(0,a.jsxs)(n.p,{children:["Yes, by issuing a ",(0,a.jsx)(n.a,{href:"/interchain-security/features/proposals#consumermodificationproposal",children:(0,a.jsx)(n.code,{children:"ConsumerModificationProposal"})}),"."]})]})}function l(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(d,{...e})}):d(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>r,a:()=>s});var a=i(7294);const t={},o=a.createContext(t);function s(e){const n=a.useContext(o);return a.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:s(e.components),a.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/06b45df8.830faa04.js b/assets/js/06b45df8.830faa04.js new file mode 100644 index 0000000000..9668ae465a --- /dev/null +++ b/assets/js/06b45df8.830faa04.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9599],{4562:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"v5.0.0","label":"v5.0.0","banner":"unreleased","badge":true,"noIndex":false,"className":"docs-version-v5.0.0","isLast":false,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Interchain Security Docs","href":"/interchain-security/v5.0.0/","docId":"index","unlisted":false},{"type":"category","label":"Introduction","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/v5.0.0/introduction/overview","docId":"introduction/overview","unlisted":false},{"type":"link","label":"Terminology","href":"/interchain-security/v5.0.0/introduction/terminology","docId":"introduction/terminology","unlisted":false},{"type":"link","label":"Interchain Security Parameters","href":"/interchain-security/v5.0.0/introduction/params","docId":"introduction/params","unlisted":false},{"type":"link","label":"Technical Specification","href":"/interchain-security/v5.0.0/introduction/technical-specification","docId":"introduction/technical-specification","unlisted":false}]},{"type":"category","label":"Upgrading","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Upgrading to ICS v5.0.0","href":"/interchain-security/v5.0.0/upgrading/migrate_v4_v5","docId":"upgrading/migrate_v4_v5","unlisted":false}]},{"type":"category","label":"Features","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Key Assignment","href":"/interchain-security/v5.0.0/features/key-assignment","docId":"features/key-assignment","unlisted":false},{"type":"link","label":"Reward Distribution","href":"/interchain-security/v5.0.0/features/reward-distribution","docId":"features/reward-distribution","unlisted":false},{"type":"link","label":"ICS Provider Proposals","href":"/interchain-security/v5.0.0/features/proposals","docId":"features/proposals","unlisted":false},{"type":"link","label":"Consumer Initiated Slashing","href":"/interchain-security/v5.0.0/features/slashing","docId":"features/slashing","unlisted":false}]},{"type":"category","label":"Consumer Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Developing an ICS consumer chain","href":"/interchain-security/v5.0.0/consumer-development/app-integration","docId":"consumer-development/app-integration","unlisted":false},{"type":"link","label":"Consumer Chain Governance","href":"/interchain-security/v5.0.0/consumer-development/consumer-chain-governance","docId":"consumer-development/consumer-chain-governance","unlisted":false},{"type":"link","label":"Onboarding Checklist","href":"/interchain-security/v5.0.0/consumer-development/onboarding","docId":"consumer-development/onboarding","unlisted":false},{"type":"link","label":"Offboarding Checklist","href":"/interchain-security/v5.0.0/consumer-development/offboarding","docId":"consumer-development/offboarding","unlisted":false},{"type":"link","label":"Changeover Procedure","href":"/interchain-security/v5.0.0/consumer-development/changeover-procedure","docId":"consumer-development/changeover-procedure","unlisted":false},{"type":"link","label":"Consumer Genesis Transformation","href":"/interchain-security/v5.0.0/consumer-development/consumer-genesis-transformation","docId":"consumer-development/consumer-genesis-transformation","unlisted":false}]},{"type":"category","label":"Validators Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/v5.0.0/validators/overview","docId":"validators/overview","unlisted":false},{"type":"link","label":"Joining Interchain Security testnet","href":"/interchain-security/v5.0.0/validators/joining-testnet","docId":"validators/joining-testnet","unlisted":false},{"type":"link","label":"Withdrawing consumer chain validator rewards","href":"/interchain-security/v5.0.0/validators/withdraw_rewards","docId":"validators/withdraw_rewards","unlisted":false},{"type":"link","label":"Validator Instructions for Changeover Procedure","href":"/interchain-security/v5.0.0/validators/changeover-procedure","docId":"validators/changeover-procedure","unlisted":false},{"type":"link","label":"Joining Neutron","href":"/interchain-security/v5.0.0/validators/joining-neutron","docId":"validators/joining-neutron","unlisted":false},{"type":"link","label":"Joining Stride","href":"/interchain-security/v5.0.0/validators/joining-stride","docId":"validators/joining-stride","unlisted":false}]},{"type":"link","label":"Frequently Asked Questions","href":"/interchain-security/v5.0.0/faq","docId":"frequently-asked-questions","unlisted":false},{"type":"category","label":"ADRs","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"ADRs","href":"/interchain-security/v5.0.0/adrs/intro","docId":"adrs/intro","unlisted":false},{"type":"link","label":"ADR Template","href":"/interchain-security/v5.0.0/adrs/adr-004-denom-dos-fixes","docId":"adrs/adr-004-denom-dos-fixes","unlisted":false},{"type":"link","label":"ADR Template","href":"/interchain-security/v5.0.0/adrs/adr-007-pause-unbonding-on-eqv-prop","docId":"adrs/adr-007-pause-unbonding-on-eqv-prop","unlisted":false},{"type":"link","label":"ADR Template","href":"/interchain-security/v5.0.0/adrs/adr-template","docId":"adrs/adr-template","unlisted":false},{"type":"link","label":"Key Assignment","href":"/interchain-security/v5.0.0/adrs/adr-001-key-assignment","docId":"adrs/adr-001-key-assignment","unlisted":false},{"type":"link","label":"Jail Throttling","href":"/interchain-security/v5.0.0/adrs/adr-002-throttle","docId":"adrs/adr-002-throttle","unlisted":false},{"type":"link","label":"Equivocation governance proposal","href":"/interchain-security/v5.0.0/adrs/adr-003-equivocation-gov-proposal","docId":"adrs/adr-003-equivocation-gov-proposal","unlisted":false},{"type":"link","label":"Cryptographic verification of equivocation evidence","href":"/interchain-security/v5.0.0/adrs/adr-005-cryptographic-equivocation-verification","docId":"adrs/adr-005-cryptographic-equivocation-verification","unlisted":false},{"type":"link","label":"Throttle with retries","href":"/interchain-security/v5.0.0/adrs/adr-008-throttle-retries","docId":"adrs/adr-008-throttle-retries","unlisted":false},{"type":"link","label":"Soft Opt-Out","href":"/interchain-security/v5.0.0/adrs/adr-009-soft-opt-out","docId":"adrs/adr-009-soft-opt-out","unlisted":false},{"type":"link","label":"Standalone to Consumer Changeover","href":"/interchain-security/v5.0.0/adrs/adr-010-standalone-changeover","docId":"adrs/adr-010-standalone-changeover","unlisted":false},{"type":"link","label":"Improving testing and increasing confidence","href":"/interchain-security/v5.0.0/adrs/adr-011-improving-test-confidence","docId":"adrs/adr-011-improving-test-confidence","unlisted":false},{"type":"link","label":"Separate Releasing","href":"/interchain-security/v5.0.0/adrs/adr-012-separate-releasing","docId":"adrs/adr-012-separate-releasing","unlisted":false},{"type":"link","label":"Slashing on the provider for consumer equivocation","href":"/interchain-security/v5.0.0/adrs/adr-013-equivocation-slashing","docId":"adrs/adr-013-equivocation-slashing","unlisted":false},{"type":"link","label":"Epochs","href":"/interchain-security/v5.0.0/adrs/adr-014-epochs","docId":"adrs/adr-014-epochs","unlisted":false},{"type":"link","label":"Partial Set Security","href":"/interchain-security/v5.0.0/adrs/adr-015-partial-set-security","docId":"adrs/adr-015-partial-set-security","unlisted":false}]}]},"docs":{"adrs/adr-001-key-assignment":{"id":"adrs/adr-001-key-assignment","title":"Key Assignment","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-002-throttle":{"id":"adrs/adr-002-throttle","title":"Jail Throttling","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-003-equivocation-gov-proposal":{"id":"adrs/adr-003-equivocation-gov-proposal","title":"Equivocation governance proposal","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-004-denom-dos-fixes":{"id":"adrs/adr-004-denom-dos-fixes","title":"ADR Template","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-005-cryptographic-equivocation-verification":{"id":"adrs/adr-005-cryptographic-equivocation-verification","title":"Cryptographic verification of equivocation evidence","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-007-pause-unbonding-on-eqv-prop":{"id":"adrs/adr-007-pause-unbonding-on-eqv-prop","title":"ADR Template","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-008-throttle-retries":{"id":"adrs/adr-008-throttle-retries","title":"Throttle with retries","description":"ADR 008: Throttle with retries","sidebar":"tutorialSidebar"},"adrs/adr-009-soft-opt-out":{"id":"adrs/adr-009-soft-opt-out","title":"Soft Opt-Out","description":"ADR 009: Soft Opt-Out","sidebar":"tutorialSidebar"},"adrs/adr-010-standalone-changeover":{"id":"adrs/adr-010-standalone-changeover","title":"Standalone to Consumer Changeover","description":"ADR 010: Standalone to Consumer Changeover","sidebar":"tutorialSidebar"},"adrs/adr-011-improving-test-confidence":{"id":"adrs/adr-011-improving-test-confidence","title":"Improving testing and increasing confidence","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-012-separate-releasing":{"id":"adrs/adr-012-separate-releasing","title":"Separate Releasing","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-013-equivocation-slashing":{"id":"adrs/adr-013-equivocation-slashing","title":"Slashing on the provider for consumer equivocation","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-014-epochs":{"id":"adrs/adr-014-epochs","title":"Epochs","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-015-partial-set-security":{"id":"adrs/adr-015-partial-set-security","title":"Partial Set Security","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-template":{"id":"adrs/adr-template","title":"ADR Template","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/intro":{"id":"adrs/intro","title":"ADRs","description":"This is a location to record all high-level architecture decisions in the Interchain Security project.","sidebar":"tutorialSidebar"},"consumer-development/app-integration":{"id":"consumer-development/app-integration","title":"Developing an ICS consumer chain","description":"When developing an ICS consumer chain, besides just focusing on your chain\'s logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.","sidebar":"tutorialSidebar"},"consumer-development/changeover-procedure":{"id":"consumer-development/changeover-procedure","title":"Changeover Procedure","description":"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.","sidebar":"tutorialSidebar"},"consumer-development/consumer-chain-governance":{"id":"consumer-development/consumer-chain-governance","title":"Consumer Chain Governance","description":"Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the \\"Whitelist\\" section below.","sidebar":"tutorialSidebar"},"consumer-development/consumer-genesis-transformation":{"id":"consumer-development/consumer-genesis-transformation","title":"Consumer Genesis Transformation","description":"Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentation on Onboarding and Changeover).","sidebar":"tutorialSidebar"},"consumer-development/offboarding":{"id":"consumer-development/offboarding","title":"Offboarding Checklist","description":"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).","sidebar":"tutorialSidebar"},"consumer-development/onboarding":{"id":"consumer-development/onboarding","title":"Onboarding Checklist","description":"The following checklists will aid in onboarding a new consumer chain to interchain security.","sidebar":"tutorialSidebar"},"features/key-assignment":{"id":"features/key-assignment","title":"Key Assignment","description":"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.","sidebar":"tutorialSidebar"},"features/proposals":{"id":"features/proposals","title":"ICS Provider Proposals","description":"Interchain security module introduces 3 new proposal types to the provider.","sidebar":"tutorialSidebar"},"features/reward-distribution":{"id":"features/reward-distribution","title":"Reward Distribution","description":"Sending and distributing rewards from consumer chains to the provider chain is handled by the Reward Distribution sub-protocol.","sidebar":"tutorialSidebar"},"features/slashing":{"id":"features/slashing","title":"Consumer Initiated Slashing","description":"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the Interchain Security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.","sidebar":"tutorialSidebar"},"frequently-asked-questions":{"id":"frequently-asked-questions","title":"Frequently Asked Questions","description":"What is the meaning of Validator Set Replication?","sidebar":"tutorialSidebar"},"index":{"id":"index","title":"Interchain Security Docs","description":"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.","sidebar":"tutorialSidebar"},"introduction/overview":{"id":"introduction/overview","title":"Overview","description":"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.","sidebar":"tutorialSidebar"},"introduction/params":{"id":"introduction/params","title":"Interchain Security Parameters","description":"The parameters necessary for Interchain Security (ICS) are defined in","sidebar":"tutorialSidebar"},"introduction/technical-specification":{"id":"introduction/technical-specification","title":"Technical Specification","description":"For a technical deep dive into the replicated security protocol, see the specification.","sidebar":"tutorialSidebar"},"introduction/terminology":{"id":"introduction/terminology","title":"Terminology","description":"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.","sidebar":"tutorialSidebar"},"upgrading/migrate_v4_v5":{"id":"upgrading/migrate_v4_v5","title":"Upgrading to ICS v5.0.0","description":"This ICS version uses cosmos-sdk v0.50.x and ibc-go v8.x.","sidebar":"tutorialSidebar"},"validators/changeover-procedure":{"id":"validators/changeover-procedure","title":"Validator Instructions for Changeover Procedure","description":"More details available in Changeover Procedure documentation.","sidebar":"tutorialSidebar"},"validators/joining-neutron":{"id":"validators/joining-neutron","title":"Joining Neutron","description":"Neutron is the first consumer chain to implement ICS.","sidebar":"tutorialSidebar"},"validators/joining-stride":{"id":"validators/joining-stride","title":"Joining Stride","description":"Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.","sidebar":"tutorialSidebar"},"validators/joining-testnet":{"id":"validators/joining-testnet","title":"Joining Interchain Security testnet","description":"Introduction","sidebar":"tutorialSidebar"},"validators/overview":{"id":"validators/overview","title":"Overview","description":"We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.","sidebar":"tutorialSidebar"},"validators/withdraw_rewards":{"id":"validators/withdraw_rewards","title":"Withdrawing consumer chain validator rewards","description":"Here are example steps for withdrawing rewards from consumer chains in the provider chain","sidebar":"tutorialSidebar"}}}')}}]); \ No newline at end of file diff --git a/assets/js/07d76e7d.195c3194.js b/assets/js/07d76e7d.195c3194.js new file mode 100644 index 0000000000..cd279541ad --- /dev/null +++ b/assets/js/07d76e7d.195c3194.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2189],{7488:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>a,metadata:()=>t,toc:()=>d});var i=s(5893),r=s(1151);const a={sidebar_position:1},o="Key Assignment",t={id:"features/key-assignment",title:"Key Assignment",description:"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.",source:"@site/docs/features/key-assignment.md",sourceDirName:"features",slug:"/features/key-assignment",permalink:"/interchain-security/features/key-assignment",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Upgrading to ICS v5.0.0",permalink:"/interchain-security/upgrading/migrate_v4_v5"},next:{title:"Reward Distribution",permalink:"/interchain-security/features/reward-distribution"}},c={},d=[{value:"Rules",id:"rules",level:2},{value:"Adding a key",id:"adding-a-key",level:2},{value:"Changing a key",id:"changing-a-key",level:2},{value:"Removing a key",id:"removing-a-key",level:2},{value:"Querying proposed consumer chains",id:"querying-proposed-consumer-chains",level:2}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"key-assignment",children:"Key Assignment"}),"\n",(0,i.jsx)(n.p,{children:"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.\nThere are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains."}),"\n",(0,i.jsxs)(n.p,{children:["The feature is outlined in this ",(0,i.jsx)(n.a,{href:"/interchain-security/adrs/adr-001-key-assignment",children:"ADR-001"})]}),"\n",(0,i.jsxs)(n.p,{children:["By sending an ",(0,i.jsx)(n.code,{children:"AssignConsumerKey"})," transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator."]}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsx)(n.p,{children:"Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity."})}),"\n",(0,i.jsx)(n.h2,{id:"rules",children:"Rules"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"a key can be assigned as soon as the consumer addition proposal is submitted to the provider"}),"\n",(0,i.jsx)(n.li,{children:"validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider"}),"\n",(0,i.jsx)(n.li,{children:"validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X"}),"\n",(0,i.jsx)(n.li,{children:"a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain"}),"\n"]}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsx)(n.p,{children:"Validators can use a different key for each consumer chain."})}),"\n",(0,i.jsx)(n.h2,{id:"adding-a-key",children:"Adding a key"}),"\n",(0,i.jsx)(n.p,{children:"First, create a new node on the consumer chain using the equivalent:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"consumerd init \n"})}),"\n",(0,i.jsx)(n.p,{children:"Then query your node for the consensus key."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":""}\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Then, make an ",(0,i.jsx)(n.code,{children:"assign-consensus-key"})," transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad tx provider assign-consensus-key '' --from --home --gas 900000 -b sync -y -o json\n"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"consumer-chain-id"})," is the string identifier of the consumer chain, as assigned on the provider chain"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"consumer-pub-key"})," has the following format ",(0,i.jsx)(n.code,{children:'{"@type":"/cosmos.crypto.ed25519.PubKey","key":""}'})]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Check that the key was assigned correctly by querying the provider:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad query provider validator-consumer-key cosmosvalcons1e....3xsj3ayzf4uv6\n"})}),"\n",(0,i.jsxs)(n.p,{children:["You must use a ",(0,i.jsx)(n.code,{children:"valcons"})," address. You can obtain it by querying your node on the provider ",(0,i.jsx)(n.code,{children:"gaiad tendermint show-address"})]}),"\n",(0,i.jsx)(n.p,{children:"OR"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad query provider validator-provider-key consumervalcons1e....123asdnoaisdao\n"})}),"\n",(0,i.jsxs)(n.p,{children:["You must use a ",(0,i.jsx)(n.code,{children:"valcons"})," address. You can obtain it by querying your node on the consumer ",(0,i.jsx)(n.code,{children:"consumerd tendermint show-address"})]}),"\n",(0,i.jsx)(n.p,{children:"OR"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad query provider all-pairs-valconsensus-address \n"})}),"\n",(0,i.jsxs)(n.p,{children:["You just need to use the ",(0,i.jsx)(n.code,{children:"chainId"})," of consumer to query all pairs valconsensus address with ",(0,i.jsx)(n.code,{children:"consumer-pub-key"})," for each of pair"]}),"\n",(0,i.jsx)(n.h2,{id:"changing-a-key",children:"Changing a key"}),"\n",(0,i.jsx)(n.p,{children:"To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied"}),"\n",(0,i.jsx)(n.h2,{id:"removing-a-key",children:"Removing a key"}),"\n",(0,i.jsxs)(n.p,{children:["To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the ",(0,i.jsx)(n.code,{children:"Adding a key"})," section and using your provider consensus key."]}),"\n",(0,i.jsx)(n.admonition,{type:"warning",children:(0,i.jsxs)(n.p,{children:["Validators are strongly recommended to assign a separate key for each consumer chain\nand ",(0,i.jsx)(n.strong,{children:"not"})," reuse the provider key across consumer chains for security reasons."]})}),"\n",(0,i.jsx)(n.h2,{id:"querying-proposed-consumer-chains",children:"Querying proposed consumer chains"}),"\n",(0,i.jsx)(n.p,{children:"To query the consumer addition proposals that are in the voting period, you can use the following command on the provider:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad query provider list-proposed-consumer-chains\n"})}),"\n",(0,i.jsx)(n.p,{children:"This query is valuable for staying informed about when keys can be assigned to newly proposed consumer chains."})]})}function l(e={}){const{wrapper:n}={...(0,r.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},1151:(e,n,s)=>{s.d(n,{Z:()=>t,a:()=>o});var i=s(7294);const r={},a=i.createContext(r);function o(e){const n=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function t(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),i.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/0cb1d302.fabe1b41.js b/assets/js/0cb1d302.fabe1b41.js new file mode 100644 index 0000000000..47f1f97aa6 --- /dev/null +++ b/assets/js/0cb1d302.fabe1b41.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1085],{5398:(n,e,t)=>{t.r(e),t.d(e,{assets:()=>a,contentTitle:()=>s,default:()=>d,frontMatter:()=>o,metadata:()=>c,toc:()=>u});var i=t(5893),r=t(1151);const o={sidebar_position:5},s="Joining Neutron",c={id:"validators/joining-neutron",title:"Joining Neutron",description:"Neutron is the first consumer chain to implement ICS.",source:"@site/docs/validators/joining-neutron.md",sourceDirName:"validators",slug:"/validators/joining-neutron",permalink:"/interchain-security/validators/joining-neutron",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Validator Instructions for Changeover Procedure",permalink:"/interchain-security/validators/changeover-procedure"},next:{title:"Joining Stride",permalink:"/interchain-security/validators/joining-stride"}},a={},u=[{value:"Resources",id:"resources",level:2}];function l(n){const e={a:"a",h1:"h1",h2:"h2",li:"li",p:"p",ul:"ul",...(0,r.a)(),...n.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"joining-neutron",children:"Joining Neutron"}),"\n",(0,i.jsx)(e.p,{children:"Neutron is the first consumer chain to implement ICS."}),"\n",(0,i.jsxs)(e.p,{children:["You can find instructions on joining the mainnet ",(0,i.jsx)(e.a,{href:"https://docs.neutron.org/neutron/consumer-chain-launch",children:"here"}),"."]}),"\n",(0,i.jsxs)(e.p,{children:["To join Neutron chain on the interchain security testnet check ",(0,i.jsx)(e.a,{href:"https://github.com/cosmos/testnets/tree/master/interchain-security/pion-1",children:"here"})]}),"\n",(0,i.jsx)(e.h2,{id:"resources",children:"Resources"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:"https://docs.neutron.org",children:"Neutron docs"})}),"\n"]})]})}function d(n={}){const{wrapper:e}={...(0,r.a)(),...n.components};return e?(0,i.jsx)(e,{...n,children:(0,i.jsx)(l,{...n})}):l(n)}},1151:(n,e,t)=>{t.d(e,{Z:()=>c,a:()=>s});var i=t(7294);const r={},o=i.createContext(r);function s(n){const e=i.useContext(o);return i.useMemo((function(){return"function"==typeof n?n(e):{...e,...n}}),[e,n])}function c(n){let e;return e=n.disableParentContext?"function"==typeof n.components?n.components(r):n.components||r:s(n.components),i.createElement(o.Provider,{value:e},n.children)}}}]); \ No newline at end of file diff --git a/assets/js/1097399d.6cf69a51.js b/assets/js/1097399d.6cf69a51.js new file mode 100644 index 0000000000..00449f906e --- /dev/null +++ b/assets/js/1097399d.6cf69a51.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6548],{5191:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>o,default:()=>h,frontMatter:()=>r,metadata:()=>d,toc:()=>c});var i=t(5893),s=t(1151);const r={sidebar_position:12,title:"Improving testing and increasing confidence"},o="ADR 011: Improving testing and increasing confidence",d={id:"adrs/adr-011-improving-test-confidence",title:"Improving testing and increasing confidence",description:"Changelog",source:"@site/versioned_docs/version-v5.0.0/adrs/adr-011-improving-test-confidence.md",sourceDirName:"adrs",slug:"/adrs/adr-011-improving-test-confidence",permalink:"/interchain-security/v5.0.0/adrs/adr-011-improving-test-confidence",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:12,frontMatter:{sidebar_position:12,title:"Improving testing and increasing confidence"},sidebar:"tutorialSidebar",previous:{title:"Standalone to Consumer Changeover",permalink:"/interchain-security/v5.0.0/adrs/adr-010-standalone-changeover"},next:{title:"Separate Releasing",permalink:"/interchain-security/v5.0.0/adrs/adr-012-separate-releasing"}},a={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Current state of testing",id:"current-state-of-testing",level:4},{value:"Unit testing",id:"unit-testing",level:3},{value:"Integration testing",id:"integration-testing",level:3},{value:"End-to-end testing",id:"end-to-end-testing",level:3},{value:"Decision",id:"decision",level:2},{value:"1. Connect specifications to code and tooling",id:"1-connect-specifications-to-code-and-tooling",level:3},{value:"Decision context and hypothesis",id:"decision-context-and-hypothesis",level:4},{value:"Main benefit",id:"main-benefit",level:4},{value:"2. Improve e2e tooling",id:"2-improve-e2e-tooling",level:3},{value:"Matrix tests",id:"matrix-tests",level:4},{value:"Introducing e2e regression testing",id:"introducing-e2e-regression-testing",level:4},{value:"Introducing e2e CometMock tests",id:"introducing-e2e-cometmock-tests",level:4},{value:"3. Introduce innovative testing approaches",id:"3-introduce-innovative-testing-approaches",level:3},{value:"Model",id:"model",level:4},{value:"Driver",id:"driver",level:4},{value:"Harness",id:"harness",level:4},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function l(e){const n={a:"a",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",img:"img",li:"li",ol:"ol",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"adr-011-improving-testing-and-increasing-confidence",children:"ADR 011: Improving testing and increasing confidence"}),"\n",(0,i.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"2023-08-11: Proposed, first draft of ADR."}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(n.p,{children:"Proposed"}),"\n",(0,i.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,i.jsx)(n.p,{children:"Testing, QA, and maintenance of interchain-security libraries is an ever-evolving area of software engineering we have to keep incrementally improving. The purpose of the QA process is to catch bugs as early as possible. In an ideal development workflow a bug should never reach production. A bug found in the specification stage is a lot cheaper to resolve than a bug discovered in production (or even in testnet). Ideally, all bugs should be found during the CI execution, and we hope that no bugs will ever even reach the testnet (although nothing can replace actual system stress test under load interacting with users)."}),"\n",(0,i.jsx)(n.p,{children:"During development and testnet operation the following types of bugs were the most commonly found:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"improper iterator usage"}),"\n",(0,i.jsx)(n.li,{children:"unbounded array access/iteration"}),"\n",(0,i.jsx)(n.li,{children:"improper input handling and validation"}),"\n",(0,i.jsx)(n.li,{children:"improper cached context usage"}),"\n",(0,i.jsx)(n.li,{children:"non-determinism check (improper use of maps in go, relying on random values)"}),"\n",(0,i.jsx)(n.li,{children:"KV store management and/or how keys are defined"}),"\n",(0,i.jsx)(n.li,{children:"deserialization issues arising from consumer/provider versioning mismatch"}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Such bugs can be discovered earlier with better tooling. Some of these bugs can induce increases in block times, chain halts, state corruption, or introduce an attack surface which is difficult to remove if other systems have started depending on that behavior."}),"\n",(0,i.jsx)(n.h4,{id:"current-state-of-testing",children:"Current state of testing"}),"\n",(0,i.jsx)(n.p,{children:"Our testing suites consist of multiple parts, each with their own trade-offs and benefits with regards to code coverage, complexity and confidence they provide."}),"\n",(0,i.jsx)(n.h3,{id:"unit-testing",children:"Unit testing"}),"\n",(0,i.jsxs)(n.p,{children:["Unit testing is employed mostly for testing single-module functionality. It is the first step in testing and often the most practical. While highly important, unit tests often ",(0,i.jsx)(n.strong,{children:"test a single piece of code"})," and don't test relationships between different moving parts, this makes them less valuable when dealing with multi-module interactions."]}),"\n",(0,i.jsx)(n.p,{children:"Unit tests often employ mocks to abstract parts of the system that are not under test. Mocks are not equivalent to actual models and should not be treated as such."}),"\n",(0,i.jsx)(n.p,{children:"Out of all the approaches used, unit testing has the most tools available and the coverage can simply be displayed as % of code lines tested. Although this is a very nice and very easy to understand metric, it does not speak about the quality of the test coverage."}),"\n",(0,i.jsx)(n.p,{children:"Since distributed systems testing is a lot more involved, unit tests are oftentimes not sufficient to cover complex interactions. Unit tests are still necessary and helpful, but in cases where unit tests are not helpful e2e or integration tests should be favored."}),"\n",(0,i.jsx)(n.h3,{id:"integration-testing",children:"Integration testing"}),"\n",(0,i.jsxs)(n.p,{children:["With integration testing we ",(0,i.jsx)(n.strong,{children:"test the multi-module interactions"})," while isolating them from the remainder of the system.\nIntegration tests can uncover bugs that are often missed by unit tests."]}),"\n",(0,i.jsxs)(n.p,{children:["It is very difficult to gauge the actual test coverage imparted by integration tests and the available tooling is limited.\nIn interchain-security we employ the ",(0,i.jsx)(n.code,{children:"ibc-go/testing"})," framework to test interactions in-memory."]}),"\n",(0,i.jsx)(n.p,{children:"At present, integration testing does not involve the consensus layer - it is only concerned with application level state and logic."}),"\n",(0,i.jsx)(n.h3,{id:"end-to-end-testing",children:"End-to-end testing"}),"\n",(0,i.jsx)(n.p,{children:"In our context end-to-end testing comprises of tests that use the actual application binaries in an isolated environment (e.g. docker container). During test execution the inputs are meant to simulate actual user interaction, either by submitting transactions/queries using the command line or using gRPC/REST APIs and checking for state changes after an action has been performed. With this testing strategy we also include the consensus layer in all of our runs. This is the closest we can get to testing user interactions without starting a full testnet."}),"\n",(0,i.jsx)(n.p,{children:"End-to-end testing strategies vary between different teams and projects and we strive to unify our approach to the best of our ability (at least for ICS and gaia)."}),"\n",(0,i.jsx)(n.p,{children:"The available tooling does not give us significant (or relevant) line of code coverage information since most of the tools are geared towards analyzing unit tests and simple code branch evaluation."}),"\n",(0,i.jsx)(n.p,{children:"We aim to adapt our best practices by learning from other similar systems and projects such as cosmos-sdk, ibc-go and CometBFT."}),"\n",(0,i.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,i.jsx)(n.h3,{id:"1-connect-specifications-to-code-and-tooling",children:"1. Connect specifications to code and tooling"}),"\n",(0,i.jsx)(n.p,{children:"Oftentimes, specifications are disconnected from the development and QA processes. This gives rise to problems where the specification does not reflect the actual state of the system and vice-versa.\nUsually specifications are just text files that are rarely used and go unmaintained after a while, resulting in consistency issues and misleading instructions/expectations about system behavior."}),"\n",(0,i.jsx)(n.h4,{id:"decision-context-and-hypothesis",children:"Decision context and hypothesis"}),"\n",(0,i.jsx)(n.p,{children:"Specifications written in a dedicated and executable specification language are easier to maintain than the ones written entirely in text.\nAdditionally, we can create models based on the specification OR make the model equivalent to a specification."}),"\n",(0,i.jsxs)(n.p,{children:["Models do not care about the intricacies of implementation and neither do specifications. Since both models and specifications care about concisely and accurately describing a system (such as a finite state machine), we see a benefit of adding model based tools (such as ",(0,i.jsx)(n.a,{href:"https://github.com/informalsystems/quint",children:"quint"}),") to our testing and development workflows."]}),"\n",(0,i.jsx)(n.h4,{id:"main-benefit",children:"Main benefit"}),"\n",(0,i.jsx)(n.p,{children:"MBT tooling can be used to generate test traces that can be executed by multiple different testing setups."}),"\n",(0,i.jsx)(n.h3,{id:"2-improve-e2e-tooling",children:"2. Improve e2e tooling"}),"\n",(0,i.jsx)(n.h4,{id:"matrix-tests",children:"Matrix tests"}),"\n",(0,i.jsxs)(n.p,{children:["Instead of only running tests against current ",(0,i.jsx)(n.code,{children:"main"})," branch we should adopt an approach where we also:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"run regression tests against different released software versions"})," (",(0,i.jsx)(n.code,{children:"ICS v1 vs v2 vs v3"}),")"]}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.strong,{children:"run non-determinism tests to uncover issues quickly"})}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["Matrix tests can be implemented using ",(0,i.jsx)(n.a,{href:"https://github.com/informalsystems/CometMock",children:"CometMock"})," and refactoring our current e2e CI setup."]}),"\n",(0,i.jsx)(n.h4,{id:"introducing-e2e-regression-testing",children:"Introducing e2e regression testing"}),"\n",(0,i.jsx)(n.p,{children:"This e2e test suite would execute using a cronjob in our CI (nightly, multiple times a day etc.)"}),"\n",(0,i.jsxs)(n.p,{children:["Briefly, the same set of traces is run against different ",(0,i.jsx)(n.strong,{children:"maintained"})," versions of the software and the ",(0,i.jsx)(n.code,{children:"main"})," branch.\nThis would allow us to discover potential issues during development instead of in a testnet scenarios."]}),"\n",(0,i.jsxs)(n.p,{children:["The most valuable issues that can be discovered in this way are ",(0,i.jsx)(n.strong,{children:"state breaking changes"}),", ",(0,i.jsx)(n.strong,{children:"regressions"})," and ",(0,i.jsx)(n.strong,{children:"version incompatibilities"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["The setup is illustrated by the image below.\n",(0,i.jsx)(n.img,{alt:"e2e matrix tests",src:t(4023).Z+"",width:"2170",height:"1624"})]}),"\n",(0,i.jsx)(n.p,{children:"This table explains which versions are tested against each other for the same set of test traces:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"\u2705 marks a passing test"}),"\n",(0,i.jsx)(n.li,{children:"\u274c marks a failing test"}),"\n"]}),"\n",(0,i.jsxs)(n.table,{children:[(0,i.jsx)(n.thead,{children:(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"USES: ICS v1 PROVIDER"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"start chain"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"add key"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"delegate"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"undelegate"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"redelegate"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"downtime"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"equivocation"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"stop chain"})})]})}),(0,i.jsxs)(n.tbody,{children:[(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"v1 consumer (sdk45,ibc4.3)"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"v2 consumer (sdk45, ibc4.4)"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"v3 consumer (sdk47, ibc7)"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"main consumer"})}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"neutron"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u274c"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"stride"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u274c"})]})]})]}),"\n",(0,i.jsx)(n.h4,{id:"introducing-e2e-cometmock-tests",children:"Introducing e2e CometMock tests"}),"\n",(0,i.jsxs)(n.p,{children:["CometMock is a mock implementation of the ",(0,i.jsx)(n.a,{href:"https://github.com/cometbft/cometbft",children:"CometBFT"})," consensus engine. It supports most operations performed by CometBFT while also being lightweight and relatively easy to use."]}),"\n",(0,i.jsxs)(n.p,{children:['CometMock tests allow more nuanced control of test scenarios because CometMock can "fool" the blockchain app into thinking that a certain number of blocks had passed.\n',(0,i.jsx)(n.strong,{children:"This allows us to test very nuanced scenarios, difficult edge cases and long-running operations (such as unbonding operations)."})]}),"\n",(0,i.jsx)(n.p,{children:"Examples of tests made easier with CometMock are listed below:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"regression tests"}),"\n",(0,i.jsx)(n.li,{children:"non-determinism tests"}),"\n",(0,i.jsx)(n.li,{children:"upgrade tests"}),"\n",(0,i.jsx)(n.li,{children:"state-breaking changes"}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["With CometMock, the ",(0,i.jsx)(n.strong,{children:"matrix test"})," approach can also be used. The image below illustrates a CometMock setup that can be used to discover non-deterministic behavior and state-breaking changes.\n",(0,i.jsx)(n.img,{alt:"e2e matrix tests",src:t(3146).Z+"",width:"3714",height:"2082"})]}),"\n",(0,i.jsx)(n.p,{children:"This table explains which versions are tested against each other for the same set of test traces:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"\u2705 marks a passing test"}),"\n",(0,i.jsx)(n.li,{children:"\u274c marks a failing test"}),"\n"]}),"\n",(0,i.jsxs)(n.table,{children:[(0,i.jsx)(n.thead,{children:(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"SCENARIO"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"start chain"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"add key"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"delegate"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"undelegate"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"redelegate"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"downtime"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"equivocation"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"stop chain"})})]})}),(0,i.jsxs)(n.tbody,{children:[(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"v3 provi + v3 consu"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"main provi + main consu"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"commit provi + commit consu"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"})]})]})]}),"\n",(0,i.jsxs)(n.p,{children:["Briefly; multiple versions of the application are run against the same CometMock instance and any deviations in app behavior would result in ",(0,i.jsx)(n.code,{children:"app hash"})," errors (the apps would be in different states after performing the same set of actions)."]}),"\n",(0,i.jsx)(n.h3,{id:"3-introduce-innovative-testing-approaches",children:"3. Introduce innovative testing approaches"}),"\n",(0,i.jsx)(n.p,{children:"When discussing e2e testing, some very important patterns emerge - especially if test traces are used instead of ad-hoc tests written by hand."}),"\n",(0,i.jsx)(n.p,{children:"We see a unique opportunity to clearly identify concerns and modularize the testing architecture."}),"\n",(0,i.jsxs)(n.p,{children:["The e2e testing frameworks can be split into a ",(0,i.jsx)(n.strong,{children:"pipeline consisting of 3 parts: model, driver and harness"}),"."]}),"\n",(0,i.jsx)(n.h4,{id:"model",children:"Model"}),"\n",(0,i.jsx)(n.p,{children:"Model is the part of the system that can emulate the behavior of the system under test.\nIdeally, it is very close to the specification and is written in a specification language such as quint, TLA+ or similar.\nOne of the purposes of the model is that it can be used to generate test traces."}),"\n",(0,i.jsx)(n.h4,{id:"driver",children:"Driver"}),"\n",(0,i.jsx)(n.p,{children:"The purpose of the driver is to accept test traces (generated by the model or written by hand), process them and provide inputs to the next part of the pipeline."}),"\n",(0,i.jsx)(n.p,{children:"Basically, the driver sits between the model and the actual infrastructure on which the test traces are being executed on."}),"\n",(0,i.jsx)(n.h4,{id:"harness",children:"Harness"}),"\n",(0,i.jsx)(n.p,{children:"Harness is the infrastructure layer of the pipeline that accepts inputs from the driver."}),"\n",(0,i.jsx)(n.p,{children:"There can be multiple harnesses as long as they can perform four things:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"bootstrap a test execution environment (local, docker, k8s\u2026)"}),"\n",(0,i.jsx)(n.li,{children:"accept inputs from drivers"}),"\n",(0,i.jsx)(n.li,{children:"perform the action specified by the driver"}),"\n",(0,i.jsx)(n.li,{children:"report results after performing actions"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,i.jsx)(n.p,{children:"The procedure outlined in this ADR is not an all-or-nothing approach. Concepts introduced here do not rely on each other, so this ADR may only be applied partially without negative impact on test coverage and code confidence."}),"\n",(0,i.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsx)(n.li,{children:"introduction of maintainable MBT solutions"}),"\n"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:'improvement over the current "difftest" setup that relies on an opinionated typescript model and go driver'}),"\n"]}),"\n",(0,i.jsxs)(n.ol,{start:"2",children:["\n",(0,i.jsx)(n.li,{children:"increased code coverage and confidence"}),"\n"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"using CometMock allows us to run more tests in less time"}),"\n",(0,i.jsx)(n.li,{children:"adding matrix e2e tests allows us to quickly pinpoint differences between code versions"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsx)(n.p,{children:"It might be easier to forgo the MBT tooling and instead focus on pure property based testing"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/667",children:"PBT proof of concept"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/flyingmutant/rapid",children:"property based testing in go"})}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:'The solutions are potentially expensive if we increase usage of the CI pipeline - this is fixed by running "expensive" tests using a cronjob, instead of running them on every commit.'}),"\n",(0,i.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,i.jsx)(n.p,{children:"The process of changing development and testing process is not something that can be thought of and delivered quickly. Luckily, the changes can be rolled out incrementally without impacting existing workflows."}),"\n",(0,i.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsx)(n.p,{children:"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!"}),"\n"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/gaia/issues/2427",children:"https://github.com/cosmos/gaia/issues/2427"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/gaia/issues/2420",children:"https://github.com/cosmos/gaia/issues/2420"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/ibc-go/tree/main/e2e",children:"ibc-go e2e tests"})}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},3146:(e,n,t)=>{t.d(n,{Z:()=>i});const i=t.p+"assets/images/cometmock_matrix_test-714f36252aff9df4214823e3145d0ef5.png"},4023:(e,n,t)=>{t.d(n,{Z:()=>i});const i=t.p+"assets/images/matrix_e2e_tests-30681305077301daaf3097e1952b54bb.png"},1151:(e,n,t)=>{t.d(n,{Z:()=>d,a:()=>o});var i=t(7294);const s={},r=i.createContext(s);function o(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/16d4e57d.c5b611b1.js b/assets/js/16d4e57d.c5b611b1.js new file mode 100644 index 0000000000..77ee6995a4 --- /dev/null +++ b/assets/js/16d4e57d.c5b611b1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5387],{1258:(e,i,t)=>{t.r(i),t.d(i,{assets:()=>c,contentTitle:()=>a,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>l});var n=t(5893),r=t(1151);const o={sidebar_position:2},a="Terminology",s={id:"introduction/terminology",title:"Terminology",description:"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.",source:"@site/versioned_docs/version-v5.0.0/introduction/terminology.md",sourceDirName:"introduction",slug:"/introduction/terminology",permalink:"/interchain-security/v5.0.0/introduction/terminology",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/v5.0.0/introduction/overview"},next:{title:"Interchain Security Parameters",permalink:"/interchain-security/v5.0.0/introduction/params"}},c={},l=[{value:"Shared Security",id:"shared-security",level:2},{value:"Interchain Security",id:"interchain-security",level:2},{value:"Replicated Security",id:"replicated-security",level:2},{value:"Mesh security",id:"mesh-security",level:2},{value:"Consumer Chain",id:"consumer-chain",level:2},{value:"Standalone Chain",id:"standalone-chain",level:2},{value:"Changeover Procedure",id:"changeover-procedure",level:2}];function h(e){const i={a:"a",h1:"h1",h2:"h2",p:"p",strong:"strong",...(0,r.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(i.h1,{id:"terminology",children:"Terminology"}),"\n",(0,n.jsx)(i.p,{children:"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions."}),"\n",(0,n.jsx)(i.h2,{id:"shared-security",children:"Shared Security"}),"\n",(0,n.jsx)(i.p,{children:"Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share its proof-of-stake security with another blockchain or off-chain process."}),"\n",(0,n.jsx)(i.h2,{id:"interchain-security",children:"Interchain Security"}),"\n",(0,n.jsx)(i.p,{children:"Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC."}),"\n",(0,n.jsx)(i.h2,{id:"replicated-security",children:"Replicated Security"}),"\n",(0,n.jsx)(i.p,{children:'A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC. Note this documentation is focused on explaining the concepts from replicated security.'}),"\n",(0,n.jsx)(i.h2,{id:"mesh-security",children:"Mesh security"}),"\n",(0,n.jsxs)(i.p,{children:["A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see ",(0,n.jsx)(i.a,{href:"https://informal.systems/blog/replicated-vs-mesh-security",children:"Replicated vs. Mesh Security on the Informal Blog"}),"."]}),"\n",(0,n.jsx)(i.h2,{id:"consumer-chain",children:"Consumer Chain"}),"\n",(0,n.jsx)(i.p,{children:"Chain that is secured by the validator set of the provider, instead of its own.\nReplicated security allows the provider chain validator set to validate blocks on the consumer chain."}),"\n",(0,n.jsx)(i.h2,{id:"standalone-chain",children:"Standalone Chain"}),"\n",(0,n.jsx)(i.p,{children:"Chain that is secured by its own validator set. This chain does not participate in replicated security."}),"\n",(0,n.jsx)(i.p,{children:'Standalone chains may sometimes be called "sovereign" - the terms are synonymous.'}),"\n",(0,n.jsx)(i.h2,{id:"changeover-procedure",children:"Changeover Procedure"}),"\n",(0,n.jsxs)(i.p,{children:["Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the ",(0,n.jsx)(i.strong,{children:"changeover procedure"})," and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain."]})]})}function d(e={}){const{wrapper:i}={...(0,r.a)(),...e.components};return i?(0,n.jsx)(i,{...e,children:(0,n.jsx)(h,{...e})}):h(e)}},1151:(e,i,t)=>{t.d(i,{Z:()=>s,a:()=>a});var n=t(7294);const r={},o=n.createContext(r);function a(e){const i=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function s(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),n.createElement(o.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/1772.531d94c5.js b/assets/js/1772.531d94c5.js new file mode 100644 index 0000000000..9ce56dc605 --- /dev/null +++ b/assets/js/1772.531d94c5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1772],{5658:(e,t,i)=>{i.d(t,{Z:()=>a});i(7294);var n=i(512),s=i(5999),o=i(2503),r=i(5893);function a(e){let{className:t}=e;return(0,r.jsx)("main",{className:(0,n.Z)("container margin-vert--xl",t),children:(0,r.jsx)("div",{className:"row",children:(0,r.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,r.jsx)(o.Z,{as:"h1",className:"hero__title",children:(0,r.jsx)(s.Z,{id:"theme.NotFound.title",description:"The title of the 404 page",children:"Page Not Found"})}),(0,r.jsx)("p",{children:(0,r.jsx)(s.Z,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page",children:"We could not find what you were looking for."})}),(0,r.jsx)("p",{children:(0,r.jsx)(s.Z,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page",children:"Please contact the owner of the site that linked you to the original URL and let them know their link is broken."})})]})})})}},1772:(e,t,i)=>{i.r(t),i.d(t,{default:()=>l});i(7294);var n=i(5999),s=i(1944),o=i(6040),r=i(5658),a=i(5893);function l(){const e=(0,n.I)({id:"theme.NotFound.title",message:"Page Not Found"});return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(s.d,{title:e}),(0,a.jsx)(o.Z,{children:(0,a.jsx)(r.Z,{})})]})}}}]); \ No newline at end of file diff --git a/assets/js/17896441.407f320a.js b/assets/js/17896441.407f320a.js new file mode 100644 index 0000000000..2ff97b6850 --- /dev/null +++ b/assets/js/17896441.407f320a.js @@ -0,0 +1 @@ +(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7918],{7951:function(e,t,n){"use strict";var s=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});const a=s(n(7294)),o=s(n(5971)),i=s(n(9286));e.exports=(i.default,e=>e.reference?a.default.createElement(o.default,{...e}):a.default.createElement(i.default,{...e}))},5971:function(e,t,n){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,t,n,s){void 0===s&&(s=n),Object.defineProperty(e,s,{enumerable:!0,get:function(){return t[n]}})}:function(e,t,n,s){void 0===s&&(s=n),e[s]=t[n]}),a=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&s(t,e,n);return a(t,e),t},i=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.codeReducer=t.parseReference=void 0;const l=o(n(7294)),r=i(n(9286)),c={code:"loading...",error:null,loading:null},d={fontSize:".9em",fontWeight:600,color:"#0E75DD",textAlign:"center",paddingBottom:"13px",textDecoration:"underline"};function u(e){const t=e.slice(e.indexOf("https"),-1),[n,s]=t.split("#"),a=globalThis||{};a.URL||(a.URL=URL);const[o,i,l,r,...c]=new a.URL(n).pathname.split("/").slice(1),[d,u]=s?s.split("-").map((e=>parseInt(e.slice(1),10)-1)):[0,1/0];return{url:`https://raw.githubusercontent.com/${o}/${i}/${r}/${c.join("/")}`,fromLine:d,toLine:u,title:c.join("/")}}function m(e,{type:t,value:n}){switch(t){case"reset":return c;case"loading":return{...e,loading:!0};case"loaded":return{...e,code:n,loading:!1};case"error":return{...e,error:n,loading:!1};default:return e}}t.parseReference=u,t.codeReducer=m,t.default=function(e){var t,n,s;const[a,o]=l.useReducer(m,c),i=u(e.children);!1!==a.loading&&async function({url:e,fromLine:t,toLine:n},s){let a;try{a=await fetch(e)}catch(l){return s({type:"error",value:l})}if(200!==a.status)return s({type:"error",value:await a.text()});const o=(await a.text()).split("\n").slice(t,(n||t)+1),i=o.reduce(((e,t)=>{if(0===t.length)return e;const n=t.match(/^\s+/);return n?Math.min(e,n[0].length):0}),1/0);s({type:"loaded",value:o.map((e=>e.slice(i))).join("\n")})}(i,o);const h=null===(t=e.metastring)||void 0===t?void 0:t.match(/title="(?.*)"/),p={...e,metastring:(null===(n=null==h?void 0:h.groups)||void 0===n?void 0:n.title)?` title="${null===(s=null==h?void 0:h.groups)||void 0===s?void 0:s.title}"`:` title="${i.title}"`,children:c.code};return l.default.createElement("div",null,l.default.createElement(r.default,{...p},a.code),l.default.createElement("div",{style:d},l.default.createElement("a",{href:e.children,target:"_blank"},"See full example on GitHub")))}},9286:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>U});var s=n(7294),a=n(2389),o=n(512),i=n(2949),l=n(6668);function r(){const{prism:e}=(0,l.L)(),{colorMode:t}=(0,i.I)(),n=e.theme,s=e.darkTheme||n;return"dark"===t?s:n}var c=n(5281),d=n(7594),u=n.n(d);const m=/title=(?<quote>["'])(?<title>.*?)\1/,h=/\{(?<range>[\d,-]+)\}/,p={js:{start:"\\/\\/",end:""},jsBlock:{start:"\\/\\*",end:"\\*\\/"},jsx:{start:"\\{\\s*\\/\\*",end:"\\*\\/\\s*\\}"},bash:{start:"#",end:""},html:{start:"\x3c!--",end:"--\x3e"},lua:{start:"--",end:""},wasm:{start:"\\;\\;",end:""},tex:{start:"%",end:""}};function f(e,t){const n=e.map((e=>{const{start:n,end:s}=p[e];return`(?:${n}\\s*(${t.flatMap((e=>[e.line,e.block?.start,e.block?.end].filter(Boolean))).join("|")})\\s*${s})`})).join("|");return new RegExp(`^\\s*(?:${n})\\s*$`)}function x(e,t){let n=e.replace(/\n$/,"");const{language:s,magicComments:a,metastring:o}=t;if(o&&h.test(o)){const e=o.match(h).groups.range;if(0===a.length)throw new Error(`A highlight range has been given in code block's metastring (\`\`\` ${o}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges.`);const t=a[0].className,s=u()(e).filter((e=>e>0)).map((e=>[e-1,[t]]));return{lineClassNames:Object.fromEntries(s),code:n}}if(void 0===s)return{lineClassNames:{},code:n};const i=function(e,t){switch(e){case"js":case"javascript":case"ts":case"typescript":return f(["js","jsBlock"],t);case"jsx":case"tsx":return f(["js","jsBlock","jsx"],t);case"html":return f(["js","jsBlock","html"],t);case"python":case"py":case"bash":return f(["bash"],t);case"markdown":case"md":return f(["html","jsx","bash"],t);case"tex":case"latex":case"matlab":return f(["tex"],t);case"lua":case"haskell":case"sql":return f(["lua"],t);case"wasm":return f(["wasm"],t);default:return f(Object.keys(p).filter((e=>!["lua","wasm","tex","latex","matlab"].includes(e))),t)}}(s,a),l=n.split("\n"),r=Object.fromEntries(a.map((e=>[e.className,{start:0,range:""}]))),c=Object.fromEntries(a.filter((e=>e.line)).map((e=>{let{className:t,line:n}=e;return[n,t]}))),d=Object.fromEntries(a.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.start,t]}))),m=Object.fromEntries(a.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.end,t]})));for(let u=0;u<l.length;){const e=l[u].match(i);if(!e){u+=1;continue}const t=e.slice(1).find((e=>void 0!==e));c[t]?r[c[t]].range+=`${u},`:d[t]?r[d[t]].start=u:m[t]&&(r[m[t]].range+=`${r[m[t]].start}-${u-1},`),l.splice(u,1)}n=l.join("\n");const x={};return Object.entries(r).forEach((e=>{let[t,{range:n}]=e;u()(n).forEach((e=>{x[e]??=[],x[e].push(t)}))})),{lineClassNames:x,code:n}}const g={codeBlockContainer:"codeBlockContainer_Ckt0"};var b=n(5893);function v(e){let{as:t,...n}=e;const s=function(e){const t={color:"--prism-color",backgroundColor:"--prism-background-color"},n={};return Object.entries(e.plain).forEach((e=>{let[s,a]=e;const o=t[s];o&&"string"==typeof a&&(n[o]=a)})),n}(r());return(0,b.jsx)(t,{...n,style:s,className:(0,o.Z)(n.className,g.codeBlockContainer,c.k.common.codeBlock)})}const j={codeBlockContent:"codeBlockContent_biex",codeBlockTitle:"codeBlockTitle_Ktv7",codeBlock:"codeBlock_bY9V",codeBlockStandalone:"codeBlockStandalone_MEMb",codeBlockLines:"codeBlockLines_e6Vv",codeBlockLinesWithNumbering:"codeBlockLinesWithNumbering_o6Pm",buttonGroup:"buttonGroup__atx"};function N(e){let{children:t,className:n}=e;return(0,b.jsx)(v,{as:"pre",tabIndex:0,className:(0,o.Z)(j.codeBlockStandalone,"thin-scrollbar",n),children:(0,b.jsx)("code",{className:j.codeBlockLines,children:t})})}var C=n(902);const k={attributes:!0,characterData:!0,childList:!0,subtree:!0};function L(e,t){const[n,a]=(0,s.useState)(),o=(0,s.useCallback)((()=>{a(e.current?.closest("[role=tabpanel][hidden]"))}),[e,a]);(0,s.useEffect)((()=>{o()}),[o]),function(e,t,n){void 0===n&&(n=k);const a=(0,C.zX)(t),o=(0,C.Ql)(n);(0,s.useEffect)((()=>{const t=new MutationObserver(a);return e&&t.observe(e,o),()=>t.disconnect()}),[e,a,o])}(n,(e=>{e.forEach((e=>{"attributes"===e.type&&"hidden"===e.attributeName&&(t(),o())}))}),{attributes:!0,characterData:!1,childList:!1,subtree:!1})}var y=n(2573);const _={codeLine:"codeLine_lJS_",codeLineNumber:"codeLineNumber_Tfdd",codeLineContent:"codeLineContent_feaV"};function w(e){let{line:t,classNames:n,showLineNumbers:s,getLineProps:a,getTokenProps:i}=e;1===t.length&&"\n"===t[0].content&&(t[0].content="");const l=a({line:t,className:(0,o.Z)(n,s&&_.codeLine)}),r=t.map(((e,t)=>(0,b.jsx)("span",{...i({token:e,key:t})},t)));return(0,b.jsxs)("span",{...l,children:[s?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)("span",{className:_.codeLineNumber}),(0,b.jsx)("span",{className:_.codeLineContent,children:r})]}):r,(0,b.jsx)("br",{})]})}var B=n(5999);function Z(e){return(0,b.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,b.jsx)("path",{fill:"currentColor",d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"})})}function T(e){return(0,b.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,b.jsx)("path",{fill:"currentColor",d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"})})}const E={copyButtonCopied:"copyButtonCopied_obH4",copyButtonIcons:"copyButtonIcons_eSgA",copyButtonIcon:"copyButtonIcon_y97N",copyButtonSuccessIcon:"copyButtonSuccessIcon_LjdS"};function H(e){let{code:t,className:n}=e;const[a,i]=(0,s.useState)(!1),l=(0,s.useRef)(void 0),r=(0,s.useCallback)((()=>{!function(e,t){let{target:n=document.body}=void 0===t?{}:t;if("string"!=typeof e)throw new TypeError(`Expected parameter \`text\` to be a \`string\`, got \`${typeof e}\`.`);const s=document.createElement("textarea"),a=document.activeElement;s.value=e,s.setAttribute("readonly",""),s.style.contain="strict",s.style.position="absolute",s.style.left="-9999px",s.style.fontSize="12pt";const o=document.getSelection(),i=o.rangeCount>0&&o.getRangeAt(0);n.append(s),s.select(),s.selectionStart=0,s.selectionEnd=e.length;let l=!1;try{l=document.execCommand("copy")}catch{}s.remove(),i&&(o.removeAllRanges(),o.addRange(i)),a&&a.focus()}(t),i(!0),l.current=window.setTimeout((()=>{i(!1)}),1e3)}),[t]);return(0,s.useEffect)((()=>()=>window.clearTimeout(l.current)),[]),(0,b.jsx)("button",{type:"button","aria-label":a?(0,B.I)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,B.I)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"}),title:(0,B.I)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,o.Z)("clean-btn",n,E.copyButton,a&&E.copyButtonCopied),onClick:r,children:(0,b.jsxs)("span",{className:E.copyButtonIcons,"aria-hidden":"true",children:[(0,b.jsx)(Z,{className:E.copyButtonIcon}),(0,b.jsx)(T,{className:E.copyButtonSuccessIcon})]})})}function M(e){return(0,b.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,b.jsx)("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"})})}const A={wordWrapButtonIcon:"wordWrapButtonIcon_Bwma",wordWrapButtonEnabled:"wordWrapButtonEnabled_EoeP"};function I(e){let{className:t,onClick:n,isEnabled:s}=e;const a=(0,B.I)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return(0,b.jsx)("button",{type:"button",onClick:n,className:(0,o.Z)("clean-btn",t,s&&A.wordWrapButtonEnabled),"aria-label":a,title:a,children:(0,b.jsx)(M,{className:A.wordWrapButtonIcon,"aria-hidden":"true"})})}function S(e){let{children:t,className:n="",metastring:a,title:i,showLineNumbers:c,language:d}=e;const{prism:{defaultLanguage:u,magicComments:h}}=(0,l.L)(),p=function(e){return e?.toLowerCase()}(d??function(e){const t=e.split(" ").find((e=>e.startsWith("language-")));return t?.replace(/language-/,"")}(n)??u),f=r(),g=function(){const[e,t]=(0,s.useState)(!1),[n,a]=(0,s.useState)(!1),o=(0,s.useRef)(null),i=(0,s.useCallback)((()=>{const n=o.current.querySelector("code");e?n.removeAttribute("style"):(n.style.whiteSpace="pre-wrap",n.style.overflowWrap="anywhere"),t((e=>!e))}),[o,e]),l=(0,s.useCallback)((()=>{const{scrollWidth:e,clientWidth:t}=o.current,n=e>t||o.current.querySelector("code").hasAttribute("style");a(n)}),[o]);return L(o,l),(0,s.useEffect)((()=>{l()}),[e,l]),(0,s.useEffect)((()=>(window.addEventListener("resize",l,{passive:!0}),()=>{window.removeEventListener("resize",l)})),[l]),{codeBlockRef:o,isEnabled:e,isCodeScrollable:n,toggle:i}}(),N=function(e){return e?.match(m)?.groups.title??""}(a)||i,{lineClassNames:C,code:k}=x(t,{metastring:a,language:p,magicComments:h}),_=c??function(e){return Boolean(e?.includes("showLineNumbers"))}(a);return(0,b.jsxs)(v,{as:"div",className:(0,o.Z)(n,p&&!n.includes(`language-${p}`)&&`language-${p}`),children:[N&&(0,b.jsx)("div",{className:j.codeBlockTitle,children:N}),(0,b.jsxs)("div",{className:j.codeBlockContent,children:[(0,b.jsx)(y.y$,{theme:f,code:k,language:p??"text",children:e=>{let{className:t,style:n,tokens:s,getLineProps:a,getTokenProps:i}=e;return(0,b.jsx)("pre",{tabIndex:0,ref:g.codeBlockRef,className:(0,o.Z)(t,j.codeBlock,"thin-scrollbar"),style:n,children:(0,b.jsx)("code",{className:(0,o.Z)(j.codeBlockLines,_&&j.codeBlockLinesWithNumbering),children:s.map(((e,t)=>(0,b.jsx)(w,{line:e,getLineProps:a,getTokenProps:i,classNames:C[t],showLineNumbers:_},t)))})})}}),(0,b.jsxs)("div",{className:j.buttonGroup,children:[(g.isEnabled||g.isCodeScrollable)&&(0,b.jsx)(I,{className:j.codeButton,onClick:()=>g.toggle(),isEnabled:g.isEnabled}),(0,b.jsx)(H,{className:j.codeButton,code:k})]})]})]})}function U(e){let{children:t,...n}=e;const o=(0,a.Z)(),i=function(e){return s.Children.toArray(e).some((e=>(0,s.isValidElement)(e)))?e:Array.isArray(e)?e.join(""):e}(t),l="string"==typeof i?S:N;return(0,b.jsx)(l,{...n,children:i},String(o))}},7078:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>bt});var s=n(7294),a=n(1944),o=n(902),i=n(5893);const l=s.createContext(null);function r(e){let{children:t,content:n}=e;const a=function(e){return(0,s.useMemo)((()=>({metadata:e.metadata,frontMatter:e.frontMatter,assets:e.assets,contentTitle:e.contentTitle,toc:e.toc})),[e])}(n);return(0,i.jsx)(l.Provider,{value:a,children:t})}function c(){const e=(0,s.useContext)(l);if(null===e)throw new o.i6("DocProvider");return e}function d(){const{metadata:e,frontMatter:t,assets:n}=c();return(0,i.jsx)(a.d,{title:e.title,description:e.description,keywords:t.keywords,image:n.image??t.image})}var u=n(512),m=n(7524),h=n(5999),p=n(9960);function f(e){const{permalink:t,title:n,subLabel:s,isNext:a}=e;return(0,i.jsxs)(p.Z,{className:(0,u.Z)("pagination-nav__link",a?"pagination-nav__link--next":"pagination-nav__link--prev"),to:t,children:[s&&(0,i.jsx)("div",{className:"pagination-nav__sublabel",children:s}),(0,i.jsx)("div",{className:"pagination-nav__label",children:n})]})}function x(e){const{previous:t,next:n}=e;return(0,i.jsxs)("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,h.I)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages",description:"The ARIA label for the docs pagination"}),children:[t&&(0,i.jsx)(f,{...t,subLabel:(0,i.jsx)(h.Z,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc",children:"Previous"})}),n&&(0,i.jsx)(f,{...n,subLabel:(0,i.jsx)(h.Z,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc",children:"Next"}),isNext:!0})]})}function g(){const{metadata:e}=c();return(0,i.jsx)(x,{previous:e.previous,next:e.next})}var b=n(2263),v=n(143),j=n(5281),N=n(373),C=n(4477);const k={unreleased:function(e){let{siteTitle:t,versionMetadata:n}=e;return(0,i.jsx)(h.Z,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:t,versionLabel:(0,i.jsx)("b",{children:n.label})},children:"This is unreleased documentation for {siteTitle} {versionLabel} version."})},unmaintained:function(e){let{siteTitle:t,versionMetadata:n}=e;return(0,i.jsx)(h.Z,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:t,versionLabel:(0,i.jsx)("b",{children:n.label})},children:"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained."})}};function L(e){const t=k[e.versionMetadata.banner];return(0,i.jsx)(t,{...e})}function y(e){let{versionLabel:t,to:n,onClick:s}=e;return(0,i.jsx)(h.Z,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:t,latestVersionLink:(0,i.jsx)("b",{children:(0,i.jsx)(p.Z,{to:n,onClick:s,children:(0,i.jsx)(h.Z,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label",children:"latest version"})})})},children:"For up-to-date documentation, see the {latestVersionLink} ({versionLabel})."})}function _(e){let{className:t,versionMetadata:n}=e;const{siteConfig:{title:s}}=(0,b.Z)(),{pluginId:a}=(0,v.gA)({failfast:!0}),{savePreferredVersionName:o}=(0,N.J)(a),{latestDocSuggestion:l,latestVersionSuggestion:r}=(0,v.Jo)(a),c=l??(d=r).docs.find((e=>e.id===d.mainDocId));var d;return(0,i.jsxs)("div",{className:(0,u.Z)(t,j.k.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert",children:[(0,i.jsx)("div",{children:(0,i.jsx)(L,{siteTitle:s,versionMetadata:n})}),(0,i.jsx)("div",{className:"margin-top--md",children:(0,i.jsx)(y,{versionLabel:r.label,to:c.path,onClick:()=>o(r.name)})})]})}function w(e){let{className:t}=e;const n=(0,C.E)();return n.banner?(0,i.jsx)(_,{className:t,versionMetadata:n}):null}function B(e){let{className:t}=e;const n=(0,C.E)();return n.badge?(0,i.jsx)("span",{className:(0,u.Z)(t,j.k.docs.docVersionBadge,"badge badge--secondary"),children:(0,i.jsx)(h.Z,{id:"theme.docs.versionBadge.label",values:{versionLabel:n.label},children:"Version: {versionLabel}"})}):null}function Z(e){let{lastUpdatedAt:t,formattedLastUpdatedAt:n}=e;return(0,i.jsx)(h.Z,{id:"theme.lastUpdated.atDate",description:"The words used to describe on which date a page has been last updated",values:{date:(0,i.jsx)("b",{children:(0,i.jsx)("time",{dateTime:new Date(1e3*t).toISOString(),children:n})})},children:" on {date}"})}function T(e){let{lastUpdatedBy:t}=e;return(0,i.jsx)(h.Z,{id:"theme.lastUpdated.byUser",description:"The words used to describe by who the page has been last updated",values:{user:(0,i.jsx)("b",{children:t})},children:" by {user}"})}function E(e){let{lastUpdatedAt:t,formattedLastUpdatedAt:n,lastUpdatedBy:s}=e;return(0,i.jsxs)("span",{className:j.k.common.lastUpdated,children:[(0,i.jsx)(h.Z,{id:"theme.lastUpdated.lastUpdatedAtBy",description:"The sentence used to display when a page has been last updated, and by who",values:{atDate:t&&n?(0,i.jsx)(Z,{lastUpdatedAt:t,formattedLastUpdatedAt:n}):"",byUser:s?(0,i.jsx)(T,{lastUpdatedBy:s}):""},children:"Last updated{atDate}{byUser}"}),!1]})}const H={iconEdit:"iconEdit_Z9Sw"};function M(e){let{className:t,...n}=e;return(0,i.jsx)("svg",{fill:"currentColor",height:"20",width:"20",viewBox:"0 0 40 40",className:(0,u.Z)(H.iconEdit,t),"aria-hidden":"true",...n,children:(0,i.jsx)("g",{children:(0,i.jsx)("path",{d:"m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"})})})}function A(e){let{editUrl:t}=e;return(0,i.jsxs)(p.Z,{to:t,className:j.k.common.editThisPage,children:[(0,i.jsx)(M,{}),(0,i.jsx)(h.Z,{id:"theme.common.editThisPage",description:"The link label to edit the current page",children:"Edit this page"})]})}const I={tag:"tag_zVej",tagRegular:"tagRegular_sFm0",tagWithCount:"tagWithCount_h2kH"};function S(e){let{permalink:t,label:n,count:s}=e;return(0,i.jsxs)(p.Z,{href:t,className:(0,u.Z)(I.tag,s?I.tagWithCount:I.tagRegular),children:[n,s&&(0,i.jsx)("span",{children:s})]})}const U={tags:"tags_jXut",tag:"tag_QGVx"};function R(e){let{tags:t}=e;return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)("b",{children:(0,i.jsx)(h.Z,{id:"theme.tags.tagsListLabel",description:"The label alongside a tag list",children:"Tags:"})}),(0,i.jsx)("ul",{className:(0,u.Z)(U.tags,"padding--none","margin-left--sm"),children:t.map((e=>{let{label:t,permalink:n}=e;return(0,i.jsx)("li",{className:U.tag,children:(0,i.jsx)(S,{label:t,permalink:n})},n)}))})]})}const z={lastUpdated:"lastUpdated_vwxv"};function O(e){return(0,i.jsx)("div",{className:(0,u.Z)(j.k.docs.docFooterTagsRow,"row margin-bottom--sm"),children:(0,i.jsx)("div",{className:"col",children:(0,i.jsx)(R,{...e})})})}function V(e){let{editUrl:t,lastUpdatedAt:n,lastUpdatedBy:s,formattedLastUpdatedAt:a}=e;return(0,i.jsxs)("div",{className:(0,u.Z)(j.k.docs.docFooterEditMetaRow,"row"),children:[(0,i.jsx)("div",{className:"col",children:t&&(0,i.jsx)(A,{editUrl:t})}),(0,i.jsx)("div",{className:(0,u.Z)("col",z.lastUpdated),children:(n||s)&&(0,i.jsx)(E,{lastUpdatedAt:n,formattedLastUpdatedAt:a,lastUpdatedBy:s})})]})}function P(){const{metadata:e}=c(),{editUrl:t,lastUpdatedAt:n,formattedLastUpdatedAt:s,lastUpdatedBy:a,tags:o}=e,l=o.length>0,r=!!(t||n||a);return l||r?(0,i.jsxs)("footer",{className:(0,u.Z)(j.k.docs.docFooter,"docusaurus-mt-lg"),children:[l&&(0,i.jsx)(O,{tags:o}),r&&(0,i.jsx)(V,{editUrl:t,lastUpdatedAt:n,lastUpdatedBy:a,formattedLastUpdatedAt:s})]}):null}var $=n(6043),D=n(6668);function W(e){const t=e.map((e=>({...e,parentIndex:-1,children:[]}))),n=Array(7).fill(-1);t.forEach(((e,t)=>{const s=n.slice(2,e.level);e.parentIndex=Math.max(...s),n[e.level]=t}));const s=[];return t.forEach((e=>{const{parentIndex:n,...a}=e;n>=0?t[n].children.push(a):s.push(a)})),s}function F(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:s}=e;return t.flatMap((e=>{const t=F({toc:e.children,minHeadingLevel:n,maxHeadingLevel:s});return function(e){return e.level>=n&&e.level<=s}(e)?[{...e,children:t}]:t}))}function q(e){const t=e.getBoundingClientRect();return t.top===t.bottom?q(e.parentNode):t}function G(e,t){let{anchorTopOffset:n}=t;const s=e.find((e=>q(e).top>=n));if(s){return function(e){return e.top>0&&e.bottom<window.innerHeight/2}(q(s))?s:e[e.indexOf(s)-1]??null}return e[e.length-1]??null}function J(){const e=(0,s.useRef)(0),{navbar:{hideOnScroll:t}}=(0,D.L)();return(0,s.useEffect)((()=>{e.current=t?0:document.querySelector(".navbar").clientHeight}),[t]),e}function Y(e){const t=(0,s.useRef)(void 0),n=J();(0,s.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:s,linkActiveClassName:a,minHeadingLevel:o,maxHeadingLevel:i}=e;function l(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(s),l=function(e){let{minHeadingLevel:t,maxHeadingLevel:n}=e;const s=[];for(let a=t;a<=n;a+=1)s.push(`h${a}.anchor`);return Array.from(document.querySelectorAll(s.join()))}({minHeadingLevel:o,maxHeadingLevel:i}),r=G(l,{anchorTopOffset:n.current}),c=e.find((e=>r&&r.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,n){n?(t.current&&t.current!==e&&t.current.classList.remove(a),e.classList.add(a),t.current=e):e.classList.remove(a)}(e,e===c)}))}return document.addEventListener("scroll",l),document.addEventListener("resize",l),l(),()=>{document.removeEventListener("scroll",l),document.removeEventListener("resize",l)}}),[e,n])}function Q(e){let{toc:t,className:n,linkClassName:s,isChild:a}=e;return t.length?(0,i.jsx)("ul",{className:a?void 0:n,children:t.map((e=>(0,i.jsxs)("li",{children:[(0,i.jsx)(p.Z,{to:`#${e.id}`,className:s??void 0,dangerouslySetInnerHTML:{__html:e.value}}),(0,i.jsx)(Q,{isChild:!0,toc:e.children,className:n,linkClassName:s})]},e.id)))}):null}const X=s.memo(Q);function K(e){let{toc:t,className:n="table-of-contents table-of-contents__left-border",linkClassName:a="table-of-contents__link",linkActiveClassName:o,minHeadingLevel:l,maxHeadingLevel:r,...c}=e;const d=(0,D.L)(),u=l??d.tableOfContents.minHeadingLevel,m=r??d.tableOfContents.maxHeadingLevel,h=function(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:a}=e;return(0,s.useMemo)((()=>F({toc:W(t),minHeadingLevel:n,maxHeadingLevel:a})),[t,n,a])}({toc:t,minHeadingLevel:u,maxHeadingLevel:m});return Y((0,s.useMemo)((()=>{if(a&&o)return{linkClassName:a,linkActiveClassName:o,minHeadingLevel:u,maxHeadingLevel:m}}),[a,o,u,m])),(0,i.jsx)(X,{toc:h,className:n,linkClassName:a,...c})}const ee={tocCollapsibleButton:"tocCollapsibleButton_TO0P",tocCollapsibleButtonExpanded:"tocCollapsibleButtonExpanded_MG3E"};function te(e){let{collapsed:t,...n}=e;return(0,i.jsx)("button",{type:"button",...n,className:(0,u.Z)("clean-btn",ee.tocCollapsibleButton,!t&&ee.tocCollapsibleButtonExpanded,n.className),children:(0,i.jsx)(h.Z,{id:"theme.TOCCollapsible.toggleButtonLabel",description:"The label used by the button on the collapsible TOC component",children:"On this page"})})}const ne={tocCollapsible:"tocCollapsible_ETCw",tocCollapsibleContent:"tocCollapsibleContent_vkbj",tocCollapsibleExpanded:"tocCollapsibleExpanded_sAul"};function se(e){let{toc:t,className:n,minHeadingLevel:s,maxHeadingLevel:a}=e;const{collapsed:o,toggleCollapsed:l}=(0,$.u)({initialState:!0});return(0,i.jsxs)("div",{className:(0,u.Z)(ne.tocCollapsible,!o&&ne.tocCollapsibleExpanded,n),children:[(0,i.jsx)(te,{collapsed:o,onClick:l}),(0,i.jsx)($.z,{lazy:!0,className:ne.tocCollapsibleContent,collapsed:o,children:(0,i.jsx)(K,{toc:t,minHeadingLevel:s,maxHeadingLevel:a})})]})}const ae={tocMobile:"tocMobile_ITEo"};function oe(){const{toc:e,frontMatter:t}=c();return(0,i.jsx)(se,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:(0,u.Z)(j.k.docs.docTocMobile,ae.tocMobile)})}const ie={tableOfContents:"tableOfContents_bqdL",docItemContainer:"docItemContainer_F8PC"},le="table-of-contents__link toc-highlight",re="table-of-contents__link--active";function ce(e){let{className:t,...n}=e;return(0,i.jsx)("div",{className:(0,u.Z)(ie.tableOfContents,"thin-scrollbar",t),children:(0,i.jsx)(K,{...n,linkClassName:le,linkActiveClassName:re})})}function de(){const{toc:e,frontMatter:t}=c();return(0,i.jsx)(ce,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:j.k.docs.docTocDesktop})}var ue=n(2503),me=n(1151),he=n(5742),pe=n(7951),fe=n.n(pe);var xe=n(2389);const ge={details:"details_lb9f",isBrowser:"isBrowser_bmU9",collapsibleContent:"collapsibleContent_i85q"};function be(e){return!!e&&("SUMMARY"===e.tagName||be(e.parentElement))}function ve(e,t){return!!e&&(e===t||ve(e.parentElement,t))}function je(e){let{summary:t,children:n,...a}=e;const o=(0,xe.Z)(),l=(0,s.useRef)(null),{collapsed:r,setCollapsed:c}=(0,$.u)({initialState:!a.open}),[d,m]=(0,s.useState)(a.open),h=s.isValidElement(t)?t:(0,i.jsx)("summary",{children:t??"Details"});return(0,i.jsxs)("details",{...a,ref:l,open:d,"data-collapsed":r,className:(0,u.Z)(ge.details,o&&ge.isBrowser,a.className),onMouseDown:e=>{be(e.target)&&e.detail>1&&e.preventDefault()},onClick:e=>{e.stopPropagation();const t=e.target;be(t)&&ve(t,l.current)&&(e.preventDefault(),r?(c(!1),m(!0)):c(!0))},children:[h,(0,i.jsx)($.z,{lazy:!1,collapsed:r,disableSSRStyle:!0,onCollapseTransitionEnd:e=>{c(e),m(!e)},children:(0,i.jsx)("div",{className:ge.collapsibleContent,children:n})})]})}const Ne={details:"details_b_Ee"},Ce="alert alert--info";function ke(e){let{...t}=e;return(0,i.jsx)(je,{...t,className:(0,u.Z)(Ce,Ne.details,t.className)})}function Le(e){const t=s.Children.toArray(e.children),n=t.find((e=>s.isValidElement(e)&&"summary"===e.type)),a=(0,i.jsx)(i.Fragment,{children:t.filter((e=>e!==n))});return(0,i.jsx)(ke,{...e,summary:n,children:a})}function ye(e){return(0,i.jsx)(ue.Z,{...e})}const _e={containsTaskList:"containsTaskList_mC6p"};function we(e){if(void 0!==e)return(0,u.Z)(e,e?.includes("contains-task-list")&&_e.containsTaskList)}const Be={img:"img_ev3q"};function Ze(e){const{mdxAdmonitionTitle:t,rest:n}=function(e){const t=s.Children.toArray(e),n=t.find((e=>s.isValidElement(e)&&"mdxAdmonitionTitle"===e.type)),a=t.filter((e=>e!==n)),o=n?.props.children;return{mdxAdmonitionTitle:o,rest:a.length>0?(0,i.jsx)(i.Fragment,{children:a}):null}}(e.children),a=e.title??t;return{...e,...a&&{title:a},children:n}}const Te={admonition:"admonition_xJq3",admonitionHeading:"admonitionHeading_Gvgb",admonitionIcon:"admonitionIcon_Rf37",admonitionContent:"admonitionContent_BuS1"};function Ee(e){let{type:t,className:n,children:s}=e;return(0,i.jsx)("div",{className:(0,u.Z)(j.k.common.admonition,j.k.common.admonitionType(t),Te.admonition,n),children:s})}function He(e){let{icon:t,title:n}=e;return(0,i.jsxs)("div",{className:Te.admonitionHeading,children:[(0,i.jsx)("span",{className:Te.admonitionIcon,children:t}),n]})}function Me(e){let{children:t}=e;return t?(0,i.jsx)("div",{className:Te.admonitionContent,children:t}):null}function Ae(e){const{type:t,icon:n,title:s,children:a,className:o}=e;return(0,i.jsxs)(Ee,{type:t,className:o,children:[(0,i.jsx)(He,{title:s,icon:n}),(0,i.jsx)(Me,{children:a})]})}function Ie(e){return(0,i.jsx)("svg",{viewBox:"0 0 14 16",...e,children:(0,i.jsx)("path",{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"})})}const Se={icon:(0,i.jsx)(Ie,{}),title:(0,i.jsx)(h.Z,{id:"theme.admonition.note",description:"The default label used for the Note admonition (:::note)",children:"note"})};function Ue(e){return(0,i.jsx)(Ae,{...Se,...e,className:(0,u.Z)("alert alert--secondary",e.className),children:e.children})}function Re(e){return(0,i.jsx)("svg",{viewBox:"0 0 12 16",...e,children:(0,i.jsx)("path",{fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"})})}const ze={icon:(0,i.jsx)(Re,{}),title:(0,i.jsx)(h.Z,{id:"theme.admonition.tip",description:"The default label used for the Tip admonition (:::tip)",children:"tip"})};function Oe(e){return(0,i.jsx)(Ae,{...ze,...e,className:(0,u.Z)("alert alert--success",e.className),children:e.children})}function Ve(e){return(0,i.jsx)("svg",{viewBox:"0 0 14 16",...e,children:(0,i.jsx)("path",{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})})}const Pe={icon:(0,i.jsx)(Ve,{}),title:(0,i.jsx)(h.Z,{id:"theme.admonition.info",description:"The default label used for the Info admonition (:::info)",children:"info"})};function $e(e){return(0,i.jsx)(Ae,{...Pe,...e,className:(0,u.Z)("alert alert--info",e.className),children:e.children})}function De(e){return(0,i.jsx)("svg",{viewBox:"0 0 16 16",...e,children:(0,i.jsx)("path",{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"})})}const We={icon:(0,i.jsx)(De,{}),title:(0,i.jsx)(h.Z,{id:"theme.admonition.warning",description:"The default label used for the Warning admonition (:::warning)",children:"warning"})};function Fe(e){return(0,i.jsx)("svg",{viewBox:"0 0 12 16",...e,children:(0,i.jsx)("path",{fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"})})}const qe={icon:(0,i.jsx)(Fe,{}),title:(0,i.jsx)(h.Z,{id:"theme.admonition.danger",description:"The default label used for the Danger admonition (:::danger)",children:"danger"})};const Ge={icon:(0,i.jsx)(De,{}),title:(0,i.jsx)(h.Z,{id:"theme.admonition.caution",description:"The default label used for the Caution admonition (:::caution)",children:"caution"})};const Je={...{note:Ue,tip:Oe,info:$e,warning:function(e){return(0,i.jsx)(Ae,{...We,...e,className:(0,u.Z)("alert alert--warning",e.className),children:e.children})},danger:function(e){return(0,i.jsx)(Ae,{...qe,...e,className:(0,u.Z)("alert alert--danger",e.className),children:e.children})}},...{secondary:e=>(0,i.jsx)(Ue,{title:"secondary",...e}),important:e=>(0,i.jsx)($e,{title:"important",...e}),success:e=>(0,i.jsx)(Oe,{title:"success",...e}),caution:function(e){return(0,i.jsx)(Ae,{...Ge,...e,className:(0,u.Z)("alert alert--warning",e.className),children:e.children})}}};function Ye(e){const t=Ze(e),n=(s=t.type,Je[s]||(console.warn(`No admonition component found for admonition type "${s}". Using Info as fallback.`),Je.info));var s;return(0,i.jsx)(n,{...t})}var Qe=n(1875);const Xe={Head:he.Z,details:Le,Details:Le,code:function(e){return s.Children.toArray(e.children).every((e=>"string"==typeof e&&!e.includes("\n")))?(0,i.jsx)("code",{...e}):(0,i.jsx)(fe(),{...e})},a:function(e){return(0,i.jsx)(p.Z,{...e})},pre:function(e){return(0,i.jsx)(i.Fragment,{children:e.children})},ul:function(e){return(0,i.jsx)("ul",{...e,className:we(e.className)})},img:function(e){return(0,i.jsx)("img",{loading:"lazy",...e,className:(t=e.className,(0,u.Z)(t,Be.img))});var t},h1:e=>(0,i.jsx)(ye,{as:"h1",...e}),h2:e=>(0,i.jsx)(ye,{as:"h2",...e}),h3:e=>(0,i.jsx)(ye,{as:"h3",...e}),h4:e=>(0,i.jsx)(ye,{as:"h4",...e}),h5:e=>(0,i.jsx)(ye,{as:"h5",...e}),h6:e=>(0,i.jsx)(ye,{as:"h6",...e}),admonition:Ye,mermaid:Qe.Z};function Ke(e){let{children:t}=e;return(0,i.jsx)(me.Z,{components:Xe,children:t})}function et(e){let{children:t}=e;const n=function(){const{metadata:e,frontMatter:t,contentTitle:n}=c();return t.hide_title||void 0!==n?null:e.title}();return(0,i.jsxs)("div",{className:(0,u.Z)(j.k.docs.docMarkdown,"markdown"),children:[n&&(0,i.jsx)("header",{children:(0,i.jsx)(ue.Z,{as:"h1",children:n})}),(0,i.jsx)(Ke,{children:t})]})}var tt=n(2802),nt=n(8596),st=n(4996);function at(e){return(0,i.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,i.jsx)("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"})})}const ot={breadcrumbHomeIcon:"breadcrumbHomeIcon_YNFT"};function it(){const e=(0,st.Z)("/");return(0,i.jsx)("li",{className:"breadcrumbs__item",children:(0,i.jsx)(p.Z,{"aria-label":(0,h.I)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:"breadcrumbs__link",href:e,children:(0,i.jsx)(at,{className:ot.breadcrumbHomeIcon})})})}const lt={breadcrumbsContainer:"breadcrumbsContainer_Z_bl"};function rt(e){let{children:t,href:n,isLast:s}=e;const a="breadcrumbs__link";return s?(0,i.jsx)("span",{className:a,itemProp:"name",children:t}):n?(0,i.jsx)(p.Z,{className:a,href:n,itemProp:"item",children:(0,i.jsx)("span",{itemProp:"name",children:t})}):(0,i.jsx)("span",{className:a,children:t})}function ct(e){let{children:t,active:n,index:s,addMicrodata:a}=e;return(0,i.jsxs)("li",{...a&&{itemScope:!0,itemProp:"itemListElement",itemType:"https://schema.org/ListItem"},className:(0,u.Z)("breadcrumbs__item",{"breadcrumbs__item--active":n}),children:[t,(0,i.jsx)("meta",{itemProp:"position",content:String(s+1)})]})}function dt(){const e=(0,tt.s1)(),t=(0,nt.Ns)();return e?(0,i.jsx)("nav",{className:(0,u.Z)(j.k.docs.docBreadcrumbs,lt.breadcrumbsContainer),"aria-label":(0,h.I)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"}),children:(0,i.jsxs)("ul",{className:"breadcrumbs",itemScope:!0,itemType:"https://schema.org/BreadcrumbList",children:[t&&(0,i.jsx)(it,{}),e.map(((t,n)=>{const s=n===e.length-1,a="category"===t.type&&t.linkUnlisted?void 0:t.href;return(0,i.jsx)(ct,{active:s,index:n,addMicrodata:!!a,children:(0,i.jsx)(rt,{href:a,isLast:s,children:t.label})},n)}))]})}):null}function ut(){return(0,i.jsx)(h.Z,{id:"theme.unlistedContent.title",description:"The unlisted content banner title",children:"Unlisted page"})}function mt(){return(0,i.jsx)(h.Z,{id:"theme.unlistedContent.message",description:"The unlisted content banner message",children:"This page is unlisted. Search engines will not index it, and only users having a direct link can access it."})}function ht(){return(0,i.jsx)(he.Z,{children:(0,i.jsx)("meta",{name:"robots",content:"noindex, nofollow"})})}function pt(e){let{className:t}=e;return(0,i.jsx)(Ye,{type:"caution",title:(0,i.jsx)(ut,{}),className:(0,u.Z)(t,j.k.common.unlistedBanner),children:(0,i.jsx)(mt,{})})}function ft(e){return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(ht,{}),(0,i.jsx)(pt,{...e})]})}const xt={docItemContainer:"docItemContainer_Djhp",docItemCol:"docItemCol_VOVn"};function gt(e){let{children:t}=e;const n=function(){const{frontMatter:e,toc:t}=c(),n=(0,m.i)(),s=e.hide_table_of_contents,a=!s&&t.length>0;return{hidden:s,mobile:a?(0,i.jsx)(oe,{}):void 0,desktop:!a||"desktop"!==n&&"ssr"!==n?void 0:(0,i.jsx)(de,{})}}(),{metadata:{unlisted:s}}=c();return(0,i.jsxs)("div",{className:"row",children:[(0,i.jsxs)("div",{className:(0,u.Z)("col",!n.hidden&&xt.docItemCol),children:[s&&(0,i.jsx)(ft,{}),(0,i.jsx)(w,{}),(0,i.jsxs)("div",{className:xt.docItemContainer,children:[(0,i.jsxs)("article",{children:[(0,i.jsx)(dt,{}),(0,i.jsx)(B,{}),n.mobile,(0,i.jsx)(et,{children:t}),(0,i.jsx)(P,{})]}),(0,i.jsx)(g,{})]})]}),n.desktop&&(0,i.jsx)("div",{className:"col col--3",children:n.desktop})]})}function bt(e){const t=`docs-doc-id-${e.content.metadata.id}`,n=e.content;return(0,i.jsx)(r,{content:e.content,children:(0,i.jsxs)(a.FG,{className:t,children:[(0,i.jsx)(d,{}),(0,i.jsx)(gt,{children:(0,i.jsx)(n,{})})]})})}},7594:(e,t)=>{function n(e){let t,n=[];for(let s of e.split(",").map((e=>e.trim())))if(/^-?\d+$/.test(s))n.push(parseInt(s,10));else if(t=s.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[e,s,a,o]=t;if(s&&o){s=parseInt(s),o=parseInt(o);const e=s<o?1:-1;"-"!==a&&".."!==a&&"\u2025"!==a||(o+=e);for(let t=s;t!==o;t+=e)n.push(t)}}return n}t.default=n,e.exports=n},1151:(e,t,n)=>{"use strict";n.d(t,{Z:()=>l,a:()=>i});var s=n(7294);const a={},o=s.createContext(a);function i(e){const t=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:i(e.components),s.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/1ae81764.482af898.js b/assets/js/1ae81764.482af898.js new file mode 100644 index 0000000000..7dd47bd6ad --- /dev/null +++ b/assets/js/1ae81764.482af898.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2262],{9436:(e,i,t)=>{t.r(i),t.d(i,{assets:()=>c,contentTitle:()=>o,default:()=>d,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var n=t(5893),r=t(1151);const a={sidebar_position:2},o="Terminology",s={id:"introduction/terminology",title:"Terminology",description:"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.",source:"@site/versioned_docs/version-v4.2.0-docs/introduction/terminology.md",sourceDirName:"introduction",slug:"/introduction/terminology",permalink:"/interchain-security/v4.2.0/introduction/terminology",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/v4.2.0/introduction/overview"},next:{title:"Interchain Security Parameters",permalink:"/interchain-security/v4.2.0/introduction/params"}},c={},l=[{value:"Shared Security",id:"shared-security",level:2},{value:"Interchain Security",id:"interchain-security",level:2},{value:"Replicated Security",id:"replicated-security",level:2},{value:"Partial Set Security",id:"partial-set-security",level:2},{value:"Mesh security",id:"mesh-security",level:2},{value:"Consumer Chain",id:"consumer-chain",level:2},{value:"Standalone Chain",id:"standalone-chain",level:2},{value:"Changeover Procedure",id:"changeover-procedure",level:2}];function h(e){const i={a:"a",h1:"h1",h2:"h2",p:"p",strong:"strong",...(0,r.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(i.h1,{id:"terminology",children:"Terminology"}),"\n",(0,n.jsx)(i.p,{children:"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions."}),"\n",(0,n.jsx)(i.h2,{id:"shared-security",children:"Shared Security"}),"\n",(0,n.jsx)(i.p,{children:"Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share its proof-of-stake security with another blockchain or off-chain process."}),"\n",(0,n.jsx)(i.h2,{id:"interchain-security",children:"Interchain Security"}),"\n",(0,n.jsx)(i.p,{children:"Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC."}),"\n",(0,n.jsx)(i.h2,{id:"replicated-security",children:"Replicated Security"}),"\n",(0,n.jsx)(i.p,{children:'A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC.'}),"\n",(0,n.jsx)(i.h2,{id:"partial-set-security",children:"Partial Set Security"}),"\n",(0,n.jsx)(i.p,{children:'A major iteration of Interchain Security, also known as "Interchain Security V2". Partial Set Security allows a provider chain to share only a subset of its validator set with a consumer chain. This subset can be determined by the top N% validators by voting power, or by validators opting in to validate the consumer chain. Partial Set Security allows for more flexible security tradeoffs than Replicated Security.'}),"\n",(0,n.jsx)(i.h2,{id:"mesh-security",children:"Mesh security"}),"\n",(0,n.jsxs)(i.p,{children:["A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see ",(0,n.jsx)(i.a,{href:"https://informal.systems/blog/replicated-vs-mesh-security",children:"Replicated vs. Mesh Security on the Informal Blog"}),"."]}),"\n",(0,n.jsx)(i.h2,{id:"consumer-chain",children:"Consumer Chain"}),"\n",(0,n.jsx)(i.p,{children:"Chain that is secured by the validator set of the provider, instead of its own.\nReplicated security allows the provider chain validator set to validate blocks on the consumer chain."}),"\n",(0,n.jsx)(i.h2,{id:"standalone-chain",children:"Standalone Chain"}),"\n",(0,n.jsx)(i.p,{children:"Chain that is secured by its own validator set. This chain does not participate in replicated security."}),"\n",(0,n.jsx)(i.p,{children:'Standalone chains may sometimes be called "sovereign" - the terms are synonymous.'}),"\n",(0,n.jsx)(i.h2,{id:"changeover-procedure",children:"Changeover Procedure"}),"\n",(0,n.jsxs)(i.p,{children:["Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the ",(0,n.jsx)(i.strong,{children:"changeover procedure"})," and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain."]})]})}function d(e={}){const{wrapper:i}={...(0,r.a)(),...e.components};return i?(0,n.jsx)(i,{...e,children:(0,n.jsx)(h,{...e})}):h(e)}},1151:(e,i,t)=>{t.d(i,{Z:()=>s,a:()=>o});var n=t(7294);const r={},a=n.createContext(r);function o(e){const i=n.useContext(a);return n.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function s(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),n.createElement(a.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/1ca82e41.07ae1c1e.js b/assets/js/1ca82e41.07ae1c1e.js new file mode 100644 index 0000000000..6d7f944d81 --- /dev/null +++ b/assets/js/1ca82e41.07ae1c1e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7617],{1343:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>c,contentTitle:()=>s,default:()=>l,frontMatter:()=>o,metadata:()=>a,toc:()=>d});var i=r(5893),t=r(1151);const o={sidebar_position:6},s="Consumer Genesis Transformation",a={id:"consumer-development/consumer-genesis-transformation",title:"Consumer Genesis Transformation",description:"Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentation on Onboarding and Changeover).",source:"@site/versioned_docs/version-v5.0.0/consumer-development/consumer-genesis-transformation.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-genesis-transformation",permalink:"/interchain-security/v5.0.0/consumer-development/consumer-genesis-transformation",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"tutorialSidebar",previous:{title:"Changeover Procedure",permalink:"/interchain-security/v5.0.0/consumer-development/changeover-procedure"},next:{title:"Overview",permalink:"/interchain-security/v5.0.0/validators/overview"}},c={},d=[{value:"1. Prerequisite",id:"1-prerequisite",level:2},{value:"2. Export the CCV data",id:"2-export-the-ccv-data",level:2},{value:"3. Transform CCV data",id:"3-transform-ccv-data",level:2}];function h(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,t.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"consumer-genesis-transformation",children:"Consumer Genesis Transformation"}),"\n",(0,i.jsxs)(n.p,{children:["Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentation on ",(0,i.jsx)(n.a,{href:"/interchain-security/v5.0.0/consumer-development/onboarding",children:"Onboarding"})," and ",(0,i.jsx)(n.a,{href:"/interchain-security/v5.0.0/consumer-development/changeover-procedure",children:"Changeover"}),").\nIn case that the provider chain is running an older version of the InterChainSecurity (ICS) module than the consumer chain - or vice versa - the exported CCV data might need to be transformed to the format supported by the ICS implementation run on the consumer chain. This is the case if the consumer chain runs version 4 of ICS or later and the provider is running version 3 or older of the ICS module."]}),"\n",(0,i.jsxs)(n.p,{children:["Check the ",(0,i.jsx)(n.a,{href:"../../../RELEASES.md#backwards-compatibility",children:"compatibility notes"})," for known incompatibilities between provider and consumer versions and indications if a consumer genesis transformation is required."]}),"\n",(0,i.jsx)(n.p,{children:"To transform such CCV data follow the instructions below"}),"\n",(0,i.jsx)(n.h2,{id:"1-prerequisite",children:"1. Prerequisite"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["used provider and consumer versions require transformation step as indicated in in the ",(0,i.jsx)(n.a,{href:"../../../RELEASES.md#backwards-compatibility",children:"compatibility notes"})]}),"\n",(0,i.jsx)(n.li,{children:"interchain-security-cd application supports the versions used by the consumer and provider"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"2-export-the-ccv-data",children:"2. Export the CCV data"}),"\n",(0,i.jsxs)(n.p,{children:["Export the CCV data from the provider chain as described in the ",(0,i.jsx)(n.a,{href:"/interchain-security/v5.0.0/consumer-development/onboarding",children:"Onboarding"})," and ",(0,i.jsx)(n.a,{href:"/interchain-security/v5.0.0/consumer-development/changeover-procedure",children:"Changeover"})," your following.\nAs a result the CCV data will be stored in a file in JSON format."]}),"\n",(0,i.jsx)(n.h2,{id:"3-transform-ccv-data",children:"3. Transform CCV data"}),"\n",(0,i.jsx)(n.p,{children:"To transform the CCV data"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["to the format supported by the current version of the consumer run the following command:","\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"interchain-security-cd genesis transform [genesis-file]\n"})}),"\n","where 'genesis-file' is the path to the file containing the CCV data exported in ",(0,i.jsx)(n.a,{href:"#2-export-the-ccv-data",children:"step 2"}),".\nAs a result the CCV data in the new format will be written to standard output."]}),"\n",(0,i.jsxs)(n.li,{children:["a specific target version of a consumer run the following command:","\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"interchain-security-cd genesis transform --to <target_version> [genesis-file]\n\n"})}),"\n","where ",(0,i.jsx)(n.code,{children:"<target_version"})," is the ICS version the consumer chain is running.\nUse ",(0,i.jsx)(n.code,{children:"interchain-security-cd genesis transform --help"})," to get more details about supported target versions and more."]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Use the new CCV data as described in the procedure you're following."})]})}function l(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},1151:(e,n,r)=>{r.d(n,{Z:()=>a,a:()=>s});var i=r(7294);const t={},o=i.createContext(t);function s(e){const n=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:s(e.components),i.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/21cfc626.8729733a.js b/assets/js/21cfc626.8729733a.js new file mode 100644 index 0000000000..a47c80dbae --- /dev/null +++ b/assets/js/21cfc626.8729733a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[52],{964:(e,r,n)=>{n.r(r),n.d(r,{assets:()=>u,contentTitle:()=>c,default:()=>m,frontMatter:()=>o,metadata:()=>d,toc:()=>h});var t=n(5893),i=n(1151),s=n(2307),a=n(8758);const o={sidebar_position:1},c="Interchain Security Docs",d={id:"index",title:"Interchain Security Docs",description:"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.",source:"@site/versioned_docs/version-v5.0.0/index.mdx",sourceDirName:".",slug:"/",permalink:"/interchain-security/v5.0.0/",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",next:{title:"Overview",permalink:"/interchain-security/v5.0.0/introduction/overview"}},u={},h=[];function l(e){const r={h1:"h1",p:"p",...(0,i.a)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(r.h1,{id:"interchain-security-docs",children:"Interchain Security Docs"}),"\n",(0,t.jsx)(r.p,{children:"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains."}),"\n",(0,t.jsx)(r.p,{children:"Here you can find information about replicated security, consumer chain development and instructions for validator onboarding."}),"\n",(0,t.jsx)(s.Z,{cards:a.Z})]})}function m(e={}){const{wrapper:r}={...(0,i.a)(),...e.components};return r?(0,t.jsx)(r,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},2307:(e,r,n)=>{n.d(r,{Z:()=>s});n(7294);var t=n(5893);const i=function(e){return(0,t.jsx)("a",{href:e.href,className:"border shadow rounded-sm border-stone-200 dark:border-stone-800 dark:bg-neutral-900 hover:border-stone-300 hover:shadow-lg dark:hover:border-stone-200 transition-all duration-200 no-underline",children:(0,t.jsxs)("div",{className:"p-6",children:[(0,t.jsx)("h2",{className:"",children:e.header}),(0,t.jsx)("p",{className:"",children:e.summary})]})})};const s=function(e){return(0,t.jsx)("div",{className:"card-section grid grid-cols-1 lg:grid-cols-2 gap-4 no-underline",children:e.cards.map(((e,r)=>(0,t.jsx)(i,{href:e.href,header:e.header,summary:e.summary},r)))})}},8758:(e,r,n)=>{n.d(r,{Z:()=>t});const t=[{href:"/interchain-security/introduction/overview",header:"Basic concepts",summary:"Get started with the basic concepts and ideas."},{href:"/interchain-security/consumer-development/app-integration",header:"Start building",summary:"Click here to start building with Interchain security"},{href:"/interchain-security/features/key-assignment",header:"Feature: Key Assignment",summary:"Learn about the key assignment feature"},{href:"/interchain-security/features/reward-distribution",header:"Feature: Reward Distribution",summary:"Learn about consumer chain rewards distribution"},{href:"/interchain-security/consumer-development/onboarding",header:"Onboarding Checklist",summary:"Checklist to help you integrate Interchain Security, get support and onboard validators"},{href:"/interchain-security/faq",header:"FAQ",summary:"Frequently asked questions about the protocol and its implications"}]},1151:(e,r,n)=>{n.d(r,{Z:()=>o,a:()=>a});var t=n(7294);const i={},s=t.createContext(i);function a(e){const r=t.useContext(s);return t.useMemo((function(){return"function"==typeof e?e(r):{...r,...e}}),[r,e])}function o(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),t.createElement(s.Provider,{value:r},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/21dfdb60.4f19dea1.js b/assets/js/21dfdb60.4f19dea1.js new file mode 100644 index 0000000000..a65701ba7c --- /dev/null +++ b/assets/js/21dfdb60.4f19dea1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5932],{2702:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>a,toc:()=>c});var s=t(5893),i=t(1151);const o={sidebar_position:2,title:"ADR Template"},r="ADR [ADR-NUMBER]: [TITLE]",a={id:"adrs/adr-template",title:"ADR Template",description:"Changelog",source:"@site/versioned_docs/version-v5.0.0/adrs/adr-template.md",sourceDirName:"adrs",slug:"/adrs/adr-template",permalink:"/interchain-security/v5.0.0/adrs/adr-template",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"ADR Template"},sidebar:"tutorialSidebar",previous:{title:"ADR Template",permalink:"/interchain-security/v5.0.0/adrs/adr-007-pause-unbonding-on-eqv-prop"},next:{title:"Key Assignment",permalink:"/interchain-security/v5.0.0/adrs/adr-001-key-assignment"}},l={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function d(e){const n={blockquote:"blockquote",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,i.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"adr-adr-number-title",children:"ADR [ADR-NUMBER]: [TITLE]"}),"\n",(0,s.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:'A decision may be "proposed" if it hasn\'t been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement.'}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"[Deprecated|Proposed|Accepted]"}),"\n",(0,s.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution."}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"This section explains all of the details of the proposed solution, including implementation details.\nIt should also describe affects / corollary items that may need to be changed as a part of this.\nIf the proposed change will be large, please also indicate a way to do the change to maximize ease of review.\n(e.g. the optimal split of things to do between separate PR's)"}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:'This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones.'}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,s.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,s.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,s.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!"}),"\n"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"[references]"}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>a,a:()=>r});var s=t(7294);const i={},o=s.createContext(i);function r(e){const n=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/2510f7b4.823faae0.js b/assets/js/2510f7b4.823faae0.js new file mode 100644 index 0000000000..26384470de --- /dev/null +++ b/assets/js/2510f7b4.823faae0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2558],{6250:(n,e,t)=>{t.r(e),t.d(e,{assets:()=>a,contentTitle:()=>s,default:()=>l,frontMatter:()=>o,metadata:()=>c,toc:()=>u});var i=t(5893),r=t(1151);const o={sidebar_position:5},s="Joining Neutron",c={id:"validators/joining-neutron",title:"Joining Neutron",description:"Neutron is the first consumer chain to implement ICS.",source:"@site/versioned_docs/version-v4.2.0-docs/validators/joining-neutron.md",sourceDirName:"validators",slug:"/validators/joining-neutron",permalink:"/interchain-security/v4.2.0/validators/joining-neutron",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Validator Instructions for Changeover Procedure",permalink:"/interchain-security/v4.2.0/validators/changeover-procedure"},next:{title:"Joining Stride",permalink:"/interchain-security/v4.2.0/validators/joining-stride"}},a={},u=[{value:"Resources",id:"resources",level:2}];function d(n){const e={a:"a",h1:"h1",h2:"h2",li:"li",p:"p",ul:"ul",...(0,r.a)(),...n.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"joining-neutron",children:"Joining Neutron"}),"\n",(0,i.jsx)(e.p,{children:"Neutron is the first consumer chain to implement ICS."}),"\n",(0,i.jsxs)(e.p,{children:["You can find instructions on joining the mainnet ",(0,i.jsx)(e.a,{href:"https://docs.neutron.org/neutron/consumer-chain-launch",children:"here"}),"."]}),"\n",(0,i.jsxs)(e.p,{children:["To join Neutron chain on the interchain security testnet check ",(0,i.jsx)(e.a,{href:"https://github.com/cosmos/testnets/tree/master/interchain-security/pion-1",children:"here"})]}),"\n",(0,i.jsx)(e.h2,{id:"resources",children:"Resources"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:"https://docs.neutron.org",children:"Neutron docs"})}),"\n"]})]})}function l(n={}){const{wrapper:e}={...(0,r.a)(),...n.components};return e?(0,i.jsx)(e,{...n,children:(0,i.jsx)(d,{...n})}):d(n)}},1151:(n,e,t)=>{t.d(e,{Z:()=>c,a:()=>s});var i=t(7294);const r={},o=i.createContext(r);function s(n){const e=i.useContext(o);return i.useMemo((function(){return"function"==typeof n?n(e):{...e,...n}}),[e,n])}function c(n){let e;return e=n.disableParentContext?"function"==typeof n.components?n.components(r):n.components||r:s(n.components),i.createElement(o.Provider,{value:e},n.children)}}}]); \ No newline at end of file diff --git a/assets/js/26981f24.3de9a95d.js b/assets/js/26981f24.3de9a95d.js new file mode 100644 index 0000000000..fcd7347c29 --- /dev/null +++ b/assets/js/26981f24.3de9a95d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1483],{5183:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>r,toc:()=>d});var s=i(5893),t=i(1151);const o={sidebar_position:5},a="Changeover Procedure",r={id:"consumer-development/changeover-procedure",title:"Changeover Procedure",description:"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.",source:"@site/versioned_docs/version-v5.0.0/consumer-development/changeover-procedure.md",sourceDirName:"consumer-development",slug:"/consumer-development/changeover-procedure",permalink:"/interchain-security/v5.0.0/consumer-development/changeover-procedure",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Offboarding Checklist",permalink:"/interchain-security/v5.0.0/consumer-development/offboarding"},next:{title:"Consumer Genesis Transformation",permalink:"/interchain-security/v5.0.0/consumer-development/consumer-genesis-transformation"}},c={},d=[{value:"Overview",id:"overview",level:2},{value:"1. ConsumerAddition proposal submitted to the <code>provider</code> chain",id:"1-consumeraddition-proposal-submitted-to-the-provider-chain",level:3},{value:"2. upgrade proposal on standalone chain",id:"2-upgrade-proposal-on-standalone-chain",level:3},{value:"3. spawn time is reached",id:"3-spawn-time-is-reached",level:3},{value:"4. standalone chain upgrade",id:"4-standalone-chain-upgrade",level:3},{value:"Notes",id:"notes",level:4},{value:"Onboarding Checklist",id:"onboarding-checklist",level:2},{value:"1. Complete testing & integration",id:"1-complete-testing--integration",level:2},{value:"2. Create an Onboarding Repository",id:"2-create-an-onboarding-repository",level:2},{value:"3. Submit a ConsumerChainAddition Governance Proposal to the provider",id:"3-submit-a-consumerchainaddition-governance-proposal-to-the-provider",level:2},{value:"3. Submit an Upgrade Proposal & Prepare for Changeover",id:"3-submit-an-upgrade-proposal--prepare-for-changeover",level:2},{value:"4. Upgrade time \ud83d\ude80",id:"4-upgrade-time-",level:2}];function l(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",input:"input",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"changeover-procedure",children:"Changeover Procedure"}),"\n",(0,s.jsxs)(n.p,{children:["Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the ",(0,s.jsx)(n.strong,{children:"changeover procedure"})," and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain."]}),"\n",(0,s.jsx)(n.p,{children:"The relevant protocol specifications are available below:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md#channel-initialization-existing-chains",children:"ICS-28 with existing chains"}),"."]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-010-standalone-changeover",children:"ADR in ICS repo"})}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"overview",children:"Overview"}),"\n",(0,s.jsx)(n.p,{children:"Standalone to consumer changeover procedure can roughly be separated into 4 parts:"}),"\n",(0,s.jsxs)(n.h3,{id:"1-consumeraddition-proposal-submitted-to-the-provider-chain",children:["1. ConsumerAddition proposal submitted to the ",(0,s.jsx)(n.code,{children:"provider"})," chain"]}),"\n",(0,s.jsx)(n.p,{children:'The proposal is equivalent to the "normal" ConsumerAddition proposal submitted by new consumer chains.'}),"\n",(0,s.jsx)(n.p,{children:"However, here are the most important notes and differences between a new consumer chain and a standalone chain performing a changeover:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"chain_id"})," must be equal to the standalone chain id"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"initial_height"})," field has additional rules to abide by:"]}),"\n"]}),"\n",(0,s.jsxs)(n.admonition,{type:"caution",children:[(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:'{\n...\n "initial_height" : {\n // must correspond to current revision number of standalone chain\n // e.g. stride-1 => "revision_number": 1\n "revision_number": 1,\n\n // must correspond to a height that is at least 1 block after the upgrade\n // that will add the `consumer` module to the standalone chain\n // e.g. "upgrade_height": 100 => "revision_height": 101\n "revision_height": 1,\n },\n...\n}\n'})}),(0,s.jsx)(n.p,{children:"RevisionNumber: 0, RevisionHeight: 111"})]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"genesis_hash"})," can be safely ignored because the chain is already running. A hash of the standalone chain's initial genesis may be used"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"binary_hash"})," may not be available ahead of time. All chains performing the changeover go through rigorous testing - if bugs are caught and fixed the hash listed in the proposal may not be the most recent one."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"spawn_time"})," listed in the proposal MUST be before the ",(0,s.jsx)(n.code,{children:"upgrade_height"})," listed in the upgrade proposal on the standalone chain."]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.admonition,{type:"caution",children:(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"spawn_time"})," must occur before the ",(0,s.jsx)(n.code,{children:"upgrade_height"})," on the standalone chain is reached because the ",(0,s.jsx)(n.code,{children:"provider"})," chain must generate the ",(0,s.jsx)(n.code,{children:"ConsumerGenesis"})," that contains the ",(0,s.jsx)(n.strong,{children:"validator set"})," that will be used after the changeover."]})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"unbonding_period"})," must correspond to the value used on the standalone chain. Otherwise, the clients used for the ccv protocol may be incorrectly initialized."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"distribution_transmission_channel"})," ",(0,s.jsx)(n.strong,{children:"should be set"}),"."]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.admonition,{type:"note",children:[(0,s.jsxs)(n.p,{children:["Populating ",(0,s.jsx)(n.code,{children:"distribution_transmission_channel"})," will enable the standalone chain to reuse one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ",(0,s.jsx)(n.code,{children:"ibc denom"})," that may already be in use."]}),(0,s.jsx)(n.p,{children:"If the parameter is not set, a new channel will be created."})]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"ccv_timeout_period"})," has no important notes"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"transfer_timeout_period"})," has no important notes"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"consumer_redistribution_fraction"})," has no important notes"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"blocks_per_distribution_transmission"})," has no important notes"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"historical_entries"})," has no important notes"]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"2-upgrade-proposal-on-standalone-chain",children:"2. upgrade proposal on standalone chain"}),"\n",(0,s.jsxs)(n.p,{children:["The standalone chain creates an upgrade proposal to include the ",(0,s.jsx)(n.code,{children:"interchain-security/x/ccv/consumer"})," module."]}),"\n",(0,s.jsx)(n.admonition,{type:"caution",children:(0,s.jsxs)(n.p,{children:["The upgrade height in the proposal should correspond to a height that is after the ",(0,s.jsx)(n.code,{children:"spawn_time"})," in the consumer addition proposal submitted to the ",(0,s.jsx)(n.code,{children:"provider"})," chain."]})}),"\n",(0,s.jsx)(n.p,{children:"Otherwise, the upgrade is indistinguishable from a regular on-chain upgrade proposal."}),"\n",(0,s.jsx)(n.h3,{id:"3-spawn-time-is-reached",children:"3. spawn time is reached"}),"\n",(0,s.jsxs)(n.p,{children:["When the ",(0,s.jsx)(n.code,{children:"spawn_time"})," is reached on the ",(0,s.jsx)(n.code,{children:"provider"})," it will generate a ",(0,s.jsx)(n.code,{children:"ConsumerGenesis"})," that contains the validator set that will supersede the ",(0,s.jsx)(n.code,{children:"standalone"})," validator set."]}),"\n",(0,s.jsxs)(n.p,{children:["This ",(0,s.jsx)(n.code,{children:"ConsumerGenesis"})," must be available on the standalone chain during the on-chain upgrade."]}),"\n",(0,s.jsx)(n.h3,{id:"4-standalone-chain-upgrade",children:"4. standalone chain upgrade"}),"\n",(0,s.jsxs)(n.p,{children:["Performing the on-chain upgrade on the standalone chain will add the ",(0,s.jsx)(n.code,{children:"ccv/consumer"})," module and allow the chain to become a ",(0,s.jsx)(n.code,{children:"consumer"})," of replicated security."]}),"\n",(0,s.jsxs)(n.admonition,{type:"caution",children:[(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"ConsumerGenesis"})," must be exported to a file and placed in the correct folder on the standalone chain before the upgrade."]}),(0,s.jsx)(n.p,{children:"The file must be placed at the exact specified location, otherwise the upgrade will not be executed correctly."}),(0,s.jsxs)(n.p,{children:["Usually the file is placed in ",(0,s.jsx)(n.code,{children:"$NODE_HOME/config"}),", but the file name and the exact directory is dictated by the upgrade code on the ",(0,s.jsx)(n.code,{children:"standalone"})," chain."]}),(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["please check exact instructions provided by the ",(0,s.jsx)(n.code,{children:"standalone"})," chain team"]}),"\n"]})]}),"\n",(0,s.jsxs)(n.p,{children:["After the ",(0,s.jsx)(n.code,{children:"genesis.json"})," file has been made available, the process is equivalent to a normal on-chain upgrade. The standalone validator set will sign the next couple of blocks before transferring control to ",(0,s.jsx)(n.code,{children:"provider"})," validator set."]}),"\n",(0,s.jsxs)(n.p,{children:["The standalone validator set can still be slashed for any infractions if evidence is submitted within the ",(0,s.jsx)(n.code,{children:"unboding_period"}),"."]}),"\n",(0,s.jsx)(n.h4,{id:"notes",children:"Notes"}),"\n",(0,s.jsx)(n.p,{children:"The changeover procedure may be updated in the future to create a seamless way of providing the validator set information to the standalone chain."}),"\n",(0,s.jsx)(n.h2,{id:"onboarding-checklist",children:"Onboarding Checklist"}),"\n",(0,s.jsxs)(n.p,{children:["This onboarding checklist is slightly different from the one under ",(0,s.jsx)(n.a,{href:"/interchain-security/v5.0.0/consumer-development/onboarding",children:"Onboarding"})]}),"\n",(0,s.jsxs)(n.p,{children:["Additionally, you can check the ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/CONSUMER_LAUNCH_GUIDE.md",children:"testnet repo"})," for a comprehensive guide on preparing and launching consumer chains."]}),"\n",(0,s.jsx)(n.h2,{id:"1-complete-testing--integration",children:"1. Complete testing & integration"}),"\n",(0,s.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","test integration with gaia"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","test your protocol with supported relayer versions (minimum hermes 1.4.1)"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","test the changeover procedure"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","reach out to the ICS team if you are facing issues"]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"2-create-an-onboarding-repository",children:"2. Create an Onboarding Repository"}),"\n",(0,s.jsx)(n.p,{children:"To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain."}),"\n",(0,s.jsx)(n.p,{children:"This should include (at minimum):"}),"\n",(0,s.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see ",(0,s.jsx)(n.a,{href:"/interchain-security/v5.0.0/consumer-development/consumer-genesis-transformation",children:"Transform Consumer Genesis"}),")"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","information about relevant seed/peer nodes you are running"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","relayer information (compatible versions)"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","copy of your governance proposal (as JSON)"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","a script showing how to start your chain and connect to peers (optional)"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable"]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["Example of such a repository can be found ",(0,s.jsx)(n.a,{href:"https://github.com/hyphacoop/ics-testnets/tree/main/game-of-chains-2022/sputnik",children:"here"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"3-submit-a-consumerchainaddition-governance-proposal-to-the-provider",children:"3. Submit a ConsumerChainAddition Governance Proposal to the provider"}),"\n",(0,s.jsxs)(n.p,{children:["Before you submit a ",(0,s.jsx)(n.code,{children:"ConsumerChainAddition"})," proposal, please provide a ",(0,s.jsx)(n.code,{children:"spawn_time"})," that is ",(0,s.jsx)(n.strong,{children:"before"})," the ",(0,s.jsx)(n.code,{children:"upgrade_height"})," of the upgrade that will introduce the ",(0,s.jsx)(n.code,{children:"ccv module"})," to your chain."]}),"\n",(0,s.jsx)(n.admonition,{type:"danger",children:(0,s.jsxs)(n.p,{children:["If the ",(0,s.jsx)(n.code,{children:"spawn_time"})," happens after your ",(0,s.jsx)(n.code,{children:"upgrade_height"})," the provider will not be able to communicate the new validator set to be used after the changeover."]})}),"\n",(0,s.jsxs)(n.p,{children:["Additionally, reach out to the community via the ",(0,s.jsx)(n.a,{href:"https://forum.cosmos.network/",children:"forum"})," to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers."]}),"\n",(0,s.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","determine your chain's spawn time"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","determine consumer chain parameters to be put in the proposal"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","take note to include a link to your onboarding repository"]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"Example of a consumer chain addition proposal."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-js",children:'// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain or add a standalone chain.\n// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.\n// It is recommended that spawn time occurs after the proposal end time and that it is scheduled to happen before the standalone chain upgrade\n// that sill introduce the ccv module.\n{\n // Title of the proposal\n "title": "Changeover Standalone chain",\n // Description of the proposal\n // format the text as a .md file and include the file in your onboarding repository\n "description": ".md description of your chain and all other relevant information",\n // Proposed chain-id of the new consumer chain.\n // Must be unique from all other consumer chain ids of the executing provider chain.\n "chain_id": "standalone-1",\n // Initial height of new consumer chain.\n // For a completely new chain, this will be {0,1}.\n "initial_height" : {\n // must correspond to current revision number of standalone chain\n // e.g. standalone-1 => "revision_number": 1\n "revision_number": 1,\n\n // must correspond to a height that is at least 1 block after the upgrade\n // that will add the `consumer` module to the standalone chain\n // e.g. "upgrade_height": 100 => "revision_height": 101\n "revision_number": 1,\n },\n // Hash of the consumer chain genesis state without the consumer CCV module genesis params.\n // => not relevant for changeover procedure\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n // Hash of the consumer chain binary that should be run by validators on standalone chain upgrade\n // => not relevant for changeover procedure as it may become stale\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n // Unbonding period for the consumer chain.\n // It should should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n // IBC transfer packets will timeout after this interval elapses.\n "transfer_timeout_period": 1800000000000,\n // The fraction of tokens allocated to the consumer redistribution address during distribution events.\n // The fraction is a string representing a decimal number. For example "0.75" would represent 75%.\n // The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.\n "consumer_redistribution_fraction": "0.75",\n // BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.\n // eg. send rewards to the provider every 1000 blocks\n "blocks_per_distribution_transmission": 1000,\n // The number of historical info entries to persist in store.\n // This param is a part of the cosmos sdk staking module. In the case of\n // a ccv enabled consumer chain, the ccv module acts as the staking module.\n "historical_entries": 10000,\n // The ID of a token transfer channel used for the Reward Distribution\n\t// sub-protocol. If DistributionTransmissionChannel == "", a new transfer\n\t// channel is created on top of the same connection as the CCV channel.\n\t// Note that transfer_channel_id is the ID of the channel end on the consumer chain.\n // it is most relevant for chains performing a standalone to consumer changeover\n // in order to maintain the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123" // NOTE: use existing transfer channel if available\n}\n'})}),"\n",(0,s.jsx)(n.h2,{id:"3-submit-an-upgrade-proposal--prepare-for-changeover",children:"3. Submit an Upgrade Proposal & Prepare for Changeover"}),"\n",(0,s.jsxs)(n.p,{children:["This proposal should add the ccv ",(0,s.jsx)(n.code,{children:"consumer"})," module to your chain."]}),"\n",(0,s.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","proposal ",(0,s.jsx)(n.code,{children:"upgrade_height"})," must happen after ",(0,s.jsx)(n.code,{children:"spawn_time"})," in the ",(0,s.jsx)(n.code,{children:"ConsumerAdditionProposal"})]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","advise validators about the exact procedure for your chain and point them to your onboarding repository"]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"4-upgrade-time-",children:"4. Upgrade time \ud83d\ude80"}),"\n",(0,s.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","after ",(0,s.jsx)(n.code,{children:"spawn_time"}),", request ",(0,s.jsx)(n.code,{children:"ConsumerGenesis"})," from the ",(0,s.jsx)(n.code,{children:"provider"})," and place it in ",(0,s.jsx)(n.code,{children:"<CURRENT_USER_HOME_DIR>/.sovereign/config/genesis.json"})]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","upgrade the binary to the one listed in your ",(0,s.jsx)(n.code,{children:"UpgradeProposal"})]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:['The chain starts after at least 66.67% of standalone voting power comes online. The consumer chain is considered interchain secured once the "old" validator set signs a couple of blocks and transfers control to the ',(0,s.jsx)(n.code,{children:"provider"})," validator set."]}),"\n",(0,s.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","provide a repo with onboarding instructions for validators (it should already be listed in the proposal)"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","genesis.json after ",(0,s.jsx)(n.code,{children:"spawn_time"})," obtained from ",(0,s.jsx)(n.code,{children:"provider"})," (MUST contain the initial validator set)"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>r,a:()=>a});var s=i(7294);const t={},o=s.createContext(t);function a(e){const n=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:a(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/287de311.83f8008b.js b/assets/js/287de311.83f8008b.js new file mode 100644 index 0000000000..2ae7caafa1 --- /dev/null +++ b/assets/js/287de311.83f8008b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7184],{3879:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>l,frontMatter:()=>a,metadata:()=>o,toc:()=>h});var s=i(5893),t=i(1151);const a={sidebar_position:1},r="Overview",o={id:"validators/overview",title:"Overview",description:"We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.",source:"@site/versioned_docs/version-v4.2.0-docs/validators/overview.md",sourceDirName:"validators",slug:"/validators/overview",permalink:"/interchain-security/v4.2.0/validators/overview",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Consumer Genesis Transformation",permalink:"/interchain-security/v4.2.0/consumer-development/consumer-genesis-transformation"},next:{title:"Joining Interchain Security testnet",permalink:"/interchain-security/v4.2.0/validators/joining-testnet"}},c={},h=[{value:"Startup sequence overview",id:"startup-sequence-overview",level:2},{value:"1. Consumer Chain init + 2. Genesis generation",id:"1-consumer-chain-init--2-genesis-generation",level:3},{value:"3. Submit Proposal",id:"3-submit-proposal",level:3},{value:"4. CCV Genesis state generation",id:"4-ccv-genesis-state-generation",level:3},{value:"5. Updating the genesis file",id:"5-updating-the-genesis-file",level:3},{value:"6. Chain start",id:"6-chain-start",level:3},{value:"7. Creating IBC connections",id:"7-creating-ibc-connections",level:3},{value:"Downtime Infractions",id:"downtime-infractions",level:2},{value:"Double-signing Infractions",id:"double-signing-infractions",level:2},{value:"Key assignment",id:"key-assignment",level:2},{value:"References:",id:"references",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"overview",children:"Overview"}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["We advise that you join the ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/testnets/tree/master/interchain-security",children:"Replicated Security testnet"})," to gain hands-on experience with running consumer chains."]})}),"\n",(0,s.jsx)(n.p,{children:"At present, replicated security requires all validators of the provider chain (ie. Cosmos Hub) to run validator nodes for all governance-approved consumer chains."}),"\n",(0,s.jsxs)(n.p,{children:["Once a ",(0,s.jsx)(n.code,{children:"ConsumerAdditionProposal"})," passes, validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains."]}),"\n",(0,s.jsx)(n.p,{children:"Provider chain and consumer chains represent standalone chains that only share the validator set ie. the same validator operators are tasked with running all chains."}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsx)(n.p,{children:"To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 180 validators for Cosmos Hub)."})}),"\n",(0,s.jsx)(n.h2,{id:"startup-sequence-overview",children:"Startup sequence overview"}),"\n",(0,s.jsxs)(n.p,{children:["Consumer chains cannot start and be secured by the validator set of the provider unless a ",(0,s.jsx)(n.code,{children:"ConsumerAdditionProposal"})," is passed.\nEach proposal contains defines a ",(0,s.jsx)(n.code,{children:"spawn_time"})," - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider."]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["Validators are required to run consumer chain binaries only after ",(0,s.jsx)(n.code,{children:"spawn_time"})," has passed."]})}),"\n",(0,s.jsx)(n.p,{children:"Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains."}),"\n",(0,s.jsxs)(n.p,{children:["The image below illustrates the startup sequence\n",(0,s.jsx)(n.img,{alt:"startup",src:i(9558).Z+"",width:"942",height:"632"})]}),"\n",(0,s.jsx)(n.h3,{id:"1-consumer-chain-init--2-genesis-generation",children:"1. Consumer Chain init + 2. Genesis generation"}),"\n",(0,s.jsxs)(n.p,{children:["Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ",(0,s.jsx)(n.code,{children:"ConsumerAdditionProposal"})]}),"\n",(0,s.jsx)(n.h3,{id:"3-submit-proposal",children:"3. Submit Proposal"}),"\n",(0,s.jsxs)(n.p,{children:["Consumer chain team (or their advocates) submits a ",(0,s.jsx)(n.code,{children:"ConsumerAdditionProposal"}),".\nThe most important parameters for validators are:"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"spawn_time"})," - the time after which the consumer chain must be started"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"genesis_hash"})," - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and ",(0,s.jsx)(n.code,{children:"spawn_time"})," is reached"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"binary_hash"})," - hash of the consumer chain binary used to validate the software builds"]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"4-ccv-genesis-state-generation",children:"4. CCV Genesis state generation"}),"\n",(0,s.jsxs)(n.p,{children:["After reaching ",(0,s.jsx)(n.code,{children:"spawn_time"})," the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain ",(0,s.jsx)(n.code,{children:"genesis.json"}),". The CCV validator set consists of the validator set on the provider at ",(0,s.jsx)(n.code,{children:"spawn_time"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"The state can be queried on the provider chain (in this case the Cosmos Hub):"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:" gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This is used by the launch coordinator to create the final ",(0,s.jsx)(n.code,{children:"genesis.json"})," that will be distributed to validators in step 5."]}),"\n",(0,s.jsx)(n.h3,{id:"5-updating-the-genesis-file",children:"5. Updating the genesis file"}),"\n",(0,s.jsxs)(n.p,{children:["Upon reaching the ",(0,s.jsx)(n.code,{children:"spawn_time"})," the initial validator set state will become available on the provider chain. The initial validator set is included in the ",(0,s.jsx)(n.strong,{children:"final genesis.json"})," of the consumer chain."]}),"\n",(0,s.jsx)(n.h3,{id:"6-chain-start",children:"6. Chain start"}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsx)(n.p,{children:"The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences."})}),"\n",(0,s.jsxs)(n.p,{children:["The new ",(0,s.jsx)(n.code,{children:"genesis.json"})," containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided ",(0,s.jsx)(n.code,{children:"genesis.json"})," to start their consumer chain node."]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["Please pay attention to any onboarding repositories provided by the consumer chain teams.\nRecommendations are available in ",(0,s.jsx)(n.a,{href:"/interchain-security/v4.2.0/consumer-development/onboarding",children:"Consumer Onboarding Checklist"}),".\nAnother comprehensive guide is available in the ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/CONSUMER_LAUNCH_GUIDE.md",children:"Interchain Security testnet repo"}),"."]})}),"\n",(0,s.jsx)(n.h3,{id:"7-creating-ibc-connections",children:"7. Creating IBC connections"}),"\n",(0,s.jsx)(n.p,{children:"Finally, to fully establish interchain security an IBC relayer is used to establish connections and create the required channels."}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsx)(n.p,{children:"The relayer can establish the connection only after the consumer chain starts producing blocks."})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> \nhermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1\nhermes start\n"})}),"\n",(0,s.jsx)(n.h2,{id:"downtime-infractions",children:"Downtime Infractions"}),"\n",(0,s.jsxs)(n.p,{children:["At present, the consumer chain can report evidence about downtime infractions to the provider chain. The ",(0,s.jsx)(n.code,{children:"min_signed_per_window"})," and ",(0,s.jsx)(n.code,{children:"signed_blocks_window"})," can be different on each consumer chain and are subject to changes via consumer chain governance."]}),"\n",(0,s.jsxs)(n.admonition,{type:"info",children:[(0,s.jsx)(n.p,{children:"Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains."}),(0,s.jsxs)(n.p,{children:["To unjail, the validator must wait for the jailing period to elapse on the provider chain and ",(0,s.jsx)(n.a,{href:"https://hub.cosmos.network/validators/validator-setup#unjail-validator",children:"submit an unjail transaction"})," on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains."]}),(0,s.jsxs)(n.p,{children:["More information is available in ",(0,s.jsx)(n.a,{href:"/interchain-security/v4.2.0/features/slashing#downtime-infractions",children:"Downtime Slashing documentation"})]})]}),"\n",(0,s.jsx)(n.h2,{id:"double-signing-infractions",children:"Double-signing Infractions"}),"\n",(0,s.jsxs)(n.p,{children:["To learn more about equivocation handling in interchain security check out the ",(0,s.jsx)(n.a,{href:"/interchain-security/v4.2.0/features/slashing",children:"Slashing"})," documentation section."]}),"\n",(0,s.jsx)(n.h2,{id:"key-assignment",children:"Key assignment"}),"\n",(0,s.jsx)(n.p,{children:"Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use."}),"\n",(0,s.jsxs)(n.p,{children:["For more information check out the ",(0,s.jsx)(n.a,{href:"/interchain-security/v4.2.0/features/key-assignment",children:"Key assignment overview and guide"})]}),"\n",(0,s.jsx)(n.h2,{id:"references",children:"References:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://hub.cosmos.network/validators/validator-faq",children:"Cosmos Hub Validators FAQ"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://hub.cosmos.network/validators/validator-setup",children:"Cosmos Hub Running a validator"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/CONSUMER_LAUNCH_GUIDE.md#chain-launch",children:"Startup Sequence"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://hub.cosmos.network/validators/validator-setup#unjail-validator",children:"Submit Unjailing Transaction"})}),"\n"]})]})}function l(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},9558:(e,n,i)=>{i.d(n,{Z:()=>s});const s=i.p+"assets/images/hypha-consumer-start-process-2141109f76c584706dd994d7965fd692.svg"},1151:(e,n,i)=>{i.d(n,{Z:()=>o,a:()=>r});var s=i(7294);const t={},a=s.createContext(t);function r(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:r(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/2a9fa04d.fa9a65c7.js b/assets/js/2a9fa04d.fa9a65c7.js new file mode 100644 index 0000000000..d88af73ae4 --- /dev/null +++ b/assets/js/2a9fa04d.fa9a65c7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3670],{8328:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>o,toc:()=>c});var i=n(5893),s=n(1151);const r={sidebar_position:7,title:"Throttle with retries"},a=void 0,o={id:"adrs/adr-008-throttle-retries",title:"Throttle with retries",description:"ADR 008: Throttle with retries",source:"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-008-throttle-retries.md",sourceDirName:"adrs",slug:"/adrs/adr-008-throttle-retries",permalink:"/interchain-security/v4.2.0/adrs/adr-008-throttle-retries",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:7,frontMatter:{sidebar_position:7,title:"Throttle with retries"},sidebar:"tutorialSidebar",previous:{title:"Cryptographic verification of equivocation evidence",permalink:"/interchain-security/v4.2.0/adrs/adr-005-cryptographic-equivocation-verification"},next:{title:"Soft Opt-Out",permalink:"/interchain-security/v4.2.0/adrs/adr-009-soft-opt-out"}},d={},c=[{value:"ADR 008: Throttle with retries",id:"adr-008-throttle-with-retries",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consumer changes",id:"consumer-changes",level:3},{value:"Consumer pending packets storage optimization",id:"consumer-pending-packets-storage-optimization",level:4},{value:"Provider changes",id:"provider-changes",level:3},{value:"Handling <code>VSCMaturedPackets</code> immediately",id:"handling-vscmaturedpackets-immediately",level:4},{value:"Why the provider can handle VSCMatured packets immediately",id:"why-the-provider-can-handle-vscmatured-packets-immediately",level:4},{value:"Splitting of PRs and Upgrade Order",id:"splitting-of-prs-and-upgrade-order",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function l(e){const t={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h2,{id:"adr-008-throttle-with-retries",children:"ADR 008: Throttle with retries"}),"\n",(0,i.jsx)(t.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"6/9/23: Initial draft"}),"\n",(0,i.jsx)(t.li,{children:"6/22/23: added note on consumer pending packets storage optimization"}),"\n",(0,i.jsx)(t.li,{children:"7/14/23: Added note on upgrade order"}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(t.p,{children:"Accepted"}),"\n",(0,i.jsx)(t.h2,{id:"context",children:"Context"}),"\n",(0,i.jsxs)(t.p,{children:["For context on why the throttling mechanism exists, see ",(0,i.jsx)(t.a,{href:"/interchain-security/v4.2.0/adrs/adr-002-throttle",children:"ADR 002"}),"."]}),"\n",(0,i.jsxs)(t.p,{children:["Note the terms slash throttling and jail throttling are synonymous, since in replicated security a ",(0,i.jsx)(t.code,{children:"SlashPacket"})," simply jails a validator for downtime infractions."]}),"\n",(0,i.jsxs)(t.p,{children:["Currently the throttling mechanism is designed so that provider logic (slash meter, etc.) dictates how many ",(0,i.jsx)(t.code,{children:"SlashPackets"})," can be handled over time.\nThrottled ",(0,i.jsx)(t.code,{children:"SlashPackets"})," are persisted on the provider, leading to multiple possible issues. Namely:"]}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:["If ",(0,i.jsx)(t.code,{children:"SlashPackets"})," or ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," are actually throttled/queued on the provider, state can grow and potentially lead to a DoS attack.\nWe have short term solutions around this, but overall they come with their own weaknesses.\nSee ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/issues/594",children:"#594"}),"."]}),"\n",(0,i.jsxs)(t.li,{children:["If a jailing attack described in ",(0,i.jsx)(t.a,{href:"/interchain-security/v4.2.0/adrs/adr-002-throttle",children:"ADR 002"})," were actually to be carried out with the current throttling design, we'd likely have to halt the provider, and perform an emergency upgrade and/or migration to clear the queues of ",(0,i.jsx)(t.code,{children:"SlashPackets"})," that were deemed to be malicious.\nAlternatively, validators would just have to ",(0,i.jsx)(t.em,{children:"tough it out"})," and wait for the queues to clear, during which all/most validators would be jailed.\nRight after being jailed, validators would have to unjail themselves promptly to ensure safety.\nThe coordination required to maintain safety in such a scenario is not ideal."]}),"\n"]}),"\n",(0,i.jsx)(t.p,{children:"As a solution, we can improve the throttling mechanism to instead queue/persist relevant data on each consumer, and have consumers retry slash requests as needed."}),"\n",(0,i.jsx)(t.h2,{id:"decision",children:"Decision"}),"\n",(0,i.jsx)(t.h3,{id:"consumer-changes",children:"Consumer changes"}),"\n",(0,i.jsxs)(t.p,{children:["Note the consumer already queues up both ",(0,i.jsx)(t.code,{children:"SlashPackets"})," and ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," via ",(0,i.jsx)(t.code,{children:"AppendPendingPacket"}),".\nThose packets are dequeued in every ",(0,i.jsx)(t.code,{children:"EndBlock"})," in ",(0,i.jsx)(t.code,{children:"SendPackets"})," and sent to the provider."]}),"\n",(0,i.jsxs)(t.p,{children:["Instead, we will now introduce the following logic on ",(0,i.jsx)(t.code,{children:"EndBlock"}),":"]}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:["Slash packets will always be sent to the provider once they're at the head of the queue.\nHowever, once sent, the consumer will not send any subsequent ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," from the queue until the provider responds with an acknowledgement that the sent ",(0,i.jsx)(t.code,{children:"SlashPacket"})," has been handled, i.e., validator was jailed.\nThat is, ",(0,i.jsx)(t.code,{children:"SlashPackets"})," block the sending of subsequent ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," in the consumer queue."]}),"\n",(0,i.jsxs)(t.li,{children:["If two ",(0,i.jsx)(t.code,{children:"SlashPackets"})," are at the head of the queue, the consumer will send the first ",(0,i.jsx)(t.code,{children:"SlashPacket"}),", and then wait for a success acknowledgement from the provider before sending the second ",(0,i.jsx)(t.code,{children:"SlashPacket"}),".\nThis seems like it'd simplify implementation."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," at the head of the queue (i.e., NOT following a ",(0,i.jsx)(t.code,{children:"SlashPacket"}),") can be sent immediately, and do not block any other packets in the queue, since the provider always handles them immediately."]}),"\n"]}),"\n",(0,i.jsxs)(t.p,{children:["To prevent the provider from having to keep track of what ",(0,i.jsx)(t.code,{children:"SlashPackets"})," have been rejected, the consumer will have to retry the sending of ",(0,i.jsx)(t.code,{children:"SlashPackets"})," over some period of time.\nThis can be achieved with an on-chain consumer param, i.e., ",(0,i.jsx)(t.code,{children:"RetryDelayPeriod"}),".\nTo reduce the amount of redundant re-sends, we recommend setting ",(0,i.jsx)(t.code,{children:"RetryDelayPeriod ~ SlashMeterReplenishmentPeriod"}),", i.e., waiting for the provider slash meter to be replenished before resending the rejected ",(0,i.jsx)(t.code,{children:"SlashPacket"}),"."]}),"\n",(0,i.jsx)(t.p,{children:"Note to prevent weird edge case behavior, a retry would not be attempted until either a success or failure acknowledgement has been received from the provider."}),"\n",(0,i.jsxs)(t.p,{children:["With the behavior described, we maintain very similar behavior to the previous throttling mechanism regarding the timing that ",(0,i.jsx)(t.code,{children:"SlashPackets"})," and ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," are handled on the provider.\nObviously the queueing and blocking logic is moved, and the two chains would have to send more messages between one another (only in the case the throttling mechanism is triggered)."]}),"\n",(0,i.jsxs)(t.p,{children:["In the normal case, when no or a few ",(0,i.jsx)(t.code,{children:"SlashPackets"})," are being sent, the ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," will not be delayed, and hence unbonding will not be delayed."]}),"\n",(0,i.jsxs)(t.p,{children:["For the implementation of this design, see ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/fec3eccad59416cbdb6844e279f59e3f81242888/x/ccv/consumer/keeper/throttle_retry.go",children:"throttle_retry.go"}),"."]}),"\n",(0,i.jsx)(t.h4,{id:"consumer-pending-packets-storage-optimization",children:"Consumer pending packets storage optimization"}),"\n",(0,i.jsx)(t.p,{children:"In addition to the mentioned consumer changes, an optimization will need to be made to the consumer's pending packets storage to properly implement the feature from this ADR."}),"\n",(0,i.jsxs)(t.p,{children:['The consumer ccv module previously queued "pending packets" to be sent in each ',(0,i.jsx)(t.code,{children:"EndBlock"})," in ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/3bc4e7135066d848aac60b0787364c07157fd36d/x/ccv/consumer/keeper/relay.go#L178",children:"SendPackets"}),".\nThese packets are queued in state with a protobuf list of ",(0,i.jsx)(t.code,{children:"ConsumerPacketData"}),".\nFor a single append operation, the entire list is deserialized, then a packet is appended to that list, and the list is serialized again.\nSee older version of ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/05c2dae7c6372b1252b9e97215d07c6aa7618f33/x/ccv/consumer/keeper/keeper.go#L606",children:"AppendPendingPacket"}),".\nThat is, a single append operation has O(N) complexity, where N is the size of the list."]}),"\n",(0,i.jsxs)(t.p,{children:["This poor append performance isn't a problem when the pending packets list is small.\nBut with this ADR being implemented, the pending packets list could potentially grow to the order of thousands of entries when ",(0,i.jsx)(t.code,{children:"SlashPackets"})," need to be resent."]}),"\n",(0,i.jsx)(t.p,{children:"We can improve the append time for this queue by converting it from a protobuf-esq list, to a queue implemented with sdk-esq code.\nThe idea is to persist a uint64 index that will be incremented each time you queue up a packet.\nYou can think of this as storing the tail of the queue.\nThen, packet data will be keyed by that index, making the data naturally ordered byte-wise for sdk's iterator.\nThe index will also be stored in the packet data value bytes, so that the index can later be used to delete certain packets from the queue."}),"\n",(0,i.jsx)(t.p,{children:"Two things are achieved with this approach:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"More efficient packet append/enqueue times"}),"\n",(0,i.jsx)(t.li,{children:"The ability to delete select packets from the queue (previously all packets were deleted at once)"}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"provider-changes",children:"Provider changes"}),"\n",(0,i.jsxs)(t.p,{children:["The main change needed for the provider is the removal of queuing logic for ",(0,i.jsx)(t.code,{children:"SlashPackets"})," and ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," upon being received."]}),"\n",(0,i.jsxs)(t.p,{children:["Instead, the provider will consult the slash meter to determine if a ",(0,i.jsx)(t.code,{children:"SlashPacket"})," can be handled immediately.\nIf not, the provider will return an acknowledgement message to the consumer communicating that the ",(0,i.jsx)(t.code,{children:"SlashPacket"})," could not be handled, and needs to be sent again in the future (retried)."]}),"\n",(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," will always be handled immediately upon being received by the provider."]}),"\n",(0,i.jsxs)(t.p,{children:["Note ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing",children:"spec"}),". Specifically the section on ",(0,i.jsx)(t.em,{children:"VSC Maturity and Slashing Order"}),". Previously the onus was on the provider to maintain this property via queuing packets and handling them FIFO."]}),"\n",(0,i.jsxs)(t.p,{children:["Now this property will be maintained by the consumer sending packets in the correct order, and blocking the sending of ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," as needed. Then, the ordered IBC channel will ensure that ",(0,i.jsx)(t.code,{children:"SlashPackets"})," and ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," are received in the correct order on the provider."]}),"\n",(0,i.jsxs)(t.p,{children:["The provider's main responsibility regarding throttling will now be to determine if a received ",(0,i.jsx)(t.code,{children:"SlashPacket"})," can be handled via slash meter etc., and appropriately acknowledge to the sending consumer."]}),"\n",(0,i.jsxs)(t.h4,{id:"handling-vscmaturedpackets-immediately",children:["Handling ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," immediately"]}),"\n",(0,i.jsx)(t.h4,{id:"why-the-provider-can-handle-vscmatured-packets-immediately",children:"Why the provider can handle VSCMatured packets immediately"}),"\n",(0,i.jsxs)(t.p,{children:["A ",(0,i.jsx)(t.code,{children:"VSCMaturedPacket"})," communicates to the provider that sufficient time passed on the consumer since the corresponding ",(0,i.jsx)(t.code,{children:"VSCPacket"})," has been applied (on the consumer) such that infractions committed on the consumer could have been submitted."]}),"\n",(0,i.jsxs)(t.p,{children:["If the consumer is following the queuing/blocking protocol described, then no bad behavior occurs and the ",(0,i.jsx)(t.em,{children:"VSC Maturity and Slashing Order"})," property is maintained."]}),"\n",(0,i.jsxs)(t.p,{children:["If a consumer sends ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," too leniently -- the consumer is malicious and sends duplicate ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"}),", or sends the packets sooner than the CCV protocol specifies -- then the provider needs to handle ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," immediately to prevent DOS, state bloat, or other issues.\nThe only possible negative outcome is that the malicious consumer may not be able to jail a validator who should have been jailed.\nThe malicious behavior only creates a negative outcome for the consumer chain that is being malicious."]}),"\n",(0,i.jsxs)(t.p,{children:["If a consumer blocks the sending of ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"}),", then unbonding operations on the provider will be delayed, but only until the VSC timeout period has elapsed.\nAt that time, the consumer is removed.\nAgain the malicious behavior only creates a negative outcome for the consumer chain that is being malicious."]}),"\n",(0,i.jsx)(t.h3,{id:"splitting-of-prs-and-upgrade-order",children:"Splitting of PRs and Upgrade Order"}),"\n",(0,i.jsxs)(t.p,{children:["This feature will implement consumer changes in ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/pull/1024",children:"#1024"}),"."]}),"\n",(0,i.jsxs)(t.p,{children:["\u2757",(0,i.jsx)(t.em,{children:(0,i.jsx)(t.strong,{children:"These changes should be deployed to production for all consumers before the provider changes are deployed to production."})})]}),"\n",(0,i.jsxs)(t.p,{children:["In other words, the consumer changes in ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/pull/1024",children:"#1024"}),' are compatible with the current ("v1") provider implementation of throttling that\'s running on the Cosmos Hub as of July 2023.']}),"\n",(0,i.jsxs)(t.p,{children:["Once all consumers have deployed the changes in #1024, the provider changes from ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/pull/1321",children:"#1321"})," can be deployed to production, fully enabling v2 throttling."]}),"\n",(0,i.jsx)(t.h2,{id:"consequences",children:"Consequences"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"Consumers will now have to manage their own queues, and retry logic."}),"\n",(0,i.jsx)(t.li,{children:"Consumers still aren't trustless, but the provider is now less susceptible to mismanaged or malicious consumers."}),"\n",(0,i.jsx)(t.li,{children:'Recovering from the "jailing attack" is more elegant.'}),"\n",(0,i.jsxs)(t.li,{children:["Some issues like ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/issues/1001",children:"#1001"})," will now be handled implicitly by the improved throttling mechanism."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.code,{children:"SlashPackets"})," and ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," can be handled immediately once received by the provider if the slash meter allows."]}),"\n",(0,i.jsxs)(t.li,{children:["In general, we reduce the amount of computation that happens in the provider ",(0,i.jsx)(t.code,{children:"EndBlock"}),"."]}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:['We no longer have to reason about a "global queue" and a "chain specific queue", and keeping those all in-sync.\nNow ',(0,i.jsx)(t.code,{children:"SlashPackets"})," and ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," queuing is handled on each consumer individually."]}),"\n",(0,i.jsx)(t.li,{children:"Due to the above, the throttling protocol becomes less complex overall."}),"\n",(0,i.jsx)(t.li,{children:"We no longer have to worry about throttle related DoS attack on the provider, since no queuing exists on the provider."}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"Increased number of IBC packets being relayed anytime throttling logic is triggered."}),"\n",(0,i.jsx)(t.li,{children:"Consumer complexity increases, since consumers now have manage queuing themselves, and implement packet retry logic."}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"neutral",children:"Neutral"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"Core throttling logic on the provider remains unchanged, i.e., slash meter, replenishment cycles, etc."}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"references",children:"References"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/issues/713",children:"EPIC"})," tracking the changes proposed by this ADR"]}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"/interchain-security/v4.2.0/adrs/adr-002-throttle",children:"ADR 002: Jail Throttling"})}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/issues/594",children:"#594"})}),"\n"]})]})}function h(e={}){const{wrapper:t}={...(0,s.a)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},1151:(e,t,n)=>{n.d(t,{Z:()=>o,a:()=>a});var i=n(7294);const s={},r=i.createContext(s);function a(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/2c92eef1.232084f8.js b/assets/js/2c92eef1.232084f8.js new file mode 100644 index 0000000000..2380e41429 --- /dev/null +++ b/assets/js/2c92eef1.232084f8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3158],{6386:(e,i,t)=>{t.r(i),t.d(i,{assets:()=>s,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>a,toc:()=>p});var n=t(5893),c=t(1151);const o={sidebar_position:4},r="Technical Specification",a={id:"introduction/technical-specification",title:"Technical Specification",description:"For a technical deep dive into the replicated security protocol, see the specification.",source:"@site/versioned_docs/version-v5.0.0/introduction/technical-specification.md",sourceDirName:"introduction",slug:"/introduction/technical-specification",permalink:"/interchain-security/v5.0.0/introduction/technical-specification",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Parameters",permalink:"/interchain-security/v5.0.0/introduction/params"},next:{title:"Upgrading to ICS v5.0.0",permalink:"/interchain-security/v5.0.0/upgrading/migrate_v4_v5"}},s={},p=[];function d(e){const i={a:"a",h1:"h1",p:"p",...(0,c.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(i.h1,{id:"technical-specification",children:"Technical Specification"}),"\n",(0,n.jsxs)(i.p,{children:["For a technical deep dive into the replicated security protocol, see the ",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/README.md",children:"specification"}),"."]})]})}function u(e={}){const{wrapper:i}={...(0,c.a)(),...e.components};return i?(0,n.jsx)(i,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},1151:(e,i,t)=>{t.d(i,{Z:()=>a,a:()=>r});var n=t(7294);const c={},o=n.createContext(c);function r(e){const i=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function a(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(c):e.components||c:r(e.components),n.createElement(o.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/2ed06975.0d9c3801.js b/assets/js/2ed06975.0d9c3801.js new file mode 100644 index 0000000000..018f0b9a2f --- /dev/null +++ b/assets/js/2ed06975.0d9c3801.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1038],{439:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>o,contentTitle:()=>c,default:()=>l,frontMatter:()=>s,metadata:()=>a,toc:()=>d});var r=i(5893),t=i(1151);const s={sidebar_position:1,title:"ADRs"},c="Architecture Decision Records (ADR)",a={id:"adrs/intro",title:"ADRs",description:"This is a location to record all high-level architecture decisions in the Interchain Security project.",source:"@site/versioned_docs/version-v5.0.0/adrs/intro.md",sourceDirName:"adrs",slug:"/adrs/intro",permalink:"/interchain-security/v5.0.0/adrs/intro",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:1,frontMatter:{sidebar_position:1,title:"ADRs"},sidebar:"tutorialSidebar",previous:{title:"Frequently Asked Questions",permalink:"/interchain-security/v5.0.0/faq"},next:{title:"ADR Template",permalink:"/interchain-security/v5.0.0/adrs/adr-004-denom-dos-fixes"}},o={},d=[{value:"Table of Contents",id:"table-of-contents",level:2},{value:"Accepted",id:"accepted",level:3},{value:"Proposed",id:"proposed",level:3},{value:"Rejected",id:"rejected",level:3},{value:"Deprecated",id:"deprecated",level:3}];function h(e){const n={a:"a",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,t.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"architecture-decision-records-adr",children:"Architecture Decision Records (ADR)"}),"\n",(0,r.jsx)(n.p,{children:"This is a location to record all high-level architecture decisions in the Interchain Security project."}),"\n",(0,r.jsxs)(n.p,{children:["You can read more about the ADR concept in this ",(0,r.jsx)(n.a,{href:"https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0#.78xhdix6t",children:"blog post"}),"."]}),"\n",(0,r.jsx)(n.p,{children:"An ADR should provide:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Context on the relevant goals and the current state"}),"\n",(0,r.jsx)(n.li,{children:"Proposed changes to achieve the goals"}),"\n",(0,r.jsx)(n.li,{children:"Summary of pros and cons"}),"\n",(0,r.jsx)(n.li,{children:"References"}),"\n",(0,r.jsx)(n.li,{children:"Changelog"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and\njustification for a change in architecture, or for the architecture of something\nnew. The spec is much more compressed and streamlined summary of everything as\nit is or should be."}),"\n",(0,r.jsx)(n.p,{children:"If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match."}),"\n",(0,r.jsx)(n.p,{children:"Note the context/background should be written in the present tense."}),"\n",(0,r.jsxs)(n.p,{children:["To suggest an ADR, please make use of the ",(0,r.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-template",children:"ADR template"})," provided."]}),"\n",(0,r.jsx)(n.h2,{id:"table-of-contents",children:"Table of Contents"}),"\n",(0,r.jsx)(n.h3,{id:"accepted",children:"Accepted"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-001-key-assignment",children:"ADR 001: Key Assignment"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-002-throttle",children:"ADR 002: Jail Throttling"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-004-denom-dos-fixes",children:"ADR 004: Denom DOS fixes"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-005-cryptographic-equivocation-verification",children:"ADR 005: Cryptographic verification of equivocation evidence"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-008-throttle-retries",children:"ADR 008: Throttle with retries"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-009-soft-opt-out",children:"ADR 009: Soft Opt-Out"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-010-standalone-changeover",children:"ADR 010: Standalone to Consumer Changeover"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-013-equivocation-slashing",children:"ADR 013: Slashing on the provider for consumer equivocation"})}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"proposed",children:"Proposed"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-011-improving-test-confidence",children:"ADR 011: Improving testing and increasing confidence"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-014-epochs",children:"ADR 014: Epochs"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-015-partial-set-security",children:"ADR 015: Partial Set Security"})}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"rejected",children:"Rejected"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-007-pause-unbonding-on-eqv-prop",children:"ADR 007: Pause validator unbonding during equivocation proposal"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-012-separate-releasing",children:"ADR 012: Separate Releasing"})}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"deprecated",children:"Deprecated"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-003-equivocation-gov-proposal",children:"ADR 003: Equivocation governance proposal"})}),"\n"]})]})}function l(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>a,a:()=>c});var r=i(7294);const t={},s=r.createContext(t);function c(e){const n=r.useContext(s);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:c(e.components),r.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/3672b5b7.7d4ba869.js b/assets/js/3672b5b7.7d4ba869.js new file mode 100644 index 0000000000..f504805255 --- /dev/null +++ b/assets/js/3672b5b7.7d4ba869.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[320],{9873:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>c,contentTitle:()=>t,default:()=>h,frontMatter:()=>o,metadata:()=>d,toc:()=>a});var r=n(5893),s=n(1151);const o={sidebar_position:3},t="Interchain Security Parameters",d={id:"introduction/params",title:"Interchain Security Parameters",description:"The parameters necessary for Interchain Security (ICS) are defined in",source:"@site/docs/introduction/params.md",sourceDirName:"introduction",slug:"/introduction/params",permalink:"/interchain-security/introduction/params",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Terminology",permalink:"/interchain-security/introduction/terminology"},next:{title:"Technical Specification",permalink:"/interchain-security/introduction/technical-specification"}},c={},a=[{value:"Time-Based Parameters",id:"time-based-parameters",level:2},{value:"ProviderUnbondingPeriod",id:"providerunbondingperiod",level:3},{value:"ConsumerUnbondingPeriod",id:"consumerunbondingperiod",level:3},{value:"TrustingPeriodFraction",id:"trustingperiodfraction",level:3},{value:"CCVTimeoutPeriod",id:"ccvtimeoutperiod",level:3},{value:"InitTimeoutPeriod",id:"inittimeoutperiod",level:3},{value:"VscTimeoutPeriod",id:"vsctimeoutperiod",level:3},{value:"BlocksPerDistributionTransmission",id:"blocksperdistributiontransmission",level:3},{value:"TransferPeriodTimeout",id:"transferperiodtimeout",level:3},{value:"Reward Distribution Parameters",id:"reward-distribution-parameters",level:2},{value:"ConsumerRedistributionFraction",id:"consumerredistributionfraction",level:3},{value:"BlocksPerDistributionTransmission",id:"blocksperdistributiontransmission-1",level:3},{value:"TransferTimeoutPeriod",id:"transfertimeoutperiod",level:3},{value:"DistributionTransmissionChannel",id:"distributiontransmissionchannel",level:3},{value:"ProviderFeePoolAddrStr",id:"providerfeepooladdrstr",level:3},{value:"Slash Throttle Parameters",id:"slash-throttle-parameters",level:2},{value:"SlashMeterReplenishPeriod",id:"slashmeterreplenishperiod",level:3},{value:"SlashMeterReplenishFraction",id:"slashmeterreplenishfraction",level:3},{value:"MaxThrottledPackets",id:"maxthrottledpackets",level:3},{value:"RetryDelayPeriod",id:"retrydelayperiod",level:3},{value:"Epoch Parameters",id:"epoch-parameters",level:2},{value:"BlocksPerEpoch",id:"blocksperepoch",level:3}];function l(e){const i={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(i.h1,{id:"interchain-security-parameters",children:"Interchain Security Parameters"}),"\n",(0,r.jsx)(i.p,{children:"The parameters necessary for Interchain Security (ICS) are defined in"}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:["the ",(0,r.jsx)(i.code,{children:"Params"})," structure in ",(0,r.jsx)(i.code,{children:"proto/interchain_security/ccv/provider/v1/provider.proto"})," for the provider;"]}),"\n",(0,r.jsxs)(i.li,{children:["the ",(0,r.jsx)(i.code,{children:"Params"})," structure in ",(0,r.jsx)(i.code,{children:"proto/interchain_security/ccv/consumer/v1/consumer.proto"})," for the consumer."]}),"\n"]}),"\n",(0,r.jsx)(i.h2,{id:"time-based-parameters",children:"Time-Based Parameters"}),"\n",(0,r.jsx)(i.p,{children:"ICS relies on the following time-based parameters."}),"\n",(0,r.jsx)(i.h3,{id:"providerunbondingperiod",children:"ProviderUnbondingPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"ProviderUnbondingPeriod"})," is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance."]}),"\n",(0,r.jsx)(i.h3,{id:"consumerunbondingperiod",children:"ConsumerUnbondingPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"ConsumerUnbondingPeriod"})," is the unbonding period on the consumer chain."]}),"\n",(0,r.jsxs)(i.admonition,{type:"info",children:[(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"ConsumerUnbondingPeriod"})," is set via the ",(0,r.jsx)(i.code,{children:"ConsumerAdditionProposal"})," governance proposal to add a new consumer chain.\nIt is recommended that every consumer chain set and unbonding period shorter than ",(0,r.jsx)(i.code,{children:"ProviderUnbondingPeriod"})]}),(0,r.jsx)("br",{}),(0,r.jsx)(i.p,{children:"Example:"}),(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{children:"ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day\n"})})]}),"\n",(0,r.jsx)(i.p,{children:"Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer."}),"\n",(0,r.jsx)(i.h3,{id:"trustingperiodfraction",children:"TrustingPeriodFraction"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"TrustingPeriodFraction"})," is used to calculate the ",(0,r.jsx)(i.code,{children:"TrustingPeriod"})," of created IBC clients on both provider and consumer chains."]}),"\n",(0,r.jsxs)(i.p,{children:["Setting ",(0,r.jsx)(i.code,{children:"TrustingPeriodFraction"})," to ",(0,r.jsx)(i.code,{children:"0.5"})," would result in the following:"]}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{children:"TrustingPeriodFraction = 0.5\nProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5\nConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5\n"})}),"\n",(0,r.jsxs)(i.p,{children:["Note that a light clients must be updated within the ",(0,r.jsx)(i.code,{children:"TrustingPeriod"})," in order to avoid being frozen."]}),"\n",(0,r.jsxs)(i.p,{children:["For more details, see the ",(0,r.jsx)(i.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/client/ics-007-tendermint-client/README.md",children:"IBC specification of Tendermint clients"}),"."]}),"\n",(0,r.jsx)(i.h3,{id:"ccvtimeoutperiod",children:"CCVTimeoutPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"CCVTimeoutPeriod"})," is the period used to compute the timeout timestamp when sending IBC packets."]}),"\n",(0,r.jsxs)(i.p,{children:["For more details, see the ",(0,r.jsx)(i.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/core/ics-004-channel-and-packet-semantics/README.md#sending-packets",children:"IBC specification of Channel & Packet Semantics"}),"."]}),"\n",(0,r.jsx)(i.admonition,{type:"warning",children:(0,r.jsx)(i.p,{children:"If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed."})}),"\n",(0,r.jsx)(i.p,{children:"CCVTimeoutPeriod may have different values on the provider and consumer chains."}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"CCVTimeoutPeriod"})," on the provider ",(0,r.jsx)(i.strong,{children:"must"})," be larger than ",(0,r.jsx)(i.code,{children:"ConsumerUnbondingPeriod"})]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"CCVTimeoutPeriod"})," on the consumer is initial set via the ",(0,r.jsx)(i.code,{children:"ConsumerAdditionProposal"})]}),"\n"]}),"\n",(0,r.jsx)(i.h3,{id:"inittimeoutperiod",children:"InitTimeoutPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"InitTimeoutPeriod"})," is the maximum allowed duration for CCV channel initialization to execute."]}),"\n",(0,r.jsxs)(i.p,{children:["For any consumer chain, if the CCV channel is not established within ",(0,r.jsx)(i.code,{children:"InitTimeoutPeriod"})," then the consumer chain will be removed and therefore will not be secured by the provider chain."]}),"\n",(0,r.jsxs)(i.p,{children:["The countdown starts when the ",(0,r.jsx)(i.code,{children:"spawn_time"})," specified in the ",(0,r.jsx)(i.code,{children:"ConsumerAdditionProposal"})," is reached."]}),"\n",(0,r.jsx)(i.h3,{id:"vsctimeoutperiod",children:"VscTimeoutPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"VscTimeoutPeriod"})," is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live.\nIf the ",(0,r.jsx)(i.code,{children:"VscTimeoutPeriod"})," is ever reached for a consumer chain that chain will be considered not live and removed from interchain security."]}),"\n",(0,r.jsx)(i.admonition,{type:"tip",children:(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"VscTimeoutPeriod"})," MUST be larger than the ",(0,r.jsx)(i.code,{children:"ConsumerUnbondingPeriod"}),"."]})}),"\n",(0,r.jsx)(i.h3,{id:"blocksperdistributiontransmission",children:"BlocksPerDistributionTransmission"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"BlocksPerDistributionTransmission"})," is the number of blocks between rewards transfers from the consumer to the provider."]}),"\n",(0,r.jsx)(i.h3,{id:"transferperiodtimeout",children:"TransferPeriodTimeout"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"TransferPeriodTimeout"})," is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider."]}),"\n",(0,r.jsxs)(i.p,{children:["If this timeout expires, then the transfer is attempted again after ",(0,r.jsx)(i.code,{children:"BlocksPerDistributionTransmission"})," blocks."]}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"TransferPeriodTimeout"})," on the consumer is initial set via the ",(0,r.jsx)(i.code,{children:"ConsumerAdditionProposal"})," gov proposal to add the consumer"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"TransferPeriodTimeout"})," should be smaller than ",(0,r.jsx)(i.code,{children:"BlocksPerDistributionTransmission x avg_block_time"})]}),"\n"]}),"\n",(0,r.jsx)(i.h2,{id:"reward-distribution-parameters",children:"Reward Distribution Parameters"}),"\n",(0,r.jsx)(i.admonition,{type:"tip",children:(0,r.jsxs)(i.p,{children:["The following chain parameters dictate consumer chain distribution amount and frequency.\nThey are set at consumer genesis and ",(0,r.jsx)(i.code,{children:"BlocksPerDistributionTransmission"}),", ",(0,r.jsx)(i.code,{children:"ConsumerRedistributionFraction"}),"\n",(0,r.jsx)(i.code,{children:"TransferTimeoutPeriod"})," must be provided in every ",(0,r.jsx)(i.code,{children:"ConsumerChainAddition"})," proposal."]})}),"\n",(0,r.jsx)(i.h3,{id:"consumerredistributionfraction",children:"ConsumerRedistributionFraction"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"ConsumerRedistributionFraction"})," is the fraction of tokens allocated to the consumer redistribution address during distribution events. The fraction is a string representing a decimal number. For example ",(0,r.jsx)(i.code,{children:'"0.75"'})," would represent ",(0,r.jsx)(i.code,{children:"75%"}),"."]}),"\n",(0,r.jsxs)(i.admonition,{type:"tip",children:[(0,r.jsx)(i.p,{children:"Example:"}),(0,r.jsxs)(i.p,{children:["With ",(0,r.jsx)(i.code,{children:"ConsumerRedistributionFraction"})," set to ",(0,r.jsx)(i.code,{children:'"0.75"'})," the consumer chain would send ",(0,r.jsx)(i.code,{children:"75%"})," of its block rewards and accumulated fees to the consumer redistribution address, and the remaining ",(0,r.jsx)(i.code,{children:"25%"})," to the provider chain every ",(0,r.jsx)(i.code,{children:"BlocksPerDistributionTransmission"})," blocks."]})]}),"\n",(0,r.jsx)(i.h3,{id:"blocksperdistributiontransmission-1",children:"BlocksPerDistributionTransmission"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"BlocksPerDistributionTransmission"})," is the number of blocks between IBC token transfers from the consumer chain to the provider chain."]}),"\n",(0,r.jsx)(i.h3,{id:"transfertimeoutperiod",children:"TransferTimeoutPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"TransferTimeoutPeriod"})," is the timeout period for consumer chain reward distribution IBC packets."]}),"\n",(0,r.jsx)(i.h3,{id:"distributiontransmissionchannel",children:"DistributionTransmissionChannel"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"DistributionTransmissionChannel"})," is the provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."]}),"\n",(0,r.jsx)(i.h3,{id:"providerfeepooladdrstr",children:"ProviderFeePoolAddrStr"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"ProviderFeePoolAddrStr"})," is the provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."]}),"\n",(0,r.jsx)(i.h2,{id:"slash-throttle-parameters",children:"Slash Throttle Parameters"}),"\n",(0,r.jsx)(i.h3,{id:"slashmeterreplenishperiod",children:"SlashMeterReplenishPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"SlashMeterReplenishPeriod"})," exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed."]}),"\n",(0,r.jsxs)(i.p,{children:["The meter is replenished to an amount equal to the slash meter allowance for that block, or ",(0,r.jsx)(i.code,{children:"SlashMeterReplenishFraction * CurrentTotalVotingPower"}),"."]}),"\n",(0,r.jsx)(i.h3,{id:"slashmeterreplenishfraction",children:"SlashMeterReplenishFraction"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"SlashMeterReplenishFraction"})," exists on the provider as the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs."]}),"\n",(0,r.jsxs)(i.p,{children:["This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a ",(0,r.jsx)(i.code,{children:"sdk.Dec"})," when used."]}),"\n",(0,r.jsx)(i.h3,{id:"maxthrottledpackets",children:"MaxThrottledPackets"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"MaxThrottledPackets"})," exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value."]}),"\n",(0,r.jsx)(i.p,{children:"This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness."}),"\n",(0,r.jsx)(i.admonition,{type:"info",children:(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"MaxThrottledPackets"})," was deprecated in ICS versions >= v3.2.0 due to the implementation of ",(0,r.jsx)(i.a,{href:"/interchain-security/adrs/adr-008-throttle-retries",children:"ADR-008"}),"."]})}),"\n",(0,r.jsx)(i.h3,{id:"retrydelayperiod",children:"RetryDelayPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"RetryDelayPeriod"})," exists on the consumer for ",(0,r.jsx)(i.strong,{children:"ICS versions >= v3.2.0"})," (introduced by the implementation of ",(0,r.jsx)(i.a,{href:"/interchain-security/adrs/adr-008-throttle-retries",children:"ADR-008"}),") and is the period at which the consumer retries to send a ",(0,r.jsx)(i.code,{children:"SlashPacket"})," that was rejected by the provider."]}),"\n",(0,r.jsx)(i.h2,{id:"epoch-parameters",children:"Epoch Parameters"}),"\n",(0,r.jsx)(i.h3,{id:"blocksperepoch",children:"BlocksPerEpoch"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"BlocksPerEpoch"})," exists on the provider for ",(0,r.jsx)(i.strong,{children:"ICS versions >= 3.3.0"})," (introduced by the implementation of ",(0,r.jsx)(i.a,{href:"/interchain-security/adrs/adr-014-epochs",children:"ADR-014"}),")\nand corresponds to the number of blocks that constitute an epoch. This param is set to 600 by default. Assuming we need 6 seconds to\ncommit a block, the duration of an epoch corresponds to 1 hour. This means that a ",(0,r.jsx)(i.code,{children:"VSCPacket"})," would be sent to a consumer\nchain once at the end of every epoch, so once every 600 blocks. This parameter can be adjusted via a governance proposal,\nhowever careful consideration is needed so that ",(0,r.jsx)(i.code,{children:"BlocksPerEpoch"})," is not too large. A large ",(0,r.jsx)(i.code,{children:"BlocksPerEpoch"})," could lead to a delay\nof ",(0,r.jsx)(i.code,{children:"VSCPacket"}),"s and hence potentially lead to ",(0,r.jsx)(i.a,{href:"https://informal.systems/blog/learning-to-live-with-unbonding-pausing",children:"unbonding pausing"}),".\nFor setting ",(0,r.jsx)(i.code,{children:"BlocksPerEpoch"}),", we also need to consider potential slow chain upgrades that could delay the sending of a\n",(0,r.jsx)(i.code,{children:"VSCPacket"}),", as well as potential increases in the time it takes to commit a block (e.g., from 6 seconds to 30 seconds)."]})]})}function h(e={}){const{wrapper:i}={...(0,s.a)(),...e.components};return i?(0,r.jsx)(i,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},1151:(e,i,n)=>{n.d(i,{Z:()=>d,a:()=>t});var r=n(7294);const s={},o=r.createContext(s);function t(e){const i=r.useContext(o);return r.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function d(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:t(e.components),r.createElement(o.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/3ec9db48.3a34695e.js b/assets/js/3ec9db48.3a34695e.js new file mode 100644 index 0000000000..98be93d4ad --- /dev/null +++ b/assets/js/3ec9db48.3a34695e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8233],{4554:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>l,frontMatter:()=>t,metadata:()=>a,toc:()=>c});var i=r(5893),s=r(1151);const t={sidebar_position:2},o="Reward Distribution",a={id:"features/reward-distribution",title:"Reward Distribution",description:"Sending and distributing rewards from consumer chains to the provider chain is handled by the Reward Distribution sub-protocol.",source:"@site/versioned_docs/version-v4.2.0-docs/features/reward-distribution.md",sourceDirName:"features",slug:"/features/reward-distribution",permalink:"/interchain-security/v4.2.0/features/reward-distribution",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/v4.2.0/features/key-assignment"},next:{title:"ICS Provider Proposals",permalink:"/interchain-security/v4.2.0/features/proposals"}},d={},c=[{value:"Whitelisting Reward Denoms",id:"whitelisting-reward-denoms",level:2}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"reward-distribution",children:"Reward Distribution"}),"\n",(0,i.jsxs)(n.p,{children:["Sending and distributing rewards from consumer chains to the provider chain is handled by the ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md#reward-distribution",children:"Reward Distribution sub-protocol"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["Consumer chains have the option of sharing (a portion of) their block rewards (inflation tokens and fees) with the provider chain validators and delegators.\nIn replicated security, block rewards are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel.\nThis channel is created during consumer chain initialization, unless it is provided via the ",(0,i.jsx)(n.code,{children:"ConsumerAdditionProposal"})," when adding a new consumer chain.\nFor more details, see the ",(0,i.jsx)(n.a,{href:"/interchain-security/v4.2.0/introduction/params#reward-distribution-parameters",children:"reward distribution parameters"}),"."]}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["Providing an IBC transfer channel (see ",(0,i.jsx)(n.code,{children:"DistributionTransmissionChannel"}),") enables a consumer chain to re-use one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ",(0,i.jsx)(n.code,{children:"ibc denom"})," that may already be in use.\nThis is especially important for standalone chains transitioning to become consumer chains.\nFor more details, see the ",(0,i.jsx)(n.a,{href:"/interchain-security/v4.2.0/consumer-development/changeover-procedure",children:"changeover procedure"}),"."]})}),"\n",(0,i.jsx)(n.p,{children:"Reward distribution on the provider is handled by the distribution module."}),"\n",(0,i.jsx)(n.h2,{id:"whitelisting-reward-denoms",children:"Whitelisting Reward Denoms"}),"\n",(0,i.jsxs)(n.p,{children:["The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the ",(0,i.jsx)(n.code,{children:"ConsumerRewardsPool"}),".\nTo avoid spam, the provider must whitelist denoms before accepting them as ICS rewards.\nOnly whitelisted denoms are transferred from the ",(0,i.jsx)(n.code,{children:"ConsumerRewardsPool"})," to the ",(0,i.jsx)(n.code,{children:"FeePoolAddress"}),", to be distributed to delegators and validators.\nThe whitelisted denoms can be adjusted through governance by sending a ",(0,i.jsx)(n.a,{href:"/interchain-security/v4.2.0/features/proposals#changerewarddenomproposal",children:(0,i.jsx)(n.code,{children:"ChangeRewardDenomProposal"})}),"."]}),"\n",(0,i.jsx)(n.p,{children:"To query the list of whitelisted reward denoms on the Cosmos Hub, use the following command:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"> gaiad q provider registered-consumer-reward-denoms\ndenoms:\n- ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5\n- ibc/6B8A3F5C2AD51CD6171FA41A7E8C35AD594AB69226438DB94450436EA57B3A89\n- uatom\n"})}),"\n",(0,i.jsxs)(n.admonition,{type:"tip",children:[(0,i.jsxs)(n.p,{children:["Use the following command to get a human readable denom from the ",(0,i.jsx)(n.code,{children:"ibc/*"})," denom trace format:"]}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"> gaiad query ibc-transfer denom-trace ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5\ndenom_trace:\n base_denom: untrn\n path: transfer/channel-569\n"})})]})]})}function l(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},1151:(e,n,r)=>{r.d(n,{Z:()=>a,a:()=>o});var i=r(7294);const s={},t=i.createContext(s);function o(e){const n=i.useContext(t);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/3f3637cb.463b9af5.js b/assets/js/3f3637cb.463b9af5.js new file mode 100644 index 0000000000..b7f2620595 --- /dev/null +++ b/assets/js/3f3637cb.463b9af5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3596],{9529:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>d,frontMatter:()=>r,metadata:()=>s,toc:()=>h});var i=o(5893),t=o(1151);const r={sidebar_position:1},a="Overview",s={id:"introduction/overview",title:"Overview",description:"Interchain Security is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.",source:"@site/versioned_docs/version-v4.2.0-docs/introduction/overview.md",sourceDirName:"introduction",slug:"/introduction/overview",permalink:"/interchain-security/v4.2.0/introduction/overview",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Docs",permalink:"/interchain-security/v4.2.0/"},next:{title:"Terminology",permalink:"/interchain-security/v4.2.0/introduction/terminology"}},c={},h=[{value:"Why Interchain Security?",id:"why-interchain-security",level:2},{value:"Core protocol",id:"core-protocol",level:2},{value:"Downtime Slashing",id:"downtime-slashing",level:3},{value:"Tokenomics and Rewards",id:"tokenomics-and-rewards",level:3}];function l(e){const n={a:"a",admonition:"admonition",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,t.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"overview",children:"Overview"}),"\n",(0,i.jsxs)(n.admonition,{type:"info",children:[(0,i.jsx)(n.p,{children:"Interchain Security is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another."}),(0,i.jsx)("br",{}),(0,i.jsx)(n.p,{children:'Interchain Security allows anyone to launch a "consumer" blockchain using a subset, or even the entire, validator set from the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit security and decentralization from the provider.'})]}),"\n",(0,i.jsx)(n.h2,{id:"why-interchain-security",children:"Why Interchain Security?"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"The right amount of security for each application. Consumer chains can choose to inherit the whole validator set from the provider, or they can launch as an opt in chain where only a subset of the provider validators validate the consumer chain. This allows for a wide range of security tradeoffs."}),"\n",(0,i.jsx)(n.li,{children:"Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum."}),"\n",(0,i.jsx)(n.li,{children:"Projects keep majority of gas fees. Depending on configuration, these fees either go to the project\u2019s community DAO, or can be used in the protocol in other ways."}),"\n",(0,i.jsx)(n.li,{children:"No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. Validators from the provider chain validate on the consumer chain with their stake on the provider chain, earning additional rewards. For the consumer chain, this comes with the benefit of exposing their chain to the wider audience of the provider chain."}),"\n",(0,i.jsx)(n.li,{children:"Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set."}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"core-protocol",children:"Core protocol"}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["Protocol specification is available as ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md",children:"ICS-028"})," in the IBC repository."]})}),"\n",(0,i.jsx)(n.p,{children:"Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer."}),"\n",(0,i.jsx)(n.p,{children:"To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider."}),"\n",(0,i.jsx)(n.h3,{id:"downtime-slashing",children:"Downtime Slashing"}),"\n",(0,i.jsx)(n.p,{children:"If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period."}),"\n",(0,i.jsx)(n.h3,{id:"tokenomics-and-rewards",children:"Tokenomics and Rewards"}),"\n",(0,i.jsx)(n.p,{children:"Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance."})]})}function d(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},1151:(e,n,o)=>{o.d(n,{Z:()=>s,a:()=>a});var i=o(7294);const t={},r=i.createContext(t);function a(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function s(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:a(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/3f869ff5.5e0f39e2.js b/assets/js/3f869ff5.5e0f39e2.js new file mode 100644 index 0000000000..7423c370d9 --- /dev/null +++ b/assets/js/3f869ff5.5e0f39e2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4470],{4522:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>d,frontMatter:()=>o,metadata:()=>r,toc:()=>h});var n=i(5893),a=i(1151);const o={},s="Power Shaping",r={id:"features/power-shaping",title:"Power Shaping",description:"To give consumer chains more flexibility in choosing their validator set, Interchain Security offers",source:"@site/versioned_docs/version-v4.2.0-docs/features/power-shaping.md",sourceDirName:"features",slug:"/features/power-shaping",permalink:"/interchain-security/v4.2.0/features/power-shaping",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Partial Set Security",permalink:"/interchain-security/v4.2.0/features/partial-set-security"},next:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/v4.2.0/consumer-development/app-integration"}},l={},h=[{value:"Guidelines for setting power shaping parameters",id:"guidelines-for-setting-power-shaping-parameters",level:2}];function c(e){const t={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"power-shaping",children:"Power Shaping"}),"\n",(0,n.jsx)(t.p,{children:'To give consumer chains more flexibility in choosing their validator set, Interchain Security offers\nseveral "power shaping" mechanisms for consumer chains.'}),"\n",(0,n.jsx)(t.p,{children:"These are:"}),"\n",(0,n.jsxs)(t.ol,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.strong,{children:"Capping the size of the validator set"}),": The consumer chain can specify a maximum number of validators it\nwants to have in its validator set. This can be used to limit the number of validators in the set, which can\nbe useful for chains that want to have a smaller validator set for faster blocks or lower overhead."]}),"\n"]}),"\n",(0,n.jsx)(t.admonition,{type:"info",children:(0,n.jsx)(t.p,{children:"This is only applicable to Opt In chains (chains with Top N = 0)."})}),"\n",(0,n.jsxs)(t.ol,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.strong,{children:"Capping the fraction of power any single validator can have"}),": The consumer chain can specify a maximum fraction\nof the total voting power that any single validator in its validator set should have.\nThis is a security measure with the intention of making it harder for a single large validator to take over a consumer chain. This mitigates the risk of an Opt In chain with only a few validators being dominated by a validator with a large amount of stake opting in.\nFor example, setting this fraction to e.g. 33% would mean that no single validator can have more than 33% of the total voting power,\nand thus there is no single validator who would stop the chain by going offline."]}),"\n"]}),"\n",(0,n.jsx)(t.admonition,{type:"info",children:(0,n.jsx)(t.p,{children:"This is a soft cap, and the actual power of a validator can exceed this fraction if the validator set is small (e.g. there are only 3 validators and the cap is 20%)."})}),"\n",(0,n.jsx)(t.admonition,{type:"info",children:(0,n.jsx)(t.p,{children:"Rewards are distributed proportionally to validators with respect to their capped voting power on the consumer,\nnot their total voting power on the provider."})}),"\n",(0,n.jsxs)(t.ol,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.strong,{children:"Allowlist and denylist"}),": The consumer chain can specify a list of validators that are allowed or disallowed from participating in the validator set. If an allowlist is set, all validators not on the allowlist cannot validate the consumer chain. If a validator is on both lists, the denylist takes precedence, that is, they cannot validate the consumer chain. If neither list is set, all validators are able to validate the consumer chain."]}),"\n"]}),"\n",(0,n.jsx)(t.admonition,{type:"warning",children:(0,n.jsxs)(t.p,{children:["Note that if denylisting is used in a Top N consumer chain, then the chain might not be secured by N% of the total provider's\npower. For example, consider that the top validator ",(0,n.jsx)(t.code,{children:"V"})," on the provider chain has 10% of the voting power, and we have a Top 50% consumer chain,\nthen if ",(0,n.jsx)(t.code,{children:"V"})," is denylisted, the consumer chain would only be secured by at least 40% of the provider's power."]})}),"\n",(0,n.jsxs)(t.p,{children:["All these mechanisms are set by the consumer chain in the ",(0,n.jsx)(t.code,{children:"ConsumerAdditionProposal"}),". They operate ",(0,n.jsx)(t.em,{children:"solely on the provider chain"}),", meaning the consumer chain simply receives the validator set after these rules have been applied and does not have any knowledge about whether they are applied."]}),"\n",(0,n.jsxs)(t.p,{children:["Each of these mechanisms is ",(0,n.jsx)(t.em,{children:"set during the consumer addition proposal"})," (see ",(0,n.jsx)(t.a,{href:"/interchain-security/v4.2.0/consumer-development/onboarding#3-submit-a-governance-proposal",children:"Onboarding"}),"), and is currently ",(0,n.jsx)(t.em,{children:"immutable"})," after the chain has been added."]}),"\n",(0,n.jsx)(t.p,{children:"The values can be seen by querying the list of consumer chains:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-bash",children:"interchain-security-pd query provider list-consumer-chains\n"})}),"\n",(0,n.jsx)(t.h2,{id:"guidelines-for-setting-power-shaping-parameters",children:"Guidelines for setting power shaping parameters"}),"\n",(0,n.jsx)(t.p,{children:"When setting power shaping parameters, please consider the following guidelines:"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["Do not cap the validator set size too low: Notice that this number is the *",(0,n.jsx)(t.em,{children:"maximum"})," number of validators that will ever validate the consumer chain. If this number is too low, the chain will be very limited in the\namount of stake that secures it. The validator set size cap should only be used if there are strong reasons to prefer fewer validators. Consider that setting the cap will mean that\neven if the whole validator set of the provider wants to validate on the chain, some validators will simply not be able to."]}),"\n",(0,n.jsx)(t.li,{children:"Capping the fraction of power any single validator can have is a decent security measure, but it's good to be aware of the interactions with the size of the validator set.\nFor example, if there are only 3 validators, and the cap is 20%, this will not be possible (since even splitting the power fairly would mean that each validator has 33% of the power, so is above the cap).\nHowever, the cap can be a good measure to prevent a single large validator from essentially taking over the chain.\nIn general, values under 33% make sense (since a validator that has 33% of the chains power would halt the chain if they go offline).\nNotice that the smaller this value is, the more the original voting power gets distorted, which could discourage large validators from deciding to opt in to the chain."}),"\n",(0,n.jsxs)(t.li,{children:["If the allowlist is ",(0,n.jsx)(t.em,{children:"empty"}),", all validators can validate the chain. If it is ",(0,n.jsx)(t.em,{children:"non empty"}),", then ",(0,n.jsx)(t.em,{children:"only"})," validators on the allowlist can validate the chain.\nThus, an allowlist containing too few validators is a security risk. In particular, consider that if the validators on the allowlist lose a lot of stake or stop being validators,\nan allowlist that is too short can very quickly become outdated and leave too few validators, or validators with too little stake, to secure the chain in a decentralized way."]}),"\n",(0,n.jsx)(t.li,{children:"If the denylist is too full, this can likewise be problematic. If too many large validators are denylisted, the chain might not be secured by a large enough fraction of the provider's power, in particular when\nthe power distribution on the provider shifts and the denylisted validators gain more power."}),"\n"]}),"\n",(0,n.jsx)(t.p,{children:"In general, when setting these parameters, consider that the voting power distribution in the future might be very different from the one right now,\nand that the chain should be secure even if the power distribution changes significantly."})]})}function d(e={}){const{wrapper:t}={...(0,a.a)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(c,{...e})}):c(e)}},1151:(e,t,i)=>{i.d(t,{Z:()=>r,a:()=>s});var n=i(7294);const a={},o=n.createContext(a);function s(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:s(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/405e8773.a6ffe47d.js b/assets/js/405e8773.a6ffe47d.js new file mode 100644 index 0000000000..7dca915361 --- /dev/null +++ b/assets/js/405e8773.a6ffe47d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5180],{1912:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var i=s(5893),t=s(1151);const r={sidebar_position:2,title:"Joining Interchain Security testnet"},o=void 0,a={id:"validators/joining-testnet",title:"Joining Interchain Security testnet",description:"Introduction",source:"@site/versioned_docs/version-v4.2.0-docs/validators/joining-testnet.md",sourceDirName:"validators",slug:"/validators/joining-testnet",permalink:"/interchain-security/v4.2.0/validators/joining-testnet",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"Joining Interchain Security testnet"},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/v4.2.0/validators/overview"},next:{title:"Withdrawing consumer chain validator rewards",permalink:"/interchain-security/v4.2.0/validators/withdraw_rewards"}},c={},d=[{value:"Introduction",id:"introduction",level:2},{value:"Joining the provider chain",id:"joining-the-provider-chain",level:2},{value:"Initialization",id:"initialization",level:2},{value:"Joining consumer chains",id:"joining-consumer-chains",level:2},{value:"Re-using consensus key",id:"re-using-consensus-key",level:2},{value:"Assigning consensus keys",id:"assigning-consensus-keys",level:2}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,t.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,i.jsxs)(n.p,{children:["This short guide will teach you how to join the ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/testnets/tree/master/interchain-security",children:"Interchain Security testnet"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"The experience gained in the testnet will prepare you for validating interchain secured chains."}),"\n",(0,i.jsxs)(n.admonition,{type:"tip",children:[(0,i.jsx)(n.p,{children:"Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set."}),(0,i.jsxs)(n.p,{children:["For general information about running cosmos-sdk based chains check out the ",(0,i.jsx)(n.a,{href:"https://hub.cosmos.network/validators/validator-setup",children:"validator basics"})," and ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/main/run-node/run-node",children:"Running a Node section"})," of Cosmos SDK docs"]})]}),"\n",(0,i.jsx)(n.h2,{id:"joining-the-provider-chain",children:"Joining the provider chain"}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsx)(n.p,{children:"At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain."})}),"\n",(0,i.jsxs)(n.p,{children:["A comprehensive guide is available ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/testnets/tree/master/interchain-security/provider",children:"here"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"initialization",children:"Initialization"}),"\n",(0,i.jsxs)(n.p,{children:["First, initialize your ",(0,i.jsx)(n.code,{children:"$NODE_HOME"})," using the ",(0,i.jsx)(n.code,{children:"provider"})," chain binary."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"NODE_MONIKER=<your_node>\nCHAIN_ID=provider\nNODE_HOME=<path_to_your_home>\n\ngaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Add your key to the keyring - more details available ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/main/run-node/keyring",children:"here"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["In this example we will use the ",(0,i.jsx)(n.code,{children:"test"})," keyring-backend. This option is not safe to use in production."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad keys add <key_moniker> --keyring-backend test\n\n# save the address as variable for later use\nMY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Before issuing any transactions, use the ",(0,i.jsx)(n.code,{children:"provider"})," testnet faucet to add funds to your address."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider\n\n# example output:\n{\n "address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",\n "amount": "10000000uatom",\n "chain": "provider",\n "hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",\n "status": "success"\n}\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Then, use the account associated with the keyring to issue a ",(0,i.jsx)(n.code,{children:"create-validator"})," transaction which will register your validator on chain."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'gaiad tx staking create-validator \\\n --amount=1000000uatom \\\n --pubkey=$(gaiad tendermint show-validator) \\\n --moniker="choose a moniker" \\\n --chain-id=$CHAIN_ID" \\\n --commission-rate="0.10" \\\n --commission-max-rate="0.20" \\\n --commission-max-change-rate="0.01" \\\n --min-self-delegation="1000000" \\\n --gas="auto" \\\n --gas-prices="0.0025uatom" \\\n --from=<key_moniker>\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["Check this ",(0,i.jsx)(n.a,{href:"https://hub.cosmos.network/validators/validator-setup#edit-validator-description",children:"guide"})," to edit your validator."]})}),"\n",(0,i.jsxs)(n.p,{children:["After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use ",(0,i.jsx)(n.code,{children:"statesync"})," to catch up to the rest of the network."]}),"\n",(0,i.jsxs)(n.p,{children:["You can use this script to modify your ",(0,i.jsx)(n.code,{children:"config.toml"})," with the required statesync parameters."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"# create the statesync script\n$: cd $NODE_HOME\n$: touch statesync.sh\n$ chmod 700 statesync.sh # make executable\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Paste the following instructions into the ",(0,i.jsx)(n.code,{children:"statesync.sh"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'#!/bin/bash\n\nSNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"\n\nLATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \\\nBLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \\\nTRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)\n\nsed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\\1true| ; \\\ns|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\\1\\"$SNAP_RPC,$SNAP_RPC\\"| ; \\\ns|^(trust_height[[:space:]]+=[[:space:]]+).*$|\\1$BLOCK_HEIGHT| ; \\\ns|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\\1\\"$TRUST_HASH\\"|" $NODE_HOME/config/config.toml\n'})}),"\n",(0,i.jsx)(n.p,{children:"Then, you can execute the script:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"$: ./statesync.sh # setup config.toml for statesync\n"})}),"\n",(0,i.jsx)(n.p,{children:"Finally, copy the provider genesis and start your node:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/interchain-security/provider/provider-genesis.json\n$: wget $GENESIS_URL -O genesis.json\n$: genesis.json $NODE_HOME/config/genesis.json\n# start the service\n$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Additional scripts to setup your nodes are available ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/provider/join-ics-provider.sh",children:"here"})," and ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/provider/join-ics-provider-cv.sh",children:"here"}),". The scripts will configure your node and create the required services - the scripts only work in linux environments."]}),"\n",(0,i.jsx)(n.h2,{id:"joining-consumer-chains",children:"Joining consumer chains"}),"\n",(0,i.jsxs)(n.admonition,{type:"tip",children:[(0,i.jsx)(n.p,{children:"Once you reach the active set on the provider chain, you will be required to validate all available consumer chains."}),(0,i.jsxs)(n.p,{children:["We strongly recommend that you assign a separate key for each consumer chain.\nCheck out this ",(0,i.jsx)(n.a,{href:"/interchain-security/v4.2.0/features/key-assignment",children:"guide"})," to learn more about key assignment in interchain security."]})]}),"\n",(0,i.jsx)(n.p,{children:"To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries."}),"\n",(0,i.jsxs)(n.admonition,{type:"info",children:[(0,i.jsxs)(n.p,{children:["When running the provider chain and consumers on the same machine please update the ",(0,i.jsx)(n.code,{children:"PORT"})," numbers for each of them and make sure they do not overlap (otherwise the binaries will not start)."]}),(0,i.jsx)(n.p,{children:"Important ports to re-configure:"}),(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"--rpc.laddr"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"--p2p.laddr"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"--api.address"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"--grpc.address"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"--grpc-web.address"})}),"\n"]})]}),"\n",(0,i.jsx)(n.h2,{id:"re-using-consensus-key",children:"Re-using consensus key"}),"\n",(0,i.jsxs)(n.p,{children:["To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the ",(0,i.jsx)(n.code,{children:"priv_validator_key.json"})," into the home directory of your consumer chain (",(0,i.jsx)(n.code,{children:"<consumer_home>/config/priv_validator_key.json"}),")."]}),"\n",(0,i.jsx)(n.p,{children:"When you start the chain, the consensus key will be the same on the provider and the consumer chain."}),"\n",(0,i.jsx)(n.h2,{id:"assigning-consensus-keys",children:"Assigning consensus keys"}),"\n",(0,i.jsx)(n.p,{children:"Whenever you initialize a new node, it will be configured with a consensus key you can use."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'# machine running consumer chain\nconsumerd init <node_moniker> --home <home_path> --chain-id consumer-1\n\n# use the output of this command to get the consumer chain consensus key\nconsumerd tendermint show-validator\n# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}\n'})}),"\n",(0,i.jsx)(n.p,{children:"Then, let the provider know which key you will be using for the consumer chain:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"# machine running the provider chain\ngaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b sync -y -o json\n"})}),"\n",(0,i.jsxs)(n.p,{children:["After this step, you are ready to copy the consumer genesis into your nodes's ",(0,i.jsx)(n.code,{children:"/config"})," folder, start your consumer chain node and catch up to the network."]})]})}function l(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},1151:(e,n,s)=>{s.d(n,{Z:()=>a,a:()=>o});var i=s(7294);const t={},r=i.createContext(t);function o(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/4106f1c5.c90c0bfb.js b/assets/js/4106f1c5.c90c0bfb.js new file mode 100644 index 0000000000..2711d898c1 --- /dev/null +++ b/assets/js/4106f1c5.c90c0bfb.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[842],{7049:(n,e,i)=>{i.r(e),i.d(e,{assets:()=>d,contentTitle:()=>t,default:()=>p,frontMatter:()=>s,metadata:()=>a,toc:()=>h});var r=i(5893),o=i(1151);const s={sidebar_position:4},t="Consumer Initiated Slashing",a={id:"features/slashing",title:"Consumer Initiated Slashing",description:"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the Interchain Security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.",source:"@site/docs/features/slashing.md",sourceDirName:"features",slug:"/features/slashing",permalink:"/interchain-security/features/slashing",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"ICS Provider Proposals",permalink:"/interchain-security/features/proposals"},next:{title:"Democracy modules",permalink:"/interchain-security/features/democracy-modules"}},d={},h=[{value:"Downtime Infractions",id:"downtime-infractions",level:2},{value:"Equivocation Infractions",id:"equivocation-infractions",level:2},{value:"Report equivocation infractions through CLI",id:"report-equivocation-infractions-through-cli",level:3},{value:"Report equivocation infractions with Hermes",id:"report-equivocation-infractions-with-hermes",level:3}];function c(n){const e={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,o.a)(),...n.components},{Details:i}=e;return i||function(n,e){throw new Error("Expected "+(e?"component":"object")+" `"+n+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(e.h1,{id:"consumer-initiated-slashing",children:"Consumer Initiated Slashing"}),"\n",(0,r.jsx)(e.p,{children:"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the Interchain Security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.\nIn essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake)."}),"\n",(0,r.jsx)(e.p,{children:"To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized.\nAny infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains."}),"\n",(0,r.jsx)(e.p,{children:"In the current implementation there are two important changes brought by the Interchain Security module."}),"\n",(0,r.jsx)(e.h2,{id:"downtime-infractions",children:"Downtime Infractions"}),"\n",(0,r.jsx)(e.p,{children:"Downtime infractions are reported by consumer chains and are acted upon on the provider as soon as the provider receives the infraction evidence."}),"\n",(0,r.jsx)(e.p,{children:"Instead of slashing, the provider will only jail offending validator for the duration of time established by the chain parameters."}),"\n",(0,r.jsx)(e.admonition,{type:"info",children:(0,r.jsxs)(e.p,{children:[(0,r.jsx)(e.a,{href:"/interchain-security/adrs/adr-002-throttle",children:"Slash throttling"})," (sometimes called jail throttling) mechanism ensures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider."]})}),"\n",(0,r.jsx)(e.p,{children:"Note that validators are only jailed for downtime on consumer chains that they opted-in to validate on,\nor in the case of Top N chains, where they are automatically opted in by being in the Top N% of the validator set on the provider."}),"\n",(0,r.jsx)(e.h2,{id:"equivocation-infractions",children:"Equivocation Infractions"}),"\n",(0,r.jsxs)(e.p,{children:["Equivocation infractions are reported by external agents (e.g., relayers) that can submit to the provider evidence of light client or double signing attacks observed on a consumer chain.\nThe evidence is submitted by sending ",(0,r.jsx)(e.code,{children:"MsgSubmitConsumerMisbehaviour"})," or ",(0,r.jsx)(e.code,{children:"MsgSubmitConsumerDoubleVoting"})," transactions to the provider.\nWhen valid evidence is received, the malicious validators are slashed, jailed, and tombstoned on the provider.\nThis is enabled through the ",(0,r.jsx)(e.em,{children:"cryptographic verification of equivocation"})," feature.\nFor more details, see ",(0,r.jsx)(e.a,{href:"/interchain-security/adrs/adr-005-cryptographic-equivocation-verification",children:"ADR-005"})," and ",(0,r.jsx)(e.a,{href:"/interchain-security/adrs/adr-013-equivocation-slashing",children:"ADR-013"}),"."]}),"\n",(0,r.jsx)(e.h3,{id:"report-equivocation-infractions-through-cli",children:"Report equivocation infractions through CLI"}),"\n",(0,r.jsx)(e.p,{children:"The ICS provider module offers two commands for submitting evidence of misbehavior originating from a consumer chain.\nBelow are two examples illustrating the process on Cosmos Hub."}),"\n",(0,r.jsx)(e.p,{children:"Use the following command to submit evidence of double signing attacks:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"gaiad tx provider submit-consumer-double-voting [path/to/evidence.json] [path/to/infraction_header.json] --from node0 --home ../node0 --chain-id $CID \n"})}),"\n",(0,r.jsxs)(i,{children:[(0,r.jsxs)("summary",{children:["Example of ",(0,r.jsx)(e.code,{children:"evidence.json"})]}),(0,r.jsx)("div",{children:(0,r.jsx)("div",{children:(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-json",children:'{\n "vote_a": {\n "type": 1,\n "height": 25,\n "round": 0,\n "block_id": {\n "hash": "tBBWTqjECl31S/clZGoxLdDqs93kTvy3qhpPqET/laY=",\n "part_set_header": {\n "total": 1,\n "hash": "ai2qCLgVZAFph4FJ4Cqw5QW1GZKR4zjOv0bI/Um5AIc="\n }\n },\n "timestamp": "2023-11-20T12:57:54.565207Z",\n "validator_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",\n "signature": "y9yILm9hmv45BZwAaaq9mS1FpH7QeAIJ5Jkcc3U2/k5uks9cuqr4NTIwaIrqMSMKwxVyqiR56xmCT59a6AngAA=="\n },\n "vote_b": {\n "type": 1,\n "height": 25,\n "round": 0,\n "block_id": {\n "hash": "3P06pszgPatuIdLTP5fDWiase4SYHIq9YXGSbRk9/50=",\n "part_set_header": {\n "total": 1,\n "hash": "S+SbOMxFRzfeNNpX9/jyFMz94VwBKk7Dpx6ZyvSYyNU="\n }\n },\n "timestamp": "2023-11-20T12:57:54.599273Z",\n "validator_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",\n "validator_index": 0,\n "signature": "DGFcn4Um1t2kXW60+JhMk5cj7ZFdE5goKVOGiZkLwnNv43+6aGmOWjoq0SHYVzM4MwSwOwbhgZNbkWX+EHGUBw=="\n },\n "total_voting_power": 300,\n "validator_power": 100,\n "timestamp": "2023-11-20T12:57:51.267308Z"\n}\n'})})})})]}),"\n",(0,r.jsxs)(i,{children:[(0,r.jsxs)("summary",{children:["Example of ",(0,r.jsx)(e.code,{children:"infraction_header.json"})]}),(0,r.jsx)("div",{children:(0,r.jsx)("div",{children:(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-json",children:'{\n "signed_header": {\n "header": {\n "version": {\n "block": 11,\n "app": 2\n },\n "chain_id": "consumer",\n "height": 22,\n "time": "2023-11-20T12:57:40.479686Z",\n "last_block_id": {\n "hash": "L63hyLJ+y9+fpb7WYKdmmBhPHwbfEGQEuKmvGzyBPiY=",\n "part_set_header": {\n "total": 18,\n "hash": "euzRQjN7MjGtM6skXM4B8wOgAldWGfZSJRA9JRlO42s="\n }\n },\n "last_commit_hash": "qdDJwVziW3pPqmf8QDGZG+5HVd3OF7fCVh2Z8KQqNVU=",\n "data_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",\n "validators_hash": "pVc+gSYkGesaP3OkK4ig3DBi4o9/GCdXGtO/PQ6i/Ik=",\n "next_validators_hash": "pVc+gSYkGesaP3OkK4ig3DBi4o9/GCdXGtO/PQ6i/Ik=",\n "consensus_hash": "BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8=",\n "app_hash": "Yu3HX62w7orbbY/pm2QEK7yIwR+AlNdjSSqiK1kmuJM=",\n "last_results_hash": "Yu3HX62w7orbbY/pm2QEK7yIwR+AlNdjSSqiK1kmuJM=",\n "evidence_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",\n "proposer_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA="\n },\n "commit": {\n "height": 22,\n "round": 1,\n "block_id": {\n "hash": "PKrS32IEZoFY2q2S3iQ68HQL751ieBhf5Eu/Y5Z/QPg=",\n "part_set_header": {\n "total": 1,\n "hash": "8UuA7Oqw5AH/KOacpmHVSMOIDe4l2eC8VmdH2mzcpiM="\n }\n },\n "signatures": [\n {\n "block_id_flag": 2,\n "validator_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",\n "timestamp": "2023-11-20T12:57:44.076538Z",\n "signature": "bSOH4+Vg2I37zeJphOguGOD0GK3JzM1ghSgJd0UlW/DHn1u9Hvv4EekHuCu6qwRLZcuS/ZxNlmr9qYNfxX3bDA=="\n },\n {\n "block_id_flag": 2,\n "validator_address": "i/A830FM7cfmA8yTn9n3xBg5XpU=",\n "timestamp": "2020-01-02T00:07:00Z",\n "signature": "7bXSDtlOwGK/gLEsFpTWOzm2TFoaARrWQUpbgWEwKtLlUs7iE06TOvJ3yPPfTfqqN/qYnvxxgjl0M0EhUWu5Bg=="\n },\n {\n "block_id_flag": 2,\n "validator_address": "lrQDkJ2fk7UAgNzRZfcwMKSYa2E=",\n "timestamp": "2023-11-20T12:57:44.076519Z",\n "signature": "Pb6G4bCg4wafmV89WNnzXxbSCknZUHnSQfSCE5QMFxPtSUIN4A7SK5m7yltqMJF5zkyenlFiEI4J3OZ4KCjCAw=="\n },\n {\n "block_id_flag": 2,\n "validator_address": "+R94nXSeM1Z49e/CXpyHT3M+h3k=",\n "timestamp": "2023-11-20T12:57:44.057451Z",\n "signature": "j3EasIHNYA6MxW/PiWyruzHsjVsBV9t11W6Qx800WMm/+P+CkfR+UZAp7MPTvKZEZFuh3GUsBtyfb/vA+jJWCw=="\n }\n ]\n }\n },\n "validator_set": {\n "validators": [\n {\n "address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",\n "pub_key": {\n "ed25519": "dtn+SfD+4QLo0+t0hAoP6Q2sGjh0XEI3LWVG+doh3u0="\n },\n "voting_power": 100,\n "proposer_priority": -200\n },\n {\n "address": "lrQDkJ2fk7UAgNzRZfcwMKSYa2E=",\n "pub_key": {\n "ed25519": "UgN2JsjPy2WLh7dzJRBkUQtdgNoT4/uGj7kbIVqqHT8="\n },\n "voting_power": 100,\n "proposer_priority": 100\n },\n {\n "address": "+R94nXSeM1Z49e/CXpyHT3M+h3k=",\n "pub_key": {\n "ed25519": "5svW8261x+cZosp2xIhqzgt2tyuawrSDyHlpbgS3BC4="\n },\n "voting_power": 100,\n "proposer_priority": 100\n },\n {\n "address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",\n "pub_key": {\n "ed25519": "dtn+SfD+4QLo0+t0hAoP6Q2sGjh0XEI3LWVG+doh3u0="\n },\n "voting_power": 100,\n "proposer_priority": -200\n }\n ],\n "proposer": {\n "address": "VUz+QceJ8Nu7GbJuVItwsfVjybA=",\n "pub_key": {\n "ed25519": "0s8KDTgEcwmOBrHWvV7mtBlItJ3upgM1FJsciwREdy4="\n },\n "voting_power": 1,\n "proposer_priority": -3\n }\n },\n "trusted_height": {\n "revision_height": 18\n },\n "trusted_validators": {\n "validators": [\n {\n "address": "VUz+QceJ8Nu7GbJuVItwsfVjybA=",\n "pub_key": {\n "ed25519": "0s8KDTgEcwmOBrHWvV7mtBlItJ3upgM1FJsciwREdy4="\n },\n "voting_power": 1,\n "proposer_priority": -3\n },\n {\n "address": "i/A830FM7cfmA8yTn9n3xBg5XpU=",\n "pub_key": {\n "ed25519": "FCmIw7hSuiAoWk/2f4LuGQ+3zx5101xiqU8DoC5wGkg="\n },\n "voting_power": 1,\n "proposer_priority": 1\n },\n {\n "address": "2DrZF0roNnnvEy4NS2aY811ncKg=",\n "pub_key": {\n "ed25519": "MI9c6sphsWlx0RAHCYOjMRXMFkTUaEYwOiOKG/0tsMs="\n },\n "voting_power": 1,\n "proposer_priority": 1\n },\n {\n "address": "73aN0uOc5b/Zfq2Xcjl0kH2r+tw=",\n "pub_key": {\n "ed25519": "gWNcDup4mdnsuqET4QeFRzVb+FnSP4Vz3iNMj5wvWXk="\n },\n "voting_power": 1,\n "proposer_priority": 1\n }\n ],\n "proposer": {\n "address": "VUz+QceJ8Nu7GbJuVItwsfVjybA=",\n "pub_key": {\n "ed25519": "0s8KDTgEcwmOBrHWvV7mtBlItJ3upgM1FJsciwREdy4="\n },\n "voting_power": 1,\n "proposer_priority": -3\n }\n }\n}\n'})})})})]}),"\n",(0,r.jsx)(e.p,{children:"Use the following command to submit evidence of light client attacks:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"gaiad tx provider submit-consumer-misbehaviour [path/to/misbehaviour.json] --from node0 --home ../node0 --chain-id $CID\n"})}),"\n",(0,r.jsxs)(i,{children:[(0,r.jsxs)("summary",{children:["Example of ",(0,r.jsx)(e.code,{children:"misbehaviour.json"})]}),(0,r.jsx)("div",{children:(0,r.jsx)("div",{children:(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-json",children:'{\n "client_id": "07-tendermint-0",\n "header_1": {\n "signed_header": {\n "header": {\n "version": {\n "block": "11",\n "app": "2"\n },\n "chain_id": "testchain2",\n "height": "19",\n "time": "2020-01-02T00:08:10Z",\n "last_block_id": {\n "hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",\n "part_set_header": {\n "total": 10000,\n "hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="\n }\n },\n "last_commit_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",\n "data_hash": "bW4ouLmLUycELqUKV91G5syFHHLlKL3qpu/e7v5moLg=",\n "validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",\n "next_validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",\n "consensus_hash": "5eVmxB7Vfj/4zBDxhBeHiLj6pgKwfPH0JSF72BefHyQ=",\n "app_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",\n "last_results_hash": "CS4FhjAkftYAmGOhLu4RfSbNnQi1rcqrN/KrNdtHWjc=",\n "evidence_hash": "c4ZdsI9J1YQokF04mrTKS5bkWjIGx6adQ6Xcc3LmBxQ=",\n "proposer_address": "CbKqPquy50bcrY7JRdW7zXybSuA="\n },\n "commit": {\n "height": "19",\n "round": 1,\n "block_id": {\n "hash": "W2xVqzPw03ZQ1kAMpcpht9WohwMzsGnyKKNjPYKDF6U=",\n "part_set_header": {\n "total": 3,\n "hash": "hwgKOc/jNqZj6lwNm97vSTq9wYt8Pj4MjmYTVMGDFDI="\n }\n },\n "signatures": [\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "timestamp": "2020-01-02T00:08:10Z",\n "signature": "PGTquCtnTNFFY5HfEFz9f9pA7PYqjtQfBwHq6cxF/Ux8OI6nVqyadD9a84Xm7fSm6mqdW+T6YVfqIKmIoRjJDQ=="\n },\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",\n "timestamp": "2020-01-02T00:08:10Z",\n "signature": "0e39yoBorwORAH/K9qJ7D1N1Yr7CutMiQJ+oiIK39eMhuoK3UWzQyMGRLzDOIDupf8yD99mvGVVAlNIODlV3Dg=="\n },\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",\n "timestamp": "2020-01-02T00:08:10Z",\n "signature": "lhc2tkwydag9D1iLQhdDCE8GgrHP94M1LbHFYMoL9tExaEq6RiFW/k71TQH5x96XQ9XYOznMIHKC2BDh4GlnAQ=="\n },\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",\n "timestamp": "2020-01-02T00:08:10Z",\n "signature": "8xeSBf0nSFs/X/rQ9CZLzwkJJhQBLA2jKdPGP3MlULxm992XxrOsIYq47u1daxvSsn6ql5OVYjzBNU0qbPpvCA=="\n }\n ]\n }\n },\n "validator_set": {\n "validators": [\n {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n {\n "address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",\n "pub_key": {\n "ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",\n "pub_key": {\n "ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",\n "pub_key": {\n "ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n }\n ],\n "proposer": {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n "total_voting_power": "0"\n },\n "trusted_height": {\n "revision_number": "0",\n "revision_height": "18"\n },\n "trusted_validators": {\n "validators": [\n {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n {\n "address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",\n "pub_key": {\n "ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",\n "pub_key": {\n "ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",\n "pub_key": {\n "ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n }\n ],\n "proposer": {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n "total_voting_power": "0"\n }\n },\n "header_2": {\n "signed_header": {\n "header": {\n "version": {\n "block": "11",\n "app": "2"\n },\n "chain_id": "testchain2",\n "height": "19",\n "time": "2020-01-02T00:08:20Z",\n "last_block_id": {\n "hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",\n "part_set_header": {\n "total": 10000,\n "hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="\n }\n },\n "last_commit_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",\n "data_hash": "bW4ouLmLUycELqUKV91G5syFHHLlKL3qpu/e7v5moLg=",\n "validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",\n "next_validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",\n "consensus_hash": "5eVmxB7Vfj/4zBDxhBeHiLj6pgKwfPH0JSF72BefHyQ=",\n "app_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",\n "last_results_hash": "CS4FhjAkftYAmGOhLu4RfSbNnQi1rcqrN/KrNdtHWjc=",\n "evidence_hash": "c4ZdsI9J1YQokF04mrTKS5bkWjIGx6adQ6Xcc3LmBxQ=",\n "proposer_address": "CbKqPquy50bcrY7JRdW7zXybSuA="\n },\n "commit": {\n "height": "19",\n "round": 1,\n "block_id": {\n "hash": "IZM8NKS+8FHB7CBmgB8Nz7BRVVXiiyqMQDvHFUvgzxo=",\n "part_set_header": {\n "total": 3,\n "hash": "hwgKOc/jNqZj6lwNm97vSTq9wYt8Pj4MjmYTVMGDFDI="\n }\n },\n "signatures": [\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "timestamp": "2020-01-02T00:08:20Z",\n "signature": "pLIEZ4WSAtnMsgryujheHSq4+YG3RqTfMn2ZxgEymr0wyi+BNlQAKRtRfesm0vfYxvjzc/jhGqtUqHtSIaCwCQ=="\n },\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",\n "timestamp": "2020-01-02T00:08:20Z",\n "signature": "XG7iTe/spWyTUkT7XDzfLMpYqrdyqizE4/X4wl/W+1eaQp0WsCHYnvPU3x9NAnYfZzaKdonZiDWs7wacbZTcDg=="\n },\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",\n "timestamp": "2020-01-02T00:08:20Z",\n "signature": "TqegK7ORuICSy++wVdPHt8fL2WfPlYsMPv1XW79wUdcjnQkezOM50OSqYaP4ua5frIZsn+sWteDrlqFTdkl3BA=="\n },\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",\n "timestamp": "2020-01-02T00:08:20Z",\n "signature": "dhvp3XlIaCxx5MFDs0TCkAPHSm0PS2EtJzYAx2c/7MWdLwUJFZrAUTeimQE2c9i9ro91cjZn/vI0/oFRXab6Aw=="\n }\n ]\n }\n },\n "validator_set": {\n "validators": [\n {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n {\n "address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",\n "pub_key": {\n "ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",\n "pub_key": {\n "ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",\n "pub_key": {\n "ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n }\n ],\n "proposer": {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n "total_voting_power": "0"\n },\n "trusted_height": {\n "revision_number": "0",\n "revision_height": "18"\n },\n "trusted_validators": {\n "validators": [\n {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n {\n "address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",\n "pub_key": {\n "ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",\n "pub_key": {\n "ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",\n "pub_key": {\n "ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n }\n ],\n "proposer": {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n "total_voting_power": "0"\n }\n }\n}\n'})})})})]}),"\n",(0,r.jsx)(e.h3,{id:"report-equivocation-infractions-with-hermes",children:"Report equivocation infractions with Hermes"}),"\n",(0,r.jsxs)(e.p,{children:["Ensure you have a well-configured Hermes ",(0,r.jsx)(e.code,{children:"v1.7.3+"})," relayer effectively relaying packets between a consumer chain and a provider chain.\nThe following command demonstrates how to run a Hermes instance in ",(0,r.jsx)(e.em,{children:"evidence mode"})," to detect misbehaviors on a consumer chain and automatically submit the evidence to the provider chain."]}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"hermes evidence --chain <CONSUMER-CHAIN-ID>\n"})}),"\n",(0,r.jsx)(e.admonition,{type:"tip",children:(0,r.jsxs)(e.p,{children:[(0,r.jsx)(e.code,{children:"hermes evidence"})," takes a ",(0,r.jsx)(e.code,{children:"--check-past-blocks"})," option giving the possibility to look for older evidence (default is 100)."]})})]})}function p(n={}){const{wrapper:e}={...(0,o.a)(),...n.components};return e?(0,r.jsx)(e,{...n,children:(0,r.jsx)(c,{...n})}):c(n)}},1151:(n,e,i)=>{i.d(e,{Z:()=>a,a:()=>t});var r=i(7294);const o={},s=r.createContext(o);function t(n){const e=r.useContext(s);return r.useMemo((function(){return"function"==typeof n?n(e):{...e,...n}}),[e,n])}function a(n){let e;return e=n.disableParentContext?"function"==typeof n.components?n.components(o):n.components||o:t(n.components),r.createElement(s.Provider,{value:e},n.children)}}}]); \ No newline at end of file diff --git a/assets/js/4179ee03.b3fced4f.js b/assets/js/4179ee03.b3fced4f.js new file mode 100644 index 0000000000..3c0f4154d4 --- /dev/null +++ b/assets/js/4179ee03.b3fced4f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6073],{2069:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>p,frontMatter:()=>o,metadata:()=>t,toc:()=>c});var s=r(5893),i=r(1151);const o={sidebar_position:1},a="Upgrading to ICS v5.0.0",t={id:"upgrading/migrate_v4_v5",title:"Upgrading to ICS v5.0.0",description:"This ICS version uses cosmos-sdk v0.50.x and ibc-go v8.x.",source:"@site/docs/upgrading/migrate_v4_v5.md",sourceDirName:"upgrading",slug:"/upgrading/migrate_v4_v5",permalink:"/interchain-security/upgrading/migrate_v4_v5",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Technical Specification",permalink:"/interchain-security/introduction/technical-specification"},next:{title:"Key Assignment",permalink:"/interchain-security/features/key-assignment"}},d={},c=[{value:"Provider",id:"provider",level:2},{value:"Keeper initialization",id:"keeper-initialization",level:3},{value:"Protocol changes",id:"protocol-changes",level:3},{value:"Revert <code>AfterUnbondingInitiated</code>",id:"revert-afterunbondinginitiated",level:4},{value:"Migration (v4 -> v5)",id:"migration-v4---v5",level:3},{value:"Additions",id:"additions",level:3},{value:"MsgUpdateParams transaction",id:"msgupdateparams-transaction",level:3},{value:"Governance proposals",id:"governance-proposals",level:3},{value:"Consumer",id:"consumer",level:2},{value:"Keeper initialization",id:"keeper-initialization-1",level:3},{value:"Additions",id:"additions-1",level:3},{value:"<code>MsgUpdateParams</code> transaction",id:"msgupdateparams-transaction-1",level:4},{value:"Params Query",id:"params-query",level:4},{value:"Migration (v2 -> v3)",id:"migration-v2---v3",level:3},{value:"Interface method changes",id:"interface-method-changes",level:3},{value:"Democracy",id:"democracy",level:2},{value:"Note:",id:"note",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"upgrading-to-ics-v500",children:"Upgrading to ICS v5.0.0"}),"\n",(0,s.jsx)(n.p,{children:"This ICS version uses cosmos-sdk v0.50.x and ibc-go v8.x."}),"\n",(0,s.jsxs)(n.p,{children:["To migrate you application to cosmos-sdk v0.50.x please use this ",(0,s.jsx)(n.a,{href:"https://docs.cosmos.network/v0.50/build/migrations/upgrading",children:"guide"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"To migrate your application to ibc-go v8.x.y please use the following guides:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://ibc.cosmos.network/main/migrations/v7-to-v8",children:"migrate ibc-go to v8.0.0"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://ibc.cosmos.network/main/migrations/v8-to-v8_1",children:"migrate ibc-go to v8.1.0"})}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"ICS specific changes are outlined below."}),"\n",(0,s.jsxs)(n.p,{children:["Pre-requisite version for this upgrade: ",(0,s.jsx)(n.code,{children:"v4.x"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"provider",children:"Provider"}),"\n",(0,s.jsx)(n.h3,{id:"keeper-initialization",children:"Keeper initialization"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-diff",children:"// app.go\n\napp.ProviderKeeper = ibcproviderkeeper.NewKeeper(\n appCodec,\n keys[providertypes.StoreKey],\n app.GetSubspace(providertypes.ModuleName),\n scopedIBCProviderKeeper,\n app.IBCKeeper.ChannelKeeper,\n- app.IBCKeeper.PortKeeper\n+ app.IBCKeeper.PortKeeper,\n app.IBCKeeper.ConnectionKeeper,\n app.IBCKeeper.ClientKeeper,\n app.StakingKeeper,\n app.SlashingKeeper,\n app.AccountKeeper,\n app.DistrKeeper,\n app.BankKeeper,\n *app.GovKeeper,\n+ authtypes.NewModuleAddress(govtypes.ModuleName).String(),\n+ authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),\n+ authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()),\n authtypes.FeeCollectorName,\n)\n"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"authority"})," was added - requirement for executing ",(0,s.jsx)(n.code,{children:"MsgUpdateParams"})]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["uses ",(0,s.jsx)(n.code,{children:"x/gov"})," module address by default"]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"validatorAddressCodec"})," & ",(0,s.jsx)(n.code,{children:"consensusAddressCodec"})," were added - they must match the bech32 address codec used by ",(0,s.jsx)(n.code,{children:"x/auth"}),", ",(0,s.jsx)(n.code,{children:"x/bank"}),", ",(0,s.jsx)(n.code,{children:"x/staking"})]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"protocol-changes",children:"Protocol changes"}),"\n",(0,s.jsxs)(n.h4,{id:"revert-afterunbondinginitiated",children:["Revert ",(0,s.jsx)(n.code,{children:"AfterUnbondingInitiated"})]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"AfterUnbondingInitiated"})," behavior was reverted to ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/v1.2.0-multiden/x/ccv/provider/keeper/hooks.go#L53",children:"ICS@v1.2.0-multiden"})]}),"\n",(0,s.jsx)(n.p,{children:"The revert re-introduces an additional state check."}),"\n",(0,s.jsxs)(n.p,{children:["See this ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/1045",children:"issue"})," for more context and the actions taken."]}),"\n",(0,s.jsx)(n.h3,{id:"migration-v4---v5",children:"Migration (v4 -> v5)"}),"\n",(0,s.jsxs)(n.p,{children:["ConensusVersion was bumped to ",(0,s.jsx)(n.code,{children:"5"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["The migration allows storing the provider module params in the ",(0,s.jsx)(n.code,{children:"x/ccv/provider"})," module store instead of relying on legacy ",(0,s.jsx)(n.code,{children:"x/param"})," store."]}),"\n",(0,s.jsx)(n.p,{children:"There are no special requirements for executing this migration."}),"\n",(0,s.jsx)(n.h3,{id:"additions",children:"Additions"}),"\n",(0,s.jsx)(n.h3,{id:"msgupdateparams-transaction",children:"MsgUpdateParams transaction"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"x/gov"})," module account is selected as the default ",(0,s.jsx)(n.code,{children:"authority"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["It is available when using ",(0,s.jsx)(n.code,{children:"gov"})," CLI commands:"]}),"\n",(0,s.jsx)(n.p,{children:"Drafting a proposal:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:'interchain-security-pd tx gov draft-proposal\n# select "other"\n# find and select "/interchain_security.ccv.provider.v1.MsgUpdateParams"\n'})}),"\n",(0,s.jsx)(n.p,{children:"Submitting a proposal:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:"interchain-security-pd tx gov submit-proposal <proposal-message.json>\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Example ",(0,s.jsx)(n.code,{children:"proposal-message.json"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "messages": [\n {\n "@type": "/interchain_security.ccv.provider.v1.MsgUpdateParams",\n "authority": "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn",\n "params": {\n "trusting_period_fraction": "0.66",\n "ccv_timeout_period": "2419200s",\n "init_timeout_period": "604800s",\n "vsc_timeout_period": "3024000s",\n "slash_meter_replenish_period": "3s",\n "slash_meter_replenish_fraction": "1.0",\n "consumer_reward_denom_registration_fee": {\n "denom": "stake",\n "amount": "10000000"\n },\n "blocks_per_epoch": "600"\n }\n }\n ],\n "metadata": "ipfs://CID",\n "deposit": "10000stake",\n "title": "Update Provider params",\n "summary": "Update Provider params",\n "expedited": false\n}\n'})}),"\n",(0,s.jsx)(n.h3,{id:""}),"\n",(0,s.jsxs)(n.p,{children:["When updating parameters ",(0,s.jsx)(n.strong,{children:"all"})," parameters fields must be specified. Make sure you are only changing parameters that you are interested in."]}),"\n",(0,s.jsx)(n.p,{children:"To avoid accidentally changing parameters you can first check the current on-chain provider params using:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:'interchain-security-pd q provider params -o json\n\n{\n "template_client": {...},\n "trusting_period_fraction": "0.66",\n "ccv_timeout_period": "2419200s",\n "init_timeout_period": "604800s",\n "vsc_timeout_period": "3024000s",\n "slash_meter_replenish_period": "3s",\n "slash_meter_replenish_fraction": "1.0",\n "consumer_reward_denom_registration_fee": {\n "denom": "stake",\n "amount": "10000000"\n },\n "blocks_per_epoch": "600"\n}\n'})}),"\n",(0,s.jsx)(n.h3,{id:"governance-proposals",children:"Governance proposals"}),"\n",(0,s.jsx)(n.p,{children:"Submitting the following legacy proposals is still supported:"}),"\n",(0,s.jsx)(n.h1,{id:"consumer-addition-proposal",children:"Consumer addition proposal"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:"interchain-security-pd tx gov submit-legacy-proposal consumer-addition <proposal_file.json>\n"})}),"\n",(0,s.jsx)(n.h1,{id:"consumer-removal-proposal",children:"Consumer removal proposal"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:"interchain-security-pd tx gov submit-legacy-proposal consumer-removal <proposal_file.json>\n"})}),"\n",(0,s.jsx)(n.h1,{id:"consumer-addition-proposal-1",children:"Consumer addition proposal"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:"interchain-security-pd tx gov submit-legacy-proposal change-reward-denoms <proposal_file.json>\n"})}),"\n",(0,s.jsxs)(n.p,{children:["You may also submit proposal messages above using ",(0,s.jsx)(n.code,{children:"submit-proposal"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"consumer",children:"Consumer"}),"\n",(0,s.jsx)(n.h3,{id:"keeper-initialization-1",children:"Keeper initialization"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-diff",children:"// pre-initialize ConsumerKeeper to satsfy ibckeeper.NewKeeper\napp.ConsumerKeeper = ibcconsumerkeeper.NewNonZeroKeeper(\n appCodec,\n keys[ibcconsumertypes.StoreKey],\n app.GetSubspace(ibcconsumertypes.ModuleName),\n)\n\napp.IBCKeeper = ibckeeper.NewKeeper(\n appCodec,\n keys[ibchost.StoreKey],\n app.GetSubspace(ibchost.ModuleName),\n app.ConsumerKeeper,\n app.UpgradeKeeper,\n scopedIBCKeeper,\n authtypes.NewModuleAddress(govtypes.ModuleName).String(),\n)\n\n// initialize the actual consumer keeper\napp.ConsumerKeeper = ibcconsumerkeeper.NewKeeper(\n appCodec,\n keys[ibcconsumertypes.StoreKey],\n app.GetSubspace(ibcconsumertypes.ModuleName),\n scopedIBCConsumerKeeper,\n app.IBCKeeper.ChannelKeeper,\n- &app.IBCKeeper.PortKeeper,\n+ app.IBCKeeper.PortKeeper,\n app.IBCKeeper.ConnectionKeeper,\n app.IBCKeeper.ClientKeeper,\n app.SlashingKeeper,\n app.BankKeeper,\n app.AccountKeeper,\n &app.TransferKeeper,\n app.IBCKeeper,\n authtypes.FeeCollectorName,\n\n // make sure the authority address makes sense for your chain\n // the exact module account may differ depending on your setup (x/gov, x/admin or custom module)\n // for x/ccv/democracy using the x/gov module address is correct\n // if you don't have a way of updating consumer params you may still use the line below as it will have no affect\n+ authtypes.NewModuleAddress(govtypes.ModuleName).String(),\n \n // add address codecs \n+ authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),\n+ authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()),\n)\n"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"authority"})," was added - requirement for executing ",(0,s.jsx)(n.code,{children:"MsgUpdateParams"})]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"make sure the authority address makes sense for your chain"}),"\n",(0,s.jsxs)(n.li,{children:["the exact module account may differ depending on your setup (",(0,s.jsx)(n.code,{children:"x/gov"}),", ",(0,s.jsx)(n.code,{children:"x/admin"})," or custom module)"]}),"\n",(0,s.jsxs)(n.li,{children:["for ",(0,s.jsx)(n.code,{children:"x/ccv/democracy"})," using the ",(0,s.jsx)(n.code,{children:"x/gov"})," module address is correct"]}),"\n",(0,s.jsxs)(n.li,{children:["if you don't have a way of updating consumer params you may use ",(0,s.jsx)(n.code,{children:"authtypes.NewModuleAddress(govtypes.ModuleName).String()"})," (has no effect on functionality)"]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"validatorAddressCodec"})," & ",(0,s.jsx)(n.code,{children:"consensusAddressCodec"})," were added - they must match the bech32 address codec used by ",(0,s.jsx)(n.code,{children:"x/auth"}),", ",(0,s.jsx)(n.code,{children:"x/bank"}),", ",(0,s.jsx)(n.code,{children:"x/staking"})]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"additions-1",children:"Additions"}),"\n",(0,s.jsxs)(n.h4,{id:"msgupdateparams-transaction-1",children:[(0,s.jsx)(n.code,{children:"MsgUpdateParams"})," transaction"]}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsxs)(n.strong,{children:["This functionality is not supported on ",(0,s.jsx)(n.code,{children:"x/ccv/consumer"})," without additional configuration."]})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["if you are using ",(0,s.jsx)(n.code,{children:"x/ccv/democracy"})," the feature is supported out of the box"]}),"\n",(0,s.jsxs)(n.li,{children:["if you are using custom logic for changing consumer params, please update your code by providing the appropriate ",(0,s.jsx)(n.code,{children:"authority"})," module account during ",(0,s.jsx)(n.code,{children:"ConsumerKeeper"})," initialization in ",(0,s.jsx)(n.code,{children:"app.go"}),"."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsxs)(n.strong,{children:["You must add ",(0,s.jsx)(n.code,{children:'"/interchain_security.ccv.consumer.v1.MsgUpdateParams"'})," to your parameters whitelist to be able to change ",(0,s.jsx)(n.code,{children:"ccvconsumer"})," parameters via governance."]})}),"\n",(0,s.jsxs)(n.p,{children:["It is available when using ",(0,s.jsx)(n.code,{children:"gov"})," CLI commands:"]}),"\n",(0,s.jsx)(n.p,{children:"Drafting a proposal:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:'interchain-security-cd tx gov draft-proposal\n# select "other"\n# find and select "/interchain_security.ccv.consumer.v1.MsgUpdateParams"\n'})}),"\n",(0,s.jsx)(n.p,{children:"Submitting a proposal:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsxs)(n.strong,{children:["this proposal cannot be executed on chains without access to ",(0,s.jsx)(n.code,{children:"x/gov"})," or other modules for managing governance"]})}),"\n"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:"\ninterchain-security-cdd tx gov submit-proposal <proposal-message.json>\n\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Example ",(0,s.jsx)(n.code,{children:"proposal-message.json"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "messages": [\n {\n "@type": "/interchain_security.ccv.consumer.v1.MsgUpdateParams",\n "authority": "consumer10d07y265gmmuvt4z0w9aw880jnsr700jlh7295",\n "params": {\n "enabled": true,\n "blocks_per_distribution_transmission": "20",\n "distribution_transmission_channel": "channel-1",\n "provider_fee_pool_addr_str": "",\n "ccv_timeout_period": "2419200s",\n "transfer_timeout_period": "3000s",\n "consumer_redistribution_fraction": "0.75",\n "historical_entries": "10000",\n "unbonding_period": "1209600s",\n "soft_opt_out_threshold": "0.05",\n "reward_denoms": [],\n "provider_reward_denoms": [],\n "retry_delay_period": "3000s"\n }\n }\n ],\n "metadata": "ipfs://CID",\n "deposit": "1000uatom",\n "title": "Update Consumer Params -- change transfer_timeout_period to 3000s",\n "summary": "Test Update Consumer Params",\n "expedited": false\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["When updating parameters ",(0,s.jsx)(n.strong,{children:"all"})," parameters fields must be specified. Make sure you are only changing parameters that you are interested in."]}),"\n",(0,s.jsx)(n.p,{children:"To avoid accidentally changing parameters you can first check the current on-chain consumer params using:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:"interchain-security-pd q ccvconsumer params -o json\n"})}),"\n",(0,s.jsx)(n.h4,{id:"params-query",children:"Params Query"}),"\n",(0,s.jsx)(n.p,{children:"Consumer params query was added:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:'interchain-security-cd q ccvconsumer params -o json\n\n{\n "params": {\n "enabled": true,\n "blocks_per_distribution_transmission": "1000",\n "distribution_transmission_channel": "",\n "provider_fee_pool_addr_str": "",\n "ccv_timeout_period": "2419200s",\n "transfer_timeout_period": "3600s",\n "consumer_redistribution_fraction": "0.75",\n "historical_entries": "10000",\n "unbonding_period": "1209600s",\n "soft_opt_out_threshold": "0.05",\n "reward_denoms": [],\n "provider_reward_denoms": [],\n "retry_delay_period": "3600s"\n }\n}\n'})}),"\n",(0,s.jsx)(n.h3,{id:"migration-v2---v3",children:"Migration (v2 -> v3)"}),"\n",(0,s.jsxs)(n.p,{children:["ConensusVersion was bumped to ",(0,s.jsx)(n.code,{children:"3"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["The migration allows storing the consumer module params in the ",(0,s.jsx)(n.code,{children:"x/ccv/consumer"})," module store instead of relying on legacy ",(0,s.jsx)(n.code,{children:"x/param"})," store."]}),"\n",(0,s.jsx)(n.p,{children:"There are no special requirements for executing this migration."}),"\n",(0,s.jsx)(n.h3,{id:"interface-method-changes",children:"Interface method changes"}),"\n",(0,s.jsxs)(n.p,{children:["Consumer methods were changed to match the cosmos-sdk ",(0,s.jsx)(n.code,{children:"StakingKeeper"})," interface.\nYou will not need to change your code, unless you are using the ",(0,s.jsx)(n.code,{children:"ConsumerKeeper"})," inside custom tests or you have developed custom app functionality that relies on ",(0,s.jsx)(n.code,{children:"ConsumerKeeper"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"Please check the list below if you are using any of the consumer methods:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-go",children:"type StakingKeeper interface {\n UnbondingTime(ctx context.Context) (time.Duration, error)\n GetValidatorByConsAddr(ctx context.Context, consAddr sdk.ConsAddress) (stakingtypes.Validator, error)\n GetLastValidatorPower(ctx context.Context, operator sdk.ValAddress) (int64, error)\n Jail(context.Context, sdk.ConsAddress) error // jail a validator\n Slash(ctx context.Context, consAddr sdk.ConsAddress, infractionHeight, power int64, slashFactor math.LegacyDec) (math.Int, error)\n SlashWithInfractionReason(ctx context.Context, consAddr sdk.ConsAddress, infractionHeight, power int64, slashFactor math.LegacyDec, infraction stakingtypes.Infraction) (math.Int, error)\n Unjail(ctx context.Context, addr sdk.ConsAddress) error\n GetValidator(ctx context.Context, addr sdk.ValAddress) (stakingtypes.Validator, error)\n IterateLastValidatorPowers(ctx context.Context, cb func(addr sdk.ValAddress, power int64) (stop bool)) error\n IterateValidators(ctx context.Context, f func(index int64, validator stakingtypes.ValidatorI) (stop bool)) error\n Validator(ctx context.Context, addr sdk.ValAddress) (stakingtypes.ValidatorI, error)\n IsValidatorJailed(ctx context.Context, addr sdk.ConsAddress) (bool, error)\n ValidatorByConsAddr(ctx context.Context, consAddr sdk.ConsAddress) (stakingtypes.ValidatorI, error)\n Delegation(ctx context.Context, addr sdk.AccAddress, valAddr sdk.ValAddress) (stakingtypes.DelegationI, error)\n MaxValidators(ctx context.Context) (uint32, error)\n}\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The consumer implements the ",(0,s.jsx)(n.code,{children:"StakingKeeper"})," interface shown above."]}),"\n",(0,s.jsx)(n.h2,{id:"democracy",children:"Democracy"}),"\n",(0,s.jsxs)(n.p,{children:["Changes in ",(0,s.jsx)(n.code,{children:"Consumer"})," also apply to ",(0,s.jsx)(n.code,{children:"Democracy"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["Democracy ",(0,s.jsx)(n.code,{children:"x/staking"}),", ",(0,s.jsx)(n.code,{children:"x/distribution"})," and ",(0,s.jsx)(n.code,{children:"x/gov"})," were updated to reflect changes in ",(0,s.jsx)(n.code,{children:"cosmos-sdk v0.50.x"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["There were no notable changes arising to the module functionality aside from conforming to ",(0,s.jsx)(n.code,{children:"cosmos-sdk v0.50.x"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"note",children:"Note:"}),"\n",(0,s.jsxs)(n.p,{children:["You must add ",(0,s.jsx)(n.code,{children:'"/interchain_security.ccv.consumer.v1.MsgUpdateParams"'})," to your parameters whitelist to be able to change ",(0,s.jsx)(n.code,{children:"consumer"})," parameters via governance."]})]})}function p(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},1151:(e,n,r)=>{r.d(n,{Z:()=>t,a:()=>a});var s=r(7294);const i={},o=s.createContext(i);function a(e){const n=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function t(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/425bba28.90680342.js b/assets/js/425bba28.90680342.js new file mode 100644 index 0000000000..03fe5f3e83 --- /dev/null +++ b/assets/js/425bba28.90680342.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1118],{737:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>c,contentTitle:()=>s,default:()=>l,frontMatter:()=>o,metadata:()=>a,toc:()=>d});var i=r(5893),t=r(1151);const o={sidebar_position:6},s="Consumer Genesis Transformation",a={id:"consumer-development/consumer-genesis-transformation",title:"Consumer Genesis Transformation",description:"Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentation on Onboarding and Changeover).",source:"@site/docs/consumer-development/consumer-genesis-transformation.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-genesis-transformation",permalink:"/interchain-security/consumer-development/consumer-genesis-transformation",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"tutorialSidebar",previous:{title:"Changeover Procedure",permalink:"/interchain-security/consumer-development/changeover-procedure"},next:{title:"Overview",permalink:"/interchain-security/validators/overview"}},c={},d=[{value:"1. Prerequisite",id:"1-prerequisite",level:2},{value:"2. Export the CCV data",id:"2-export-the-ccv-data",level:2},{value:"3. Transform CCV data",id:"3-transform-ccv-data",level:2}];function h(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,t.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"consumer-genesis-transformation",children:"Consumer Genesis Transformation"}),"\n",(0,i.jsxs)(n.p,{children:["Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentation on ",(0,i.jsx)(n.a,{href:"/interchain-security/consumer-development/onboarding",children:"Onboarding"})," and ",(0,i.jsx)(n.a,{href:"/interchain-security/consumer-development/changeover-procedure",children:"Changeover"}),").\nIn case that the provider chain is running an older version of the InterChainSecurity (ICS) module than the consumer chain - or vice versa - the exported CCV data might need to be transformed to the format supported by the ICS implementation run on the consumer chain. This is the case if the consumer chain runs version 4 of ICS or later and the provider is running version 3 or older of the ICS module."]}),"\n",(0,i.jsxs)(n.p,{children:["Check the ",(0,i.jsx)(n.a,{href:"../../../RELEASES.md#backwards-compatibility",children:"compatibility notes"})," for known incompatibilities between provider and consumer versions and indications if a consumer genesis transformation is required."]}),"\n",(0,i.jsx)(n.p,{children:"To transform such CCV data follow the instructions below"}),"\n",(0,i.jsx)(n.h2,{id:"1-prerequisite",children:"1. Prerequisite"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["used provider and consumer versions require transformation step as indicated in in the ",(0,i.jsx)(n.a,{href:"../../../RELEASES.md#backwards-compatibility",children:"compatibility notes"})]}),"\n",(0,i.jsx)(n.li,{children:"interchain-security-cd application supports the versions used by the consumer and provider"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"2-export-the-ccv-data",children:"2. Export the CCV data"}),"\n",(0,i.jsxs)(n.p,{children:["Export the CCV data from the provider chain as described in the ",(0,i.jsx)(n.a,{href:"/interchain-security/consumer-development/onboarding",children:"Onboarding"})," and ",(0,i.jsx)(n.a,{href:"/interchain-security/consumer-development/changeover-procedure",children:"Changeover"})," your following.\nAs a result the CCV data will be stored in a file in JSON format."]}),"\n",(0,i.jsx)(n.h2,{id:"3-transform-ccv-data",children:"3. Transform CCV data"}),"\n",(0,i.jsx)(n.p,{children:"To transform the CCV data"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["to the format supported by the current version of the consumer run the following command:","\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"interchain-security-cd genesis transform [genesis-file]\n"})}),"\n","where 'genesis-file' is the path to the file containing the CCV data exported in ",(0,i.jsx)(n.a,{href:"#2-export-the-ccv-data",children:"step 2"}),".\nAs a result the CCV data in the new format will be written to standard output."]}),"\n",(0,i.jsxs)(n.li,{children:["a specific target version of a consumer run the following command:","\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"interchain-security-cd genesis transform --to <target_version> [genesis-file]\n\n"})}),"\n","where ",(0,i.jsx)(n.code,{children:"<target_version"})," is the ICS version the consumer chain is running.\nUse ",(0,i.jsx)(n.code,{children:"interchain-security-cd genesis transform --help"})," to get more details about supported target versions and more."]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Use the new CCV data as described in the procedure you're following."})]})}function l(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},1151:(e,n,r)=>{r.d(n,{Z:()=>a,a:()=>s});var i=r(7294);const t={},o=i.createContext(t);function s(e){const n=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:s(e.components),i.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/434502c4.8d5a5d14.js b/assets/js/434502c4.8d5a5d14.js new file mode 100644 index 0000000000..c83f6410a1 --- /dev/null +++ b/assets/js/434502c4.8d5a5d14.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[411],{854:(n,e,i)=>{i.r(e),i.d(e,{assets:()=>d,contentTitle:()=>t,default:()=>p,frontMatter:()=>o,metadata:()=>a,toc:()=>h});var r=i(5893),s=i(1151);const o={sidebar_position:4},t="Consumer Initiated Slashing",a={id:"features/slashing",title:"Consumer Initiated Slashing",description:"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the Interchain Security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.",source:"@site/versioned_docs/version-v5.0.0/features/slashing.md",sourceDirName:"features",slug:"/features/slashing",permalink:"/interchain-security/v5.0.0/features/slashing",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"ICS Provider Proposals",permalink:"/interchain-security/v5.0.0/features/proposals"},next:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/v5.0.0/consumer-development/app-integration"}},d={},h=[{value:"Downtime Infractions",id:"downtime-infractions",level:2},{value:"Equivocation Infractions",id:"equivocation-infractions",level:2},{value:"Report equivocation infractions through CLI",id:"report-equivocation-infractions-through-cli",level:3},{value:"Report equivocation infractions with Hermes",id:"report-equivocation-infractions-with-hermes",level:3}];function c(n){const e={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,s.a)(),...n.components},{Details:i}=e;return i||function(n,e){throw new Error("Expected "+(e?"component":"object")+" `"+n+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(e.h1,{id:"consumer-initiated-slashing",children:"Consumer Initiated Slashing"}),"\n",(0,r.jsx)(e.p,{children:"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the Interchain Security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.\nIn essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake)."}),"\n",(0,r.jsx)(e.p,{children:"To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized.\nAny infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains."}),"\n",(0,r.jsx)(e.p,{children:"In the current implementation there are two important changes brought by the Interchain Security module."}),"\n",(0,r.jsx)(e.h2,{id:"downtime-infractions",children:"Downtime Infractions"}),"\n",(0,r.jsx)(e.p,{children:"Downtime infractions are reported by consumer chains and are acted upon on the provider as soon as the provider receives the infraction evidence."}),"\n",(0,r.jsx)(e.p,{children:"Instead of slashing, the provider will only jail offending validator for the duration of time established by the chain parameters."}),"\n",(0,r.jsx)(e.admonition,{type:"info",children:(0,r.jsxs)(e.p,{children:[(0,r.jsx)(e.a,{href:"/interchain-security/v5.0.0/adrs/adr-002-throttle",children:"Slash throttling"})," (sometimes called jail throttling) mechanism ensures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider."]})}),"\n",(0,r.jsx)(e.h2,{id:"equivocation-infractions",children:"Equivocation Infractions"}),"\n",(0,r.jsxs)(e.p,{children:["Equivocation infractions are reported by external agents (e.g., relayers) that can submit to the provider evidence of light client or double signing attacks observed on a consumer chain.\nThe evidence is submitted by sending ",(0,r.jsx)(e.code,{children:"MsgSubmitConsumerMisbehaviour"})," or ",(0,r.jsx)(e.code,{children:"MsgSubmitConsumerDoubleVoting"})," transactions to the provider.\nWhen valid evidence is received, the malicious validators are slashed, jailed, and tombstoned on the provider.\nThis is enabled through the ",(0,r.jsx)(e.em,{children:"cryptographic verification of equivocation"})," feature.\nFor more details, see ",(0,r.jsx)(e.a,{href:"/interchain-security/v5.0.0/adrs/adr-005-cryptographic-equivocation-verification",children:"ADR-005"})," and ",(0,r.jsx)(e.a,{href:"/interchain-security/v5.0.0/adrs/adr-013-equivocation-slashing",children:"ADR-013"}),"."]}),"\n",(0,r.jsx)(e.h3,{id:"report-equivocation-infractions-through-cli",children:"Report equivocation infractions through CLI"}),"\n",(0,r.jsx)(e.p,{children:"The ICS provider module offers two commands for submitting evidence of misbehavior originating from a consumer chain.\nBelow are two examples illustrating the process on Cosmos Hub."}),"\n",(0,r.jsx)(e.p,{children:"Use the following command to submit evidence of double signing attacks:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"gaiad tx provider submit-consumer-double-voting [path/to/evidence.json] [path/to/infraction_header.json] --from node0 --home ../node0 --chain-id $CID \n"})}),"\n",(0,r.jsxs)(i,{children:[(0,r.jsxs)("summary",{children:["Example of ",(0,r.jsx)(e.code,{children:"evidence.json"})]}),(0,r.jsx)("div",{children:(0,r.jsx)("div",{children:(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-json",children:'{\n "vote_a": {\n "type": 1,\n "height": 25,\n "round": 0,\n "block_id": {\n "hash": "tBBWTqjECl31S/clZGoxLdDqs93kTvy3qhpPqET/laY=",\n "part_set_header": {\n "total": 1,\n "hash": "ai2qCLgVZAFph4FJ4Cqw5QW1GZKR4zjOv0bI/Um5AIc="\n }\n },\n "timestamp": "2023-11-20T12:57:54.565207Z",\n "validator_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",\n "signature": "y9yILm9hmv45BZwAaaq9mS1FpH7QeAIJ5Jkcc3U2/k5uks9cuqr4NTIwaIrqMSMKwxVyqiR56xmCT59a6AngAA=="\n },\n "vote_b": {\n "type": 1,\n "height": 25,\n "round": 0,\n "block_id": {\n "hash": "3P06pszgPatuIdLTP5fDWiase4SYHIq9YXGSbRk9/50=",\n "part_set_header": {\n "total": 1,\n "hash": "S+SbOMxFRzfeNNpX9/jyFMz94VwBKk7Dpx6ZyvSYyNU="\n }\n },\n "timestamp": "2023-11-20T12:57:54.599273Z",\n "validator_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",\n "validator_index": 0,\n "signature": "DGFcn4Um1t2kXW60+JhMk5cj7ZFdE5goKVOGiZkLwnNv43+6aGmOWjoq0SHYVzM4MwSwOwbhgZNbkWX+EHGUBw=="\n },\n "total_voting_power": 300,\n "validator_power": 100,\n "timestamp": "2023-11-20T12:57:51.267308Z"\n}\n'})})})})]}),"\n",(0,r.jsxs)(i,{children:[(0,r.jsxs)("summary",{children:["Example of ",(0,r.jsx)(e.code,{children:"infraction_header.json"})]}),(0,r.jsx)("div",{children:(0,r.jsx)("div",{children:(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-json",children:'{\n "signed_header": {\n "header": {\n "version": {\n "block": 11,\n "app": 2\n },\n "chain_id": "consumer",\n "height": 22,\n "time": "2023-11-20T12:57:40.479686Z",\n "last_block_id": {\n "hash": "L63hyLJ+y9+fpb7WYKdmmBhPHwbfEGQEuKmvGzyBPiY=",\n "part_set_header": {\n "total": 18,\n "hash": "euzRQjN7MjGtM6skXM4B8wOgAldWGfZSJRA9JRlO42s="\n }\n },\n "last_commit_hash": "qdDJwVziW3pPqmf8QDGZG+5HVd3OF7fCVh2Z8KQqNVU=",\n "data_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",\n "validators_hash": "pVc+gSYkGesaP3OkK4ig3DBi4o9/GCdXGtO/PQ6i/Ik=",\n "next_validators_hash": "pVc+gSYkGesaP3OkK4ig3DBi4o9/GCdXGtO/PQ6i/Ik=",\n "consensus_hash": "BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8=",\n "app_hash": "Yu3HX62w7orbbY/pm2QEK7yIwR+AlNdjSSqiK1kmuJM=",\n "last_results_hash": "Yu3HX62w7orbbY/pm2QEK7yIwR+AlNdjSSqiK1kmuJM=",\n "evidence_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",\n "proposer_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA="\n },\n "commit": {\n "height": 22,\n "round": 1,\n "block_id": {\n "hash": "PKrS32IEZoFY2q2S3iQ68HQL751ieBhf5Eu/Y5Z/QPg=",\n "part_set_header": {\n "total": 1,\n "hash": "8UuA7Oqw5AH/KOacpmHVSMOIDe4l2eC8VmdH2mzcpiM="\n }\n },\n "signatures": [\n {\n "block_id_flag": 2,\n "validator_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",\n "timestamp": "2023-11-20T12:57:44.076538Z",\n "signature": "bSOH4+Vg2I37zeJphOguGOD0GK3JzM1ghSgJd0UlW/DHn1u9Hvv4EekHuCu6qwRLZcuS/ZxNlmr9qYNfxX3bDA=="\n },\n {\n "block_id_flag": 2,\n "validator_address": "i/A830FM7cfmA8yTn9n3xBg5XpU=",\n "timestamp": "2020-01-02T00:07:00Z",\n "signature": "7bXSDtlOwGK/gLEsFpTWOzm2TFoaARrWQUpbgWEwKtLlUs7iE06TOvJ3yPPfTfqqN/qYnvxxgjl0M0EhUWu5Bg=="\n },\n {\n "block_id_flag": 2,\n "validator_address": "lrQDkJ2fk7UAgNzRZfcwMKSYa2E=",\n "timestamp": "2023-11-20T12:57:44.076519Z",\n "signature": "Pb6G4bCg4wafmV89WNnzXxbSCknZUHnSQfSCE5QMFxPtSUIN4A7SK5m7yltqMJF5zkyenlFiEI4J3OZ4KCjCAw=="\n },\n {\n "block_id_flag": 2,\n "validator_address": "+R94nXSeM1Z49e/CXpyHT3M+h3k=",\n "timestamp": "2023-11-20T12:57:44.057451Z",\n "signature": "j3EasIHNYA6MxW/PiWyruzHsjVsBV9t11W6Qx800WMm/+P+CkfR+UZAp7MPTvKZEZFuh3GUsBtyfb/vA+jJWCw=="\n }\n ]\n }\n },\n "validator_set": {\n "validators": [\n {\n "address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",\n "pub_key": {\n "ed25519": "dtn+SfD+4QLo0+t0hAoP6Q2sGjh0XEI3LWVG+doh3u0="\n },\n "voting_power": 100,\n "proposer_priority": -200\n },\n {\n "address": "lrQDkJ2fk7UAgNzRZfcwMKSYa2E=",\n "pub_key": {\n "ed25519": "UgN2JsjPy2WLh7dzJRBkUQtdgNoT4/uGj7kbIVqqHT8="\n },\n "voting_power": 100,\n "proposer_priority": 100\n },\n {\n "address": "+R94nXSeM1Z49e/CXpyHT3M+h3k=",\n "pub_key": {\n "ed25519": "5svW8261x+cZosp2xIhqzgt2tyuawrSDyHlpbgS3BC4="\n },\n "voting_power": 100,\n "proposer_priority": 100\n },\n {\n "address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",\n "pub_key": {\n "ed25519": "dtn+SfD+4QLo0+t0hAoP6Q2sGjh0XEI3LWVG+doh3u0="\n },\n "voting_power": 100,\n "proposer_priority": -200\n }\n ],\n "proposer": {\n "address": "VUz+QceJ8Nu7GbJuVItwsfVjybA=",\n "pub_key": {\n "ed25519": "0s8KDTgEcwmOBrHWvV7mtBlItJ3upgM1FJsciwREdy4="\n },\n "voting_power": 1,\n "proposer_priority": -3\n }\n },\n "trusted_height": {\n "revision_height": 18\n },\n "trusted_validators": {\n "validators": [\n {\n "address": "VUz+QceJ8Nu7GbJuVItwsfVjybA=",\n "pub_key": {\n "ed25519": "0s8KDTgEcwmOBrHWvV7mtBlItJ3upgM1FJsciwREdy4="\n },\n "voting_power": 1,\n "proposer_priority": -3\n },\n {\n "address": "i/A830FM7cfmA8yTn9n3xBg5XpU=",\n "pub_key": {\n "ed25519": "FCmIw7hSuiAoWk/2f4LuGQ+3zx5101xiqU8DoC5wGkg="\n },\n "voting_power": 1,\n "proposer_priority": 1\n },\n {\n "address": "2DrZF0roNnnvEy4NS2aY811ncKg=",\n "pub_key": {\n "ed25519": "MI9c6sphsWlx0RAHCYOjMRXMFkTUaEYwOiOKG/0tsMs="\n },\n "voting_power": 1,\n "proposer_priority": 1\n },\n {\n "address": "73aN0uOc5b/Zfq2Xcjl0kH2r+tw=",\n "pub_key": {\n "ed25519": "gWNcDup4mdnsuqET4QeFRzVb+FnSP4Vz3iNMj5wvWXk="\n },\n "voting_power": 1,\n "proposer_priority": 1\n }\n ],\n "proposer": {\n "address": "VUz+QceJ8Nu7GbJuVItwsfVjybA=",\n "pub_key": {\n "ed25519": "0s8KDTgEcwmOBrHWvV7mtBlItJ3upgM1FJsciwREdy4="\n },\n "voting_power": 1,\n "proposer_priority": -3\n }\n }\n}\n'})})})})]}),"\n",(0,r.jsx)(e.p,{children:"Use the following command to submit evidence of light client attacks:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"gaiad tx provider submit-consumer-misbehaviour [path/to/misbehaviour.json] --from node0 --home ../node0 --chain-id $CID\n"})}),"\n",(0,r.jsxs)(i,{children:[(0,r.jsxs)("summary",{children:["Example of ",(0,r.jsx)(e.code,{children:"misbehaviour.json"})]}),(0,r.jsx)("div",{children:(0,r.jsx)("div",{children:(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-json",children:'{\n "client_id": "07-tendermint-0",\n "header_1": {\n "signed_header": {\n "header": {\n "version": {\n "block": "11",\n "app": "2"\n },\n "chain_id": "testchain2",\n "height": "19",\n "time": "2020-01-02T00:08:10Z",\n "last_block_id": {\n "hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",\n "part_set_header": {\n "total": 10000,\n "hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="\n }\n },\n "last_commit_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",\n "data_hash": "bW4ouLmLUycELqUKV91G5syFHHLlKL3qpu/e7v5moLg=",\n "validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",\n "next_validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",\n "consensus_hash": "5eVmxB7Vfj/4zBDxhBeHiLj6pgKwfPH0JSF72BefHyQ=",\n "app_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",\n "last_results_hash": "CS4FhjAkftYAmGOhLu4RfSbNnQi1rcqrN/KrNdtHWjc=",\n "evidence_hash": "c4ZdsI9J1YQokF04mrTKS5bkWjIGx6adQ6Xcc3LmBxQ=",\n "proposer_address": "CbKqPquy50bcrY7JRdW7zXybSuA="\n },\n "commit": {\n "height": "19",\n "round": 1,\n "block_id": {\n "hash": "W2xVqzPw03ZQ1kAMpcpht9WohwMzsGnyKKNjPYKDF6U=",\n "part_set_header": {\n "total": 3,\n "hash": "hwgKOc/jNqZj6lwNm97vSTq9wYt8Pj4MjmYTVMGDFDI="\n }\n },\n "signatures": [\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "timestamp": "2020-01-02T00:08:10Z",\n "signature": "PGTquCtnTNFFY5HfEFz9f9pA7PYqjtQfBwHq6cxF/Ux8OI6nVqyadD9a84Xm7fSm6mqdW+T6YVfqIKmIoRjJDQ=="\n },\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",\n "timestamp": "2020-01-02T00:08:10Z",\n "signature": "0e39yoBorwORAH/K9qJ7D1N1Yr7CutMiQJ+oiIK39eMhuoK3UWzQyMGRLzDOIDupf8yD99mvGVVAlNIODlV3Dg=="\n },\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",\n "timestamp": "2020-01-02T00:08:10Z",\n "signature": "lhc2tkwydag9D1iLQhdDCE8GgrHP94M1LbHFYMoL9tExaEq6RiFW/k71TQH5x96XQ9XYOznMIHKC2BDh4GlnAQ=="\n },\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",\n "timestamp": "2020-01-02T00:08:10Z",\n "signature": "8xeSBf0nSFs/X/rQ9CZLzwkJJhQBLA2jKdPGP3MlULxm992XxrOsIYq47u1daxvSsn6ql5OVYjzBNU0qbPpvCA=="\n }\n ]\n }\n },\n "validator_set": {\n "validators": [\n {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n {\n "address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",\n "pub_key": {\n "ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",\n "pub_key": {\n "ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",\n "pub_key": {\n "ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n }\n ],\n "proposer": {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n "total_voting_power": "0"\n },\n "trusted_height": {\n "revision_number": "0",\n "revision_height": "18"\n },\n "trusted_validators": {\n "validators": [\n {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n {\n "address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",\n "pub_key": {\n "ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",\n "pub_key": {\n "ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",\n "pub_key": {\n "ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n }\n ],\n "proposer": {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n "total_voting_power": "0"\n }\n },\n "header_2": {\n "signed_header": {\n "header": {\n "version": {\n "block": "11",\n "app": "2"\n },\n "chain_id": "testchain2",\n "height": "19",\n "time": "2020-01-02T00:08:20Z",\n "last_block_id": {\n "hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",\n "part_set_header": {\n "total": 10000,\n "hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="\n }\n },\n "last_commit_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",\n "data_hash": "bW4ouLmLUycELqUKV91G5syFHHLlKL3qpu/e7v5moLg=",\n "validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",\n "next_validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",\n "consensus_hash": "5eVmxB7Vfj/4zBDxhBeHiLj6pgKwfPH0JSF72BefHyQ=",\n "app_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",\n "last_results_hash": "CS4FhjAkftYAmGOhLu4RfSbNnQi1rcqrN/KrNdtHWjc=",\n "evidence_hash": "c4ZdsI9J1YQokF04mrTKS5bkWjIGx6adQ6Xcc3LmBxQ=",\n "proposer_address": "CbKqPquy50bcrY7JRdW7zXybSuA="\n },\n "commit": {\n "height": "19",\n "round": 1,\n "block_id": {\n "hash": "IZM8NKS+8FHB7CBmgB8Nz7BRVVXiiyqMQDvHFUvgzxo=",\n "part_set_header": {\n "total": 3,\n "hash": "hwgKOc/jNqZj6lwNm97vSTq9wYt8Pj4MjmYTVMGDFDI="\n }\n },\n "signatures": [\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "timestamp": "2020-01-02T00:08:20Z",\n "signature": "pLIEZ4WSAtnMsgryujheHSq4+YG3RqTfMn2ZxgEymr0wyi+BNlQAKRtRfesm0vfYxvjzc/jhGqtUqHtSIaCwCQ=="\n },\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",\n "timestamp": "2020-01-02T00:08:20Z",\n "signature": "XG7iTe/spWyTUkT7XDzfLMpYqrdyqizE4/X4wl/W+1eaQp0WsCHYnvPU3x9NAnYfZzaKdonZiDWs7wacbZTcDg=="\n },\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",\n "timestamp": "2020-01-02T00:08:20Z",\n "signature": "TqegK7ORuICSy++wVdPHt8fL2WfPlYsMPv1XW79wUdcjnQkezOM50OSqYaP4ua5frIZsn+sWteDrlqFTdkl3BA=="\n },\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",\n "timestamp": "2020-01-02T00:08:20Z",\n "signature": "dhvp3XlIaCxx5MFDs0TCkAPHSm0PS2EtJzYAx2c/7MWdLwUJFZrAUTeimQE2c9i9ro91cjZn/vI0/oFRXab6Aw=="\n }\n ]\n }\n },\n "validator_set": {\n "validators": [\n {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n {\n "address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",\n "pub_key": {\n "ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",\n "pub_key": {\n "ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",\n "pub_key": {\n "ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n }\n ],\n "proposer": {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n "total_voting_power": "0"\n },\n "trusted_height": {\n "revision_number": "0",\n "revision_height": "18"\n },\n "trusted_validators": {\n "validators": [\n {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n {\n "address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",\n "pub_key": {\n "ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",\n "pub_key": {\n "ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",\n "pub_key": {\n "ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n }\n ],\n "proposer": {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n "total_voting_power": "0"\n }\n }\n}\n'})})})})]}),"\n",(0,r.jsx)(e.h3,{id:"report-equivocation-infractions-with-hermes",children:"Report equivocation infractions with Hermes"}),"\n",(0,r.jsxs)(e.p,{children:["Ensure you have a well-configured Hermes ",(0,r.jsx)(e.code,{children:"v1.7.3+"})," relayer effectively relaying packets between a consumer chain and a provider chain.\nThe following command demonstrates how to run a Hermes instance in ",(0,r.jsx)(e.em,{children:"evidence mode"})," to detect misbehaviors on a consumer chain and automatically submit the evidence to the provider chain."]}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"hermes evidence --chain <CONSUMER-CHAIN-ID>\n"})}),"\n",(0,r.jsx)(e.admonition,{type:"tip",children:(0,r.jsxs)(e.p,{children:[(0,r.jsx)(e.code,{children:"hermes evidence"})," takes a ",(0,r.jsx)(e.code,{children:"--check-past-blocks"})," option giving the possibility to look for older evidence (default is 100)."]})})]})}function p(n={}){const{wrapper:e}={...(0,s.a)(),...n.components};return e?(0,r.jsx)(e,{...n,children:(0,r.jsx)(c,{...n})}):c(n)}},1151:(n,e,i)=>{i.d(e,{Z:()=>a,a:()=>t});var r=i(7294);const s={},o=r.createContext(s);function t(n){const e=r.useContext(o);return r.useMemo((function(){return"function"==typeof n?n(e):{...e,...n}}),[e,n])}function a(n){let e;return e=n.disableParentContext?"function"==typeof n.components?n.components(s):n.components||s:t(n.components),r.createElement(o.Provider,{value:e},n.children)}}}]); \ No newline at end of file diff --git a/assets/js/46057b98.17b22c1f.js b/assets/js/46057b98.17b22c1f.js new file mode 100644 index 0000000000..9e0c1af100 --- /dev/null +++ b/assets/js/46057b98.17b22c1f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3159],{8812:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>t,metadata:()=>r,toc:()=>d});var o=i(5893),s=i(1151);const t={sidebar_position:4,title:"Equivocation governance proposal"},a="ADR 003: Equivocation governance proposal",r={id:"adrs/adr-003-equivocation-gov-proposal",title:"Equivocation governance proposal",description:"Changelog",source:"@site/docs/adrs/adr-003-equivocation-gov-proposal.md",sourceDirName:"adrs",slug:"/adrs/adr-003-equivocation-gov-proposal",permalink:"/interchain-security/adrs/adr-003-equivocation-gov-proposal",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Equivocation governance proposal"},sidebar:"tutorialSidebar",previous:{title:"Jail Throttling",permalink:"/interchain-security/adrs/adr-002-throttle"},next:{title:"Cryptographic verification of equivocation evidence",permalink:"/interchain-security/adrs/adr-005-cryptographic-equivocation-verification"}},c={},d=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function l(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"adr-003-equivocation-governance-proposal",children:"ADR 003: Equivocation governance proposal"}),"\n",(0,o.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"2023-02-06: Initial draft"}),"\n",(0,o.jsx)(n.li,{children:"2023-11-30: Change status to deprecated"}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,o.jsx)(n.p,{children:"Deprecated"}),"\n",(0,o.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.strong,{children:"Note:"})," ADR deprecated as the equivocation proposal was removed by the\ncryptographic verification of equivocation feature\n(see ",(0,o.jsx)(n.a,{href:"/interchain-security/adrs/adr-005-cryptographic-equivocation-verification",children:"ADR-005"})," and\n",(0,o.jsx)(n.a,{href:"/interchain-security/adrs/adr-013-equivocation-slashing",children:"ADR-013"}),")."]}),"\n",(0,o.jsx)(n.p,{children:"We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain."}),"\n",(0,o.jsx)(n.p,{children:"For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence."}),"\n",(0,o.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,o.jsx)(n.p,{children:"To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain."}),"\n",(0,o.jsxs)(n.p,{children:["A new kind of governance proposal is added to the ",(0,o.jsx)(n.code,{children:"provider"})," module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain."]}),"\n",(0,o.jsxs)(n.p,{children:["If such proposal passes, the proposal handler delegates to the ",(0,o.jsx)(n.code,{children:"evidence"})," module to process the equivocation. This module ensures the evidence isn\u2019t too old, or else ignores it (see ",(0,o.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/21021b837882d1d40f1d79bcbc4fad2e79a3fefe/x/evidence/keeper/infraction.go#L54-L62",children:"code"}),"). ",(0,o.jsx)(n.em,{children:"Too old"})," is determined by 2 consensus params :"]}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"evidence.max_age_duration"})," number of nanoseconds before an evidence is considered too old"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"evidence.max_age_numblocks"})," number of blocks before an evidence is considered too old."]}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:"On the hub, those parameters are equals to"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-json",children:'// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682\n(...)\n"evidence": {\n\t"max_age_num_blocks": "1000000",\n\t"max_age_duration": "172800000000000",\n (...)\n},\n(...)\n'})}),"\n",(0,o.jsxs)(n.p,{children:["A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the ",(0,o.jsx)(n.code,{children:"evidence"})," module when the proposal passes and is handled by the hub."]}),"\n",(0,o.jsxs)(n.p,{children:["For ",(0,o.jsx)(n.code,{children:"max_age_num_blocks=1M"}),", the parameter is big enough if we consider the hub produces 12k blocks per day (",(0,o.jsx)(n.code,{children:"blocks_per_year/365 = 436,0000/365"}),"). The evidence can be up to 83 days old (",(0,o.jsx)(n.code,{children:"1,000,000/12,000"}),") and not be ignored."]}),"\n",(0,o.jsxs)(n.p,{children:["For ",(0,o.jsx)(n.code,{children:"max_age_duration=172,800,000,000,000"}),", the parameter is too low, because the value is in nanoseconds so it\u2019s 2 days. Fortunately the condition that checks those 2 parameters uses a ",(0,o.jsx)(n.strong,{children:"AND"}),", so if ",(0,o.jsx)(n.code,{children:"max_age_num_blocks"})," condition passes, the evidence won\u2019t be ignored."]}),"\n",(0,o.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,o.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Remove the possibility from a malicious consumer chain to \u201cattack\u201d the provider chain by slashing/jailing validators."}),"\n",(0,o.jsx)(n.li,{children:"Provide a more acceptable implementation for the validator community."}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Punishment action of double-signing isn\u2019t \u201cautomated\u201d, a governance proposal is required which takes more time."}),"\n",(0,o.jsx)(n.li,{children:"You need to pay 250ATOM to submit an equivocation evidence."}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,o.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:["PR that ignores non downtime slash packet : ",(0,o.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/692",children:"https://github.com/cosmos/interchain-security/pull/692"})]}),"\n",(0,o.jsxs)(n.li,{children:["PR that adds the governance slash proposal: ",(0,o.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/703",children:"https://github.com/cosmos/interchain-security/pull/703"})]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>r,a:()=>a});var o=i(7294);const s={},t=o.createContext(s);function a(e){const n=o.useContext(t);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),o.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/491e9485.2134357d.js b/assets/js/491e9485.2134357d.js new file mode 100644 index 0000000000..caa944dcf4 --- /dev/null +++ b/assets/js/491e9485.2134357d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6784],{953:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>o,toc:()=>c});var i=n(5893),s=n(1151);const r={sidebar_position:7,title:"Throttle with retries"},a=void 0,o={id:"adrs/adr-008-throttle-retries",title:"Throttle with retries",description:"ADR 008: Throttle with retries",source:"@site/versioned_docs/version-v5.0.0/adrs/adr-008-throttle-retries.md",sourceDirName:"adrs",slug:"/adrs/adr-008-throttle-retries",permalink:"/interchain-security/v5.0.0/adrs/adr-008-throttle-retries",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:7,frontMatter:{sidebar_position:7,title:"Throttle with retries"},sidebar:"tutorialSidebar",previous:{title:"Cryptographic verification of equivocation evidence",permalink:"/interchain-security/v5.0.0/adrs/adr-005-cryptographic-equivocation-verification"},next:{title:"Soft Opt-Out",permalink:"/interchain-security/v5.0.0/adrs/adr-009-soft-opt-out"}},d={},c=[{value:"ADR 008: Throttle with retries",id:"adr-008-throttle-with-retries",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consumer changes",id:"consumer-changes",level:3},{value:"Consumer pending packets storage optimization",id:"consumer-pending-packets-storage-optimization",level:4},{value:"Provider changes",id:"provider-changes",level:3},{value:"Handling <code>VSCMaturedPackets</code> immediately",id:"handling-vscmaturedpackets-immediately",level:4},{value:"Why the provider can handle VSCMatured packets immediately",id:"why-the-provider-can-handle-vscmatured-packets-immediately",level:4},{value:"Splitting of PRs and Upgrade Order",id:"splitting-of-prs-and-upgrade-order",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function l(e){const t={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h2,{id:"adr-008-throttle-with-retries",children:"ADR 008: Throttle with retries"}),"\n",(0,i.jsx)(t.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"6/9/23: Initial draft"}),"\n",(0,i.jsx)(t.li,{children:"6/22/23: added note on consumer pending packets storage optimization"}),"\n",(0,i.jsx)(t.li,{children:"7/14/23: Added note on upgrade order"}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(t.p,{children:"Accepted"}),"\n",(0,i.jsx)(t.h2,{id:"context",children:"Context"}),"\n",(0,i.jsxs)(t.p,{children:["For context on why the throttling mechanism exists, see ",(0,i.jsx)(t.a,{href:"/interchain-security/v5.0.0/adrs/adr-002-throttle",children:"ADR 002"}),"."]}),"\n",(0,i.jsxs)(t.p,{children:["Note the terms slash throttling and jail throttling are synonymous, since in replicated security a ",(0,i.jsx)(t.code,{children:"SlashPacket"})," simply jails a validator for downtime infractions."]}),"\n",(0,i.jsxs)(t.p,{children:["Currently the throttling mechanism is designed so that provider logic (slash meter, etc.) dictates how many ",(0,i.jsx)(t.code,{children:"SlashPackets"})," can be handled over time.\nThrottled ",(0,i.jsx)(t.code,{children:"SlashPackets"})," are persisted on the provider, leading to multiple possible issues. Namely:"]}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:["If ",(0,i.jsx)(t.code,{children:"SlashPackets"})," or ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," are actually throttled/queued on the provider, state can grow and potentially lead to a DoS attack.\nWe have short term solutions around this, but overall they come with their own weaknesses.\nSee ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/issues/594",children:"#594"}),"."]}),"\n",(0,i.jsxs)(t.li,{children:["If a jailing attack described in ",(0,i.jsx)(t.a,{href:"/interchain-security/v5.0.0/adrs/adr-002-throttle",children:"ADR 002"})," were actually to be carried out with the current throttling design, we'd likely have to halt the provider, and perform an emergency upgrade and/or migration to clear the queues of ",(0,i.jsx)(t.code,{children:"SlashPackets"})," that were deemed to be malicious.\nAlternatively, validators would just have to ",(0,i.jsx)(t.em,{children:"tough it out"})," and wait for the queues to clear, during which all/most validators would be jailed.\nRight after being jailed, validators would have to unjail themselves promptly to ensure safety.\nThe coordination required to maintain safety in such a scenario is not ideal."]}),"\n"]}),"\n",(0,i.jsx)(t.p,{children:"As a solution, we can improve the throttling mechanism to instead queue/persist relevant data on each consumer, and have consumers retry slash requests as needed."}),"\n",(0,i.jsx)(t.h2,{id:"decision",children:"Decision"}),"\n",(0,i.jsx)(t.h3,{id:"consumer-changes",children:"Consumer changes"}),"\n",(0,i.jsxs)(t.p,{children:["Note the consumer already queues up both ",(0,i.jsx)(t.code,{children:"SlashPackets"})," and ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," via ",(0,i.jsx)(t.code,{children:"AppendPendingPacket"}),".\nThose packets are dequeued in every ",(0,i.jsx)(t.code,{children:"EndBlock"})," in ",(0,i.jsx)(t.code,{children:"SendPackets"})," and sent to the provider."]}),"\n",(0,i.jsxs)(t.p,{children:["Instead, we will now introduce the following logic on ",(0,i.jsx)(t.code,{children:"EndBlock"}),":"]}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:["Slash packets will always be sent to the provider once they're at the head of the queue.\nHowever, once sent, the consumer will not send any subsequent ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," from the queue until the provider responds with an acknowledgement that the sent ",(0,i.jsx)(t.code,{children:"SlashPacket"})," has been handled, i.e., validator was jailed.\nThat is, ",(0,i.jsx)(t.code,{children:"SlashPackets"})," block the sending of subsequent ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," in the consumer queue."]}),"\n",(0,i.jsxs)(t.li,{children:["If two ",(0,i.jsx)(t.code,{children:"SlashPackets"})," are at the head of the queue, the consumer will send the first ",(0,i.jsx)(t.code,{children:"SlashPacket"}),", and then wait for a success acknowledgement from the provider before sending the second ",(0,i.jsx)(t.code,{children:"SlashPacket"}),".\nThis seems like it'd simplify implementation."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," at the head of the queue (i.e., NOT following a ",(0,i.jsx)(t.code,{children:"SlashPacket"}),") can be sent immediately, and do not block any other packets in the queue, since the provider always handles them immediately."]}),"\n"]}),"\n",(0,i.jsxs)(t.p,{children:["To prevent the provider from having to keep track of what ",(0,i.jsx)(t.code,{children:"SlashPackets"})," have been rejected, the consumer will have to retry the sending of ",(0,i.jsx)(t.code,{children:"SlashPackets"})," over some period of time.\nThis can be achieved with an on-chain consumer param, i.e., ",(0,i.jsx)(t.code,{children:"RetryDelayPeriod"}),".\nTo reduce the amount of redundant re-sends, we recommend setting ",(0,i.jsx)(t.code,{children:"RetryDelayPeriod ~ SlashMeterReplenishmentPeriod"}),", i.e., waiting for the provider slash meter to be replenished before resending the rejected ",(0,i.jsx)(t.code,{children:"SlashPacket"}),"."]}),"\n",(0,i.jsx)(t.p,{children:"Note to prevent weird edge case behavior, a retry would not be attempted until either a success or failure acknowledgement has been received from the provider."}),"\n",(0,i.jsxs)(t.p,{children:["With the behavior described, we maintain very similar behavior to the previous throttling mechanism regarding the timing that ",(0,i.jsx)(t.code,{children:"SlashPackets"})," and ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," are handled on the provider.\nObviously the queueing and blocking logic is moved, and the two chains would have to send more messages between one another (only in the case the throttling mechanism is triggered)."]}),"\n",(0,i.jsxs)(t.p,{children:["In the normal case, when no or a few ",(0,i.jsx)(t.code,{children:"SlashPackets"})," are being sent, the ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," will not be delayed, and hence unbonding will not be delayed."]}),"\n",(0,i.jsxs)(t.p,{children:["For the implementation of this design, see ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/fec3eccad59416cbdb6844e279f59e3f81242888/x/ccv/consumer/keeper/throttle_retry.go",children:"throttle_retry.go"}),"."]}),"\n",(0,i.jsx)(t.h4,{id:"consumer-pending-packets-storage-optimization",children:"Consumer pending packets storage optimization"}),"\n",(0,i.jsx)(t.p,{children:"In addition to the mentioned consumer changes, an optimization will need to be made to the consumer's pending packets storage to properly implement the feature from this ADR."}),"\n",(0,i.jsxs)(t.p,{children:['The consumer ccv module previously queued "pending packets" to be sent in each ',(0,i.jsx)(t.code,{children:"EndBlock"})," in ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/3bc4e7135066d848aac60b0787364c07157fd36d/x/ccv/consumer/keeper/relay.go#L178",children:"SendPackets"}),".\nThese packets are queued in state with a protobuf list of ",(0,i.jsx)(t.code,{children:"ConsumerPacketData"}),".\nFor a single append operation, the entire list is deserialized, then a packet is appended to that list, and the list is serialized again.\nSee older version of ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/05c2dae7c6372b1252b9e97215d07c6aa7618f33/x/ccv/consumer/keeper/keeper.go#L606",children:"AppendPendingPacket"}),".\nThat is, a single append operation has O(N) complexity, where N is the size of the list."]}),"\n",(0,i.jsxs)(t.p,{children:["This poor append performance isn't a problem when the pending packets list is small.\nBut with this ADR being implemented, the pending packets list could potentially grow to the order of thousands of entries when ",(0,i.jsx)(t.code,{children:"SlashPackets"})," need to be resent."]}),"\n",(0,i.jsx)(t.p,{children:"We can improve the append time for this queue by converting it from a protobuf-esq list, to a queue implemented with sdk-esq code.\nThe idea is to persist a uint64 index that will be incremented each time you queue up a packet.\nYou can think of this as storing the tail of the queue.\nThen, packet data will be keyed by that index, making the data naturally ordered byte-wise for sdk's iterator.\nThe index will also be stored in the packet data value bytes, so that the index can later be used to delete certain packets from the queue."}),"\n",(0,i.jsx)(t.p,{children:"Two things are achieved with this approach:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"More efficient packet append/enqueue times"}),"\n",(0,i.jsx)(t.li,{children:"The ability to delete select packets from the queue (previously all packets were deleted at once)"}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"provider-changes",children:"Provider changes"}),"\n",(0,i.jsxs)(t.p,{children:["The main change needed for the provider is the removal of queuing logic for ",(0,i.jsx)(t.code,{children:"SlashPackets"})," and ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," upon being received."]}),"\n",(0,i.jsxs)(t.p,{children:["Instead, the provider will consult the slash meter to determine if a ",(0,i.jsx)(t.code,{children:"SlashPacket"})," can be handled immediately.\nIf not, the provider will return an acknowledgement message to the consumer communicating that the ",(0,i.jsx)(t.code,{children:"SlashPacket"})," could not be handled, and needs to be sent again in the future (retried)."]}),"\n",(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," will always be handled immediately upon being received by the provider."]}),"\n",(0,i.jsxs)(t.p,{children:["Note ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing",children:"spec"}),". Specifically the section on ",(0,i.jsx)(t.em,{children:"VSC Maturity and Slashing Order"}),". Previously the onus was on the provider to maintain this property via queuing packets and handling them FIFO."]}),"\n",(0,i.jsxs)(t.p,{children:["Now this property will be maintained by the consumer sending packets in the correct order, and blocking the sending of ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," as needed. Then, the ordered IBC channel will ensure that ",(0,i.jsx)(t.code,{children:"SlashPackets"})," and ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," are received in the correct order on the provider."]}),"\n",(0,i.jsxs)(t.p,{children:["The provider's main responsibility regarding throttling will now be to determine if a received ",(0,i.jsx)(t.code,{children:"SlashPacket"})," can be handled via slash meter etc., and appropriately acknowledge to the sending consumer."]}),"\n",(0,i.jsxs)(t.h4,{id:"handling-vscmaturedpackets-immediately",children:["Handling ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," immediately"]}),"\n",(0,i.jsx)(t.h4,{id:"why-the-provider-can-handle-vscmatured-packets-immediately",children:"Why the provider can handle VSCMatured packets immediately"}),"\n",(0,i.jsxs)(t.p,{children:["A ",(0,i.jsx)(t.code,{children:"VSCMaturedPacket"})," communicates to the provider that sufficient time passed on the consumer since the corresponding ",(0,i.jsx)(t.code,{children:"VSCPacket"})," has been applied (on the consumer) such that infractions committed on the consumer could have been submitted."]}),"\n",(0,i.jsxs)(t.p,{children:["If the consumer is following the queuing/blocking protocol described, then no bad behavior occurs and the ",(0,i.jsx)(t.em,{children:"VSC Maturity and Slashing Order"})," property is maintained."]}),"\n",(0,i.jsxs)(t.p,{children:["If a consumer sends ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," too leniently -- the consumer is malicious and sends duplicate ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"}),", or sends the packets sooner than the CCV protocol specifies -- then the provider needs to handle ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," immediately to prevent DOS, state bloat, or other issues.\nThe only possible negative outcome is that the malicious consumer may not be able to jail a validator who should have been jailed.\nThe malicious behavior only creates a negative outcome for the consumer chain that is being malicious."]}),"\n",(0,i.jsxs)(t.p,{children:["If a consumer blocks the sending of ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"}),", then unbonding operations on the provider will be delayed, but only until the VSC timeout period has elapsed.\nAt that time, the consumer is removed.\nAgain the malicious behavior only creates a negative outcome for the consumer chain that is being malicious."]}),"\n",(0,i.jsx)(t.h3,{id:"splitting-of-prs-and-upgrade-order",children:"Splitting of PRs and Upgrade Order"}),"\n",(0,i.jsxs)(t.p,{children:["This feature will implement consumer changes in ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/pull/1024",children:"#1024"}),"."]}),"\n",(0,i.jsxs)(t.p,{children:["\u2757",(0,i.jsx)(t.em,{children:(0,i.jsx)(t.strong,{children:"These changes should be deployed to production for all consumers before the provider changes are deployed to production."})})]}),"\n",(0,i.jsxs)(t.p,{children:["In other words, the consumer changes in ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/pull/1024",children:"#1024"}),' are compatible with the current ("v1") provider implementation of throttling that\'s running on the Cosmos Hub as of July 2023.']}),"\n",(0,i.jsxs)(t.p,{children:["Once all consumers have deployed the changes in #1024, the provider changes from ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/pull/1321",children:"#1321"})," can be deployed to production, fully enabling v2 throttling."]}),"\n",(0,i.jsx)(t.h2,{id:"consequences",children:"Consequences"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"Consumers will now have to manage their own queues, and retry logic."}),"\n",(0,i.jsx)(t.li,{children:"Consumers still aren't trustless, but the provider is now less susceptible to mismanaged or malicious consumers."}),"\n",(0,i.jsx)(t.li,{children:'Recovering from the "jailing attack" is more elegant.'}),"\n",(0,i.jsxs)(t.li,{children:["Some issues like ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/issues/1001",children:"#1001"})," will now be handled implicitly by the improved throttling mechanism."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.code,{children:"SlashPackets"})," and ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," can be handled immediately once received by the provider if the slash meter allows."]}),"\n",(0,i.jsxs)(t.li,{children:["In general, we reduce the amount of computation that happens in the provider ",(0,i.jsx)(t.code,{children:"EndBlock"}),"."]}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:['We no longer have to reason about a "global queue" and a "chain specific queue", and keeping those all in-sync.\nNow ',(0,i.jsx)(t.code,{children:"SlashPackets"})," and ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," queuing is handled on each consumer individually."]}),"\n",(0,i.jsx)(t.li,{children:"Due to the above, the throttling protocol becomes less complex overall."}),"\n",(0,i.jsx)(t.li,{children:"We no longer have to worry about throttle related DoS attack on the provider, since no queuing exists on the provider."}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"Increased number of IBC packets being relayed anytime throttling logic is triggered."}),"\n",(0,i.jsx)(t.li,{children:"Consumer complexity increases, since consumers now have manage queuing themselves, and implement packet retry logic."}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"neutral",children:"Neutral"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"Core throttling logic on the provider remains unchanged, i.e., slash meter, replenishment cycles, etc."}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"references",children:"References"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/issues/713",children:"EPIC"})," tracking the changes proposed by this ADR"]}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"/interchain-security/v5.0.0/adrs/adr-002-throttle",children:"ADR 002: Jail Throttling"})}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/issues/594",children:"#594"})}),"\n"]})]})}function h(e={}){const{wrapper:t}={...(0,s.a)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},1151:(e,t,n)=>{n.d(t,{Z:()=>o,a:()=>a});var i=n(7294);const s={},r=i.createContext(s);function a(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/4c7d82ee.1a561975.js b/assets/js/4c7d82ee.1a561975.js new file mode 100644 index 0000000000..eaa82e436c --- /dev/null +++ b/assets/js/4c7d82ee.1a561975.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7649],{1915:(e,i,t)=>{t.r(i),t.d(i,{assets:()=>r,contentTitle:()=>a,default:()=>d,frontMatter:()=>o,metadata:()=>c,toc:()=>h});var n=t(5893),s=t(1151);const o={sidebar_position:4,title:"Cryptographic verification of equivocation evidence"},a="ADR 005: Cryptographic verification of equivocation evidence",c={id:"adrs/adr-005-cryptographic-equivocation-verification",title:"Cryptographic verification of equivocation evidence",description:"Changelog",source:"@site/docs/adrs/adr-005-cryptographic-equivocation-verification.md",sourceDirName:"adrs",slug:"/adrs/adr-005-cryptographic-equivocation-verification",permalink:"/interchain-security/adrs/adr-005-cryptographic-equivocation-verification",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Cryptographic verification of equivocation evidence"},sidebar:"tutorialSidebar",previous:{title:"Equivocation governance proposal",permalink:"/interchain-security/adrs/adr-003-equivocation-gov-proposal"},next:{title:"Throttle with retries",permalink:"/interchain-security/adrs/adr-008-throttle-retries"}},r={},h=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Light Client Attack",id:"light-client-attack",level:3},{value:"Double Signing Attack",id:"double-signing-attack",level:3},{value:"Decision",id:"decision",level:2},{value:"Light Client Attack",id:"light-client-attack-1",level:3},{value:"Double Signing Attack",id:"double-signing-attack-1",level:3},{value:"Current limitations:",id:"current-limitations",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}];function l(e){const i={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,s.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(i.h1,{id:"adr-005-cryptographic-verification-of-equivocation-evidence",children:"ADR 005: Cryptographic verification of equivocation evidence"}),"\n",(0,n.jsx)(i.h2,{id:"changelog",children:"Changelog"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsx)(i.li,{children:"5/1/2023: First draft"}),"\n",(0,n.jsx)(i.li,{children:"7/23/2023: Add light client attacks handling"}),"\n",(0,n.jsx)(i.li,{children:"9/6/2023: Add double signing attacks handling"}),"\n",(0,n.jsx)(i.li,{children:"11/3/2023: Update limitations to clarify amnesia attacks are ignored"}),"\n"]}),"\n",(0,n.jsx)(i.h2,{id:"status",children:"Status"}),"\n",(0,n.jsx)(i.p,{children:"Accepted"}),"\n",(0,n.jsx)(i.h2,{id:"context",children:"Context"}),"\n",(0,n.jsx)(i.p,{children:"Currently, we use a governance proposal to slash validators for equivocation (double signing and light client attacks).\nEvery proposal needs to go through a (two weeks) voting period before it can be approved.\nGiven a three-week unbonding period, this means that an equivocation proposal needs to be submitted within one week since the infraction occurred."}),"\n",(0,n.jsx)(i.p,{children:"This ADR proposes a system to slash validators automatically for equivocation, immediately upon the provider chain's receipt of the evidence. Another thing to note is that we intend to introduce this system in stages, since even the partial ability to slash and/or tombstone is a strict improvement in security.\nThe feature is implemented in two parts, each with its dedicated endpoint. One endpoint handles light client attacks, while the other handles double signing attacks."}),"\n",(0,n.jsx)(i.h3,{id:"light-client-attack",children:"Light Client Attack"}),"\n",(0,n.jsx)(i.p,{children:"In a nutshell, the light client is a process that solely verifies a specific state machine's\nconsensus without executing the transactions. The light clients get new headers by querying\nmultiple nodes, called primary and witness nodes."}),"\n",(0,n.jsxs)(i.p,{children:["Light clients download new headers committed on chain from a primary. Headers can be verified in two ways: sequentially,\nwhere the block height of headers is serial, or using skipping. This second verification method allows light clients to download headers\nwith nonconsecutive block height, where some intermediate headers are skipped (see ",(0,n.jsx)(i.a,{href:"https://arxiv.org/pdf/2010.07031",children:"Tendermint Light Client, Figure 1 and Figure 3"}),").\nAdditionally, light clients are cross-checking new headers obtained from a primary with witnesses to ensure all nodes share the same state."]}),"\n",(0,n.jsxs)(i.p,{children:["A light client attack occurs when a Byzantine validator sends invalid headers to a light client.\nAs the light client doesn't execute transactions, it can be deceived into trusting corrupted application state transitions.\nFor instance, if a light client receives header ",(0,n.jsx)(i.code,{children:"A"})," from the primary and header ",(0,n.jsx)(i.code,{children:"B"})," from a witness for the same block height ",(0,n.jsx)(i.code,{children:"H"}),",\nand both headers are successfully verified, it indicates a light client attack.\nNote that in this case, either the primary or the witness or both are malicious."]}),"\n",(0,n.jsxs)(i.p,{children:["The types of light client attacks are defined by analyzing the differences between the conflicting headers.\nThere are three types of light client attacks: lunatic attack, equivocation attack, and amnesia attack.\nFor details, see the ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/main/spec/light-client/attacks/notes-on-evidence-handling.md#evidence-handling",children:"CometBFT specification"}),"."]}),"\n",(0,n.jsxs)(i.p,{children:["When a light client agent detects two conflicting headers, it will initially verify their traces (see ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/light/detector.go#L28",children:"cometBFT detector"}),") using its primary and witness nodes.\nIf these headers pass successful verification, the Byzantine validators will be identified based on the header's commit signatures\nand the type of light client attack. The agent will then transmit this information to its nodes using a ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#light-client-attacks",children:(0,n.jsx)(i.code,{children:"LightClientAttackEvidence"})})," evidence to be eventually voted on and added to a block.\nNote that from a light client agent perspective, it is not possible to establish whether a primary or a witness node, or both, are malicious.\nTherefore, it will create and send two evidences: one against the primary (sent to the witness), and one against the witness (sent to the primary).\nBoth nodes will then verify it before broadcasting it and adding it to the ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/evidence/pool.go#L28",children:"evidence pool"}),".\nIf an evidence is finally committed to a block, the chain's evidence module will execute it, resulting in the jailing and the slashing of the validators responsible for the light client attack."]}),"\n",(0,n.jsxs)(i.p,{children:["Light clients are a core component of IBC. In the event of a light client attack, IBC relayers notify the affected chains by submitting an ",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/ibc-go/blob/v4.4.2/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79",children:"IBC misbehavior message"}),".\nA misbehavior message includes the conflicting headers that constitute a light client attack evidence. Upon receiving such a message,\na chain will first verify whether these headers would have convinced its light client. This verification is achieved by checking\nthe header states against the light client consensus states (see ",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/ibc-go/blob/v4.4.2/modules/light-clients/07-tendermint/types/misbehaviour_handle.go#L24",children:"IBC misbehaviour handler"}),'). If the misbehaviour is successfully verified, the chain will then "freeze" the\nlight client, halting any further trust in or updating of its states.']}),"\n",(0,n.jsx)(i.h3,{id:"double-signing-attack",children:"Double Signing Attack"}),"\n",(0,n.jsxs)(i.p,{children:["A double signing attack, also known as equivocation,\noccurs when a validator votes for two different blocks in the same round of the CometBFT consensus.\nThis consensus mechanism operates with multiple voting rounds at each block height,\nand it strictly prohibits sending two votes of the same type during a round\n(see ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/consensus.md#state-machine-overview",children:"CometBFT State Machine Overview"}),")."]}),"\n",(0,n.jsxs)(i.p,{children:["When a node observes two votes from the same peer, it will use these two votes to create\na ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/types/evidence.go#L35",children:(0,n.jsx)(i.code,{children:"DuplicateVoteEvidence"})}),"\nevidence and gossip it to the other nodes in the network\n(see ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#detection",children:"CometBFT equivocation detection"}),").\nEach node will then verify the evidence according to the CometBFT rules that define a valid double signing infraction, and based on this verification, they will decide whether to add the evidence to a block.\nDuring the evidence verification process, the signatures of the conflicting votes must be verified successfully.\nNote that this is achieved using the public key of the misbehaving validator, along with the chain ID of the chain where the infraction occurred (see ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#verification",children:"CometBFT equivocation verification"}),")."]}),"\n",(0,n.jsxs)(i.p,{children:["Once a double signing evidence is committed to a block, the consensus layer will report the equivocation to the evidence module of the Cosmos SDK application layer.\nThe application will, in turn, punish the malicious validator through jailing, tombstoning and slashing\n(see ",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/evidence/keeper/infraction.go#L263",children:"handleEquivocationEvidence"}),")."]}),"\n",(0,n.jsx)(i.h2,{id:"decision",children:"Decision"}),"\n",(0,n.jsx)(i.h3,{id:"light-client-attack-1",children:"Light Client Attack"}),"\n",(0,n.jsxs)(i.p,{children:["In the first part of the feature, we introduce a new endpoint: ",(0,n.jsx)(i.code,{children:"HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour)"}),".\nThe main idea is to leverage the current IBC misbehaviour handling and update it to solely jail and slash the validators that\nperformed a light client attack. Note that in this context, we assume that chains connected via a light client\nshare a subset of the validator set of the provider."]}),"\n",(0,n.jsx)(i.p,{children:"This endpoint reuses the IBC client libraries to verify that the misbehaviour headers would have fooled the light client.\nAdditionally, it\u2019s crucial that the endpoint logic results in the slashing and jailing of validators under the same conditions\nas a light client agent detector. Therefore, the endpoint ensures that the two conditions are met:\nthe headers in the misbehaviour message have the same block height, and\nthe light client isn\u2019t expired."}),"\n",(0,n.jsx)(i.p,{children:"After having successfully verified a misbehaviour, the endpoint executes the jailing and slashing of the malicious validators similarly as in the evidence module."}),"\n",(0,n.jsx)(i.h3,{id:"double-signing-attack-1",children:"Double Signing Attack"}),"\n",(0,n.jsxs)(i.p,{children:["In the second part of the feature, we introduce a new endpoint ",(0,n.jsx)(i.code,{children:"HandleConsumerDoubleVoting( ctx sdk.Context, evidence *tmtypes.DuplicateVoteEvidence, chainID string, pubkey cryptotypes.PubKey)"}),".\nSimply put, the handling logic verifies a double signing evidence against a provided\npublic key and chain ID and, if successful, executes the jailing of the malicious validator who double voted."]}),"\n",(0,n.jsxs)(i.p,{children:["We define a new\n",(0,n.jsx)(i.code,{children:"MsgSubmitConsumerDoubleVoting"})," message to report a double voting evidence observed\non a consumer chain to the endpoint of the provider chain. This message contains two fields:\na double signing evidence\n",(0,n.jsx)(i.code,{children:"duplicate_vote_evidence"})," and a light client header for the infraction block height,\nreferred to as ",(0,n.jsx)(i.code,{children:"infraction_block_header"}),".\nThe latter provides the malicious validator's public key and the chain ID required to verify the signature of the votes contained in the evidence."]}),"\n",(0,n.jsxs)(i.p,{children:["Note that double signing evidence is not verified using the same conditions as in the implementation CometBFT (see\n",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/evidence/verify.go#L19",children:(0,n.jsx)(i.code,{children:"verify(evidence types.Evidence)"})})," method). Specifically, we do not check that the evidence hasn't expired.\nMore details can be found in the ",(0,n.jsx)(i.a,{href:"#current-limitations",children:'"Current limitations"'})," section below."]}),"\n",(0,n.jsxs)(i.p,{children:["Upon a successful equivocation verification, the misbehaving validator is jailed for the maximum time\n(see ",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/evidence/types/params.go#L11",children:"DoubleSignJailEndTime"}),"\nin the SDK evidence module)."]}),"\n",(0,n.jsx)(i.h3,{id:"current-limitations",children:"Current limitations:"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsxs)(i.li,{children:["\n",(0,n.jsx)(i.p,{children:"We cannot derive an infraction height from the evidence, so it is only possible to jail validators, not actually slash them.\nTo explain the technical reasons behind this limitation, let's recap the initial consumer initiated slashing logic.\nIn a nutshell, consumer heights are mapped to provider heights through VSCPackets, namely through the so called vscIDs.\nWhen an infraction occurs on the consumer, a SlashPacket containing the vscID obtained from mapping the consumer infraction height\nis sent to the provider. Upon receiving the packet, the provider maps the consumer infraction height to a local infraction height,\nwhich is used to slash the misbehaving validator. In the context of untrusted consumer chains, all their states, including vscIDs,\ncould be corrupted and therefore cannot be used for slashing purposes."}),"\n"]}),"\n",(0,n.jsxs)(i.li,{children:["\n",(0,n.jsx)(i.p,{children:"For the same reasons explained above, the age of a consumer double signing evidence can't be verified,\neither using its infraction height or its unsigned timestamp. Note that changes the jailing behaviour, potentially leading to a validator's jailing based on some \"old\" evidence from a consumer, which wouldn't occur if the consumer were a standalone chain."}),"\n"]}),"\n",(0,n.jsxs)(i.li,{children:["\n",(0,n.jsxs)(i.p,{children:["In the first stage of this feature, validators are jailed indefinitely without being tombstoned.\nThe underlying reason is that a malicious validator could take advantage of getting tombstoned\nto avoid being slashed on the provider (",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/interchain-security/pull/1232#issuecomment-1693127641",children:"see comment"}),")."]}),"\n"]}),"\n",(0,n.jsxs)(i.li,{children:["\n",(0,n.jsxs)(i.p,{children:["Currently, the endpoint can only handle ",(0,n.jsx)(i.em,{children:"equivocation"})," light client attacks. This is because the ",(0,n.jsx)(i.em,{children:"lunatic"})," attacks require the endpoint to possess the ability to dissociate which header is conflicted or trusted upon receiving a misbehavior message. Without this information, it's not possible to extract the Byzantine validators from the conflicting headers (see ",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/interchain-security/pull/826#discussion_r1268668684",children:"comment"}),'). In addition, "amnesia" attacks are ignored, similar to CometBFT (see ',(0,n.jsx)(i.a,{href:"https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-047-handling-evidence-from-light-client.md#negative",children:"ADR-056"}),")."]}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(i.h2,{id:"consequences",children:"Consequences"}),"\n",(0,n.jsx)(i.h3,{id:"positive",children:"Positive"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsx)(i.li,{children:"It is now possible for the provider chain to jail validators who committed\nlight client or double signing attacks on a consumer chain."}),"\n"]}),"\n",(0,n.jsx)(i.h3,{id:"negative",children:"Negative"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsx)(i.li,{children:"N/A"}),"\n"]}),"\n",(0,n.jsx)(i.h2,{id:"references",children:"References"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://github.com/cosmos/interchain-security/pull/826",children:"ICS misbehaviour handling PR"})}),"\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://github.com/cosmos/interchain-security/pull/1232",children:"Consumer double voting handler PR"})}),"\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://docs.google.com/document/d/1fe1uSJl1ZIYWXoME3Yf4Aodvz7V597Ric875JH-rigM/edit#heading=h.rv4t8i6d6jfn",children:"Architectural diagrams"})}),"\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-013-equivocation-slashing.md",children:"ADR on equivocation slashing"})}),"\n"]})]})}function d(e={}){const{wrapper:i}={...(0,s.a)(),...e.components};return i?(0,n.jsx)(i,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},1151:(e,i,t)=>{t.d(i,{Z:()=>c,a:()=>a});var n=t(7294);const s={},o=n.createContext(s);function a(e){const i=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function c(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),n.createElement(o.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/4edc808e.176093f8.js b/assets/js/4edc808e.176093f8.js new file mode 100644 index 0000000000..b896846bdd --- /dev/null +++ b/assets/js/4edc808e.176093f8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4173],{7559:(e,r,n)=>{n.r(r),n.d(r,{assets:()=>u,contentTitle:()=>c,default:()=>m,frontMatter:()=>o,metadata:()=>d,toc:()=>h});var t=n(5893),i=n(1151),s=n(2307),a=n(8758);const o={sidebar_position:1},c="Interchain Security Docs",d={id:"index",title:"Interchain Security Docs",description:"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.",source:"@site/docs/index.mdx",sourceDirName:".",slug:"/",permalink:"/interchain-security/",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",next:{title:"Overview",permalink:"/interchain-security/introduction/overview"}},u={},h=[];function l(e){const r={h1:"h1",p:"p",...(0,i.a)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(r.h1,{id:"interchain-security-docs",children:"Interchain Security Docs"}),"\n",(0,t.jsx)(r.p,{children:"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains."}),"\n",(0,t.jsx)(r.p,{children:"Here you can find information about Interchain Security, consumer chain development and instructions for validator onboarding."}),"\n",(0,t.jsx)(s.Z,{cards:a.Z})]})}function m(e={}){const{wrapper:r}={...(0,i.a)(),...e.components};return r?(0,t.jsx)(r,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},2307:(e,r,n)=>{n.d(r,{Z:()=>s});n(7294);var t=n(5893);const i=function(e){return(0,t.jsx)("a",{href:e.href,className:"border shadow rounded-sm border-stone-200 dark:border-stone-800 dark:bg-neutral-900 hover:border-stone-300 hover:shadow-lg dark:hover:border-stone-200 transition-all duration-200 no-underline",children:(0,t.jsxs)("div",{className:"p-6",children:[(0,t.jsx)("h2",{className:"",children:e.header}),(0,t.jsx)("p",{className:"",children:e.summary})]})})};const s=function(e){return(0,t.jsx)("div",{className:"card-section grid grid-cols-1 lg:grid-cols-2 gap-4 no-underline",children:e.cards.map(((e,r)=>(0,t.jsx)(i,{href:e.href,header:e.header,summary:e.summary},r)))})}},8758:(e,r,n)=>{n.d(r,{Z:()=>t});const t=[{href:"/interchain-security/introduction/overview",header:"Basic concepts",summary:"Get started with the basic concepts and ideas."},{href:"/interchain-security/consumer-development/app-integration",header:"Start building",summary:"Click here to start building with Interchain security"},{href:"/interchain-security/features/key-assignment",header:"Feature: Key Assignment",summary:"Learn about the key assignment feature"},{href:"/interchain-security/features/reward-distribution",header:"Feature: Reward Distribution",summary:"Learn about consumer chain rewards distribution"},{href:"/interchain-security/consumer-development/onboarding",header:"Onboarding Checklist",summary:"Checklist to help you integrate Interchain Security, get support and onboard validators"},{href:"/interchain-security/faq",header:"FAQ",summary:"Frequently asked questions about the protocol and its implications"}]},1151:(e,r,n)=>{n.d(r,{Z:()=>o,a:()=>a});var t=n(7294);const i={},s=t.createContext(i);function a(e){const r=t.useContext(s);return t.useMemo((function(){return"function"==typeof e?e(r):{...r,...e}}),[r,e])}function o(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),t.createElement(s.Provider,{value:r},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/4edefe03.b3451047.js b/assets/js/4edefe03.b3451047.js new file mode 100644 index 0000000000..68bb0ca108 --- /dev/null +++ b/assets/js/4edefe03.b3451047.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[918],{7168:(e,i,t)=>{t.r(i),t.d(i,{assets:()=>r,contentTitle:()=>a,default:()=>d,frontMatter:()=>o,metadata:()=>c,toc:()=>h});var n=t(5893),s=t(1151);const o={sidebar_position:4,title:"Cryptographic verification of equivocation evidence"},a="ADR 005: Cryptographic verification of equivocation evidence",c={id:"adrs/adr-005-cryptographic-equivocation-verification",title:"Cryptographic verification of equivocation evidence",description:"Changelog",source:"@site/versioned_docs/version-v5.0.0/adrs/adr-005-cryptographic-equivocation-verification.md",sourceDirName:"adrs",slug:"/adrs/adr-005-cryptographic-equivocation-verification",permalink:"/interchain-security/v5.0.0/adrs/adr-005-cryptographic-equivocation-verification",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Cryptographic verification of equivocation evidence"},sidebar:"tutorialSidebar",previous:{title:"Equivocation governance proposal",permalink:"/interchain-security/v5.0.0/adrs/adr-003-equivocation-gov-proposal"},next:{title:"Throttle with retries",permalink:"/interchain-security/v5.0.0/adrs/adr-008-throttle-retries"}},r={},h=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Light Client Attack",id:"light-client-attack",level:3},{value:"Double Signing Attack",id:"double-signing-attack",level:3},{value:"Decision",id:"decision",level:2},{value:"Light Client Attack",id:"light-client-attack-1",level:3},{value:"Double Signing Attack",id:"double-signing-attack-1",level:3},{value:"Current limitations:",id:"current-limitations",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}];function l(e){const i={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,s.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(i.h1,{id:"adr-005-cryptographic-verification-of-equivocation-evidence",children:"ADR 005: Cryptographic verification of equivocation evidence"}),"\n",(0,n.jsx)(i.h2,{id:"changelog",children:"Changelog"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsx)(i.li,{children:"5/1/2023: First draft"}),"\n",(0,n.jsx)(i.li,{children:"7/23/2023: Add light client attacks handling"}),"\n",(0,n.jsx)(i.li,{children:"9/6/2023: Add double signing attacks handling"}),"\n",(0,n.jsx)(i.li,{children:"11/3/2023: Update limitations to clarify amnesia attacks are ignored"}),"\n"]}),"\n",(0,n.jsx)(i.h2,{id:"status",children:"Status"}),"\n",(0,n.jsx)(i.p,{children:"Accepted"}),"\n",(0,n.jsx)(i.h2,{id:"context",children:"Context"}),"\n",(0,n.jsx)(i.p,{children:"Currently, we use a governance proposal to slash validators for equivocation (double signing and light client attacks).\nEvery proposal needs to go through a (two weeks) voting period before it can be approved.\nGiven a three-week unbonding period, this means that an equivocation proposal needs to be submitted within one week since the infraction occurred."}),"\n",(0,n.jsx)(i.p,{children:"This ADR proposes a system to slash validators automatically for equivocation, immediately upon the provider chain's receipt of the evidence. Another thing to note is that we intend to introduce this system in stages, since even the partial ability to slash and/or tombstone is a strict improvement in security.\nThe feature is implemented in two parts, each with its dedicated endpoint. One endpoint handles light client attacks, while the other handles double signing attacks."}),"\n",(0,n.jsx)(i.h3,{id:"light-client-attack",children:"Light Client Attack"}),"\n",(0,n.jsx)(i.p,{children:"In a nutshell, the light client is a process that solely verifies a specific state machine's\nconsensus without executing the transactions. The light clients get new headers by querying\nmultiple nodes, called primary and witness nodes."}),"\n",(0,n.jsxs)(i.p,{children:["Light clients download new headers committed on chain from a primary. Headers can be verified in two ways: sequentially,\nwhere the block height of headers is serial, or using skipping. This second verification method allows light clients to download headers\nwith nonconsecutive block height, where some intermediate headers are skipped (see ",(0,n.jsx)(i.a,{href:"https://arxiv.org/pdf/2010.07031.pdf",children:"Tendermint Light Client, Figure 1 and Figure 3"}),").\nAdditionally, light clients are cross-checking new headers obtained from a primary with witnesses to ensure all nodes share the same state."]}),"\n",(0,n.jsxs)(i.p,{children:["A light client attack occurs when a Byzantine validator sends invalid headers to a light client.\nAs the light client doesn't execute transactions, it can be deceived into trusting corrupted application state transitions.\nFor instance, if a light client receives header ",(0,n.jsx)(i.code,{children:"A"})," from the primary and header ",(0,n.jsx)(i.code,{children:"B"})," from a witness for the same block height ",(0,n.jsx)(i.code,{children:"H"}),",\nand both headers are successfully verified, it indicates a light client attack.\nNote that in this case, either the primary or the witness or both are malicious."]}),"\n",(0,n.jsxs)(i.p,{children:["The types of light client attacks are defined by analyzing the differences between the conflicting headers.\nThere are three types of light client attacks: lunatic attack, equivocation attack, and amnesia attack.\nFor details, see the ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/main/spec/light-client/attacks/notes-on-evidence-handling.md#evidence-handling",children:"CometBFT specification"}),"."]}),"\n",(0,n.jsxs)(i.p,{children:["When a light client agent detects two conflicting headers, it will initially verify their traces (see ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/light/detector.go#L28",children:"cometBFT detector"}),") using its primary and witness nodes.\nIf these headers pass successful verification, the Byzantine validators will be identified based on the header's commit signatures\nand the type of light client attack. The agent will then transmit this information to its nodes using a ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#light-client-attacks",children:(0,n.jsx)(i.code,{children:"LightClientAttackEvidence"})})," evidence to be eventually voted on and added to a block.\nNote that from a light client agent perspective, it is not possible to establish whether a primary or a witness node, or both, are malicious.\nTherefore, it will create and send two evidences: one against the primary (sent to the witness), and one against the witness (sent to the primary).\nBoth nodes will then verify it before broadcasting it and adding it to the ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/evidence/pool.go#L28",children:"evidence pool"}),".\nIf an evidence is finally committed to a block, the chain's evidence module will execute it, resulting in the jailing and the slashing of the validators responsible for the light client attack."]}),"\n",(0,n.jsxs)(i.p,{children:["Light clients are a core component of IBC. In the event of a light client attack, IBC relayers notify the affected chains by submitting an ",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/ibc-go/blob/v4.4.2/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79",children:"IBC misbehavior message"}),".\nA misbehavior message includes the conflicting headers that constitute a light client attack evidence. Upon receiving such a message,\na chain will first verify whether these headers would have convinced its light client. This verification is achieved by checking\nthe header states against the light client consensus states (see ",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/ibc-go/blob/v4.4.2/modules/light-clients/07-tendermint/types/misbehaviour_handle.go#L24",children:"IBC misbehaviour handler"}),'). If the misbehaviour is successfully verified, the chain will then "freeze" the\nlight client, halting any further trust in or updating of its states.']}),"\n",(0,n.jsx)(i.h3,{id:"double-signing-attack",children:"Double Signing Attack"}),"\n",(0,n.jsxs)(i.p,{children:["A double signing attack, also known as equivocation,\noccurs when a validator votes for two different blocks in the same round of the CometBFT consensus.\nThis consensus mechanism operates with multiple voting rounds at each block height,\nand it strictly prohibits sending two votes of the same type during a round\n(see ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/consensus.md#state-machine-overview",children:"CometBFT State Machine Overview"}),")."]}),"\n",(0,n.jsxs)(i.p,{children:["When a node observes two votes from the same peer, it will use these two votes to create\na ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/types/evidence.go#L35",children:(0,n.jsx)(i.code,{children:"DuplicateVoteEvidence"})}),"\nevidence and gossip it to the other nodes in the network\n(see ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#detection",children:"CometBFT equivocation detection"}),").\nEach node will then verify the evidence according to the CometBFT rules that define a valid double signing infraction, and based on this verification, they will decide whether to add the evidence to a block.\nDuring the evidence verification process, the signatures of the conflicting votes must be verified successfully.\nNote that this is achieved using the public key of the misbehaving validator, along with the chain ID of the chain where the infraction occurred (see ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#verification",children:"CometBFT equivocation verification"}),")."]}),"\n",(0,n.jsxs)(i.p,{children:["Once a double signing evidence is committed to a block, the consensus layer will report the equivocation to the evidence module of the Cosmos SDK application layer.\nThe application will, in turn, punish the malicious validator through jailing, tombstoning and slashing\n(see ",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/evidence/keeper/infraction.go#L263",children:"handleEquivocationEvidence"}),")."]}),"\n",(0,n.jsx)(i.h2,{id:"decision",children:"Decision"}),"\n",(0,n.jsx)(i.h3,{id:"light-client-attack-1",children:"Light Client Attack"}),"\n",(0,n.jsxs)(i.p,{children:["In the first part of the feature, we introduce a new endpoint: ",(0,n.jsx)(i.code,{children:"HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour)"}),".\nThe main idea is to leverage the current IBC misbehaviour handling and update it to solely jail and slash the validators that\nperformed a light client attack. Note that in this context, we assume that chains connected via a light client\nshare the same validator set, as is the case with Replicated Security."]}),"\n",(0,n.jsx)(i.p,{children:"This endpoint reuses the IBC client libraries to verify that the misbehaviour headers would have fooled the light client.\nAdditionally, it\u2019s crucial that the endpoint logic results in the slashing and jailing of validators under the same conditions\nas a light client agent detector. Therefore, the endpoint ensures that the two conditions are met:\nthe headers in the misbehaviour message have the same block height, and\nthe light client isn\u2019t expired."}),"\n",(0,n.jsx)(i.p,{children:"After having successfully verified a misbehaviour, the endpoint executes the jailing and slashing of the malicious validators similarly as in the evidence module."}),"\n",(0,n.jsx)(i.h3,{id:"double-signing-attack-1",children:"Double Signing Attack"}),"\n",(0,n.jsxs)(i.p,{children:["In the second part of the feature, we introduce a new endpoint ",(0,n.jsx)(i.code,{children:"HandleConsumerDoubleVoting( ctx sdk.Context, evidence *tmtypes.DuplicateVoteEvidence, chainID string, pubkey cryptotypes.PubKey)"}),".\nSimply put, the handling logic verifies a double signing evidence against a provided\npublic key and chain ID and, if successful, executes the jailing of the malicious validator who double voted."]}),"\n",(0,n.jsxs)(i.p,{children:["We define a new\n",(0,n.jsx)(i.code,{children:"MsgSubmitConsumerDoubleVoting"})," message to report a double voting evidence observed\non a consumer chain to the endpoint of the provider chain. This message contains two fields:\na double signing evidence\n",(0,n.jsx)(i.code,{children:"duplicate_vote_evidence"})," and a light client header for the infraction block height,\nreferred to as ",(0,n.jsx)(i.code,{children:"infraction_block_header"}),".\nThe latter provides the malicious validator's public key and the chain ID required to verify the signature of the votes contained in the evidence."]}),"\n",(0,n.jsxs)(i.p,{children:["Note that double signing evidence is not verified using the same conditions as in the implementation CometBFT (see\n",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/evidence/verify.go#L19",children:(0,n.jsx)(i.code,{children:"verify(evidence types.Evidence)"})})," method). Specifically, we do not check that the evidence hasn't expired.\nMore details can be found in the ",(0,n.jsx)(i.a,{href:"#current-limitations",children:'"Current limitations"'})," section below."]}),"\n",(0,n.jsxs)(i.p,{children:["Upon a successful equivocation verification, the misbehaving validator is jailed for the maximum time\n(see ",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/evidence/types/params.go#L11",children:"DoubleSignJailEndTime"}),"\nin the SDK evidence module)."]}),"\n",(0,n.jsx)(i.h3,{id:"current-limitations",children:"Current limitations:"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsxs)(i.li,{children:["\n",(0,n.jsx)(i.p,{children:"We cannot derive an infraction height from the evidence, so it is only possible to jail validators, not actually slash them.\nTo explain the technical reasons behind this limitation, let's recap the initial consumer initiated slashing logic.\nIn a nutshell, consumer heights are mapped to provider heights through VSCPackets, namely through the so called vscIDs.\nWhen an infraction occurs on the consumer, a SlashPacket containing the vscID obtained from mapping the consumer infraction height\nis sent to the provider. Upon receiving the packet, the provider maps the consumer infraction height to a local infraction height,\nwhich is used to slash the misbehaving validator. In the context of untrusted consumer chains, all their states, including vscIDs,\ncould be corrupted and therefore cannot be used for slashing purposes."}),"\n"]}),"\n",(0,n.jsxs)(i.li,{children:["\n",(0,n.jsx)(i.p,{children:"For the same reasons explained above, the age of a consumer double signing evidence can't be verified,\neither using its infraction height or its unsigned timestamp. Note that changes the jailing behaviour, potentially leading to a validator's jailing based on some \"old\" evidence from a consumer, which wouldn't occur if the consumer were a standalone chain."}),"\n"]}),"\n",(0,n.jsxs)(i.li,{children:["\n",(0,n.jsxs)(i.p,{children:["In the first stage of this feature, validators are jailed indefinitely without being tombstoned.\nThe underlying reason is that a malicious validator could take advantage of getting tombstoned\nto avoid being slashed on the provider (",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/interchain-security/pull/1232#issuecomment-1693127641",children:"see comment"}),")."]}),"\n"]}),"\n",(0,n.jsxs)(i.li,{children:["\n",(0,n.jsxs)(i.p,{children:["Currently, the endpoint can only handle ",(0,n.jsx)(i.em,{children:"equivocation"})," light client attacks. This is because the ",(0,n.jsx)(i.em,{children:"lunatic"})," attacks require the endpoint to possess the ability to dissociate which header is conflicted or trusted upon receiving a misbehavior message. Without this information, it's not possible to extract the Byzantine validators from the conflicting headers (see ",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/interchain-security/pull/826#discussion_r1268668684",children:"comment"}),'). In addition, "amnesia" attacks are ignored, similar to CometBFT (see ',(0,n.jsx)(i.a,{href:"https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-047-handling-evidence-from-light-client.md#negative",children:"ADR-056"}),")."]}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(i.h2,{id:"consequences",children:"Consequences"}),"\n",(0,n.jsx)(i.h3,{id:"positive",children:"Positive"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsx)(i.li,{children:"It is now possible for the provider chain to jail validators who committed\nlight client or double signing attacks on a consumer chain."}),"\n"]}),"\n",(0,n.jsx)(i.h3,{id:"negative",children:"Negative"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsx)(i.li,{children:"N/A"}),"\n"]}),"\n",(0,n.jsx)(i.h2,{id:"references",children:"References"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://github.com/cosmos/interchain-security/pull/826",children:"ICS misbehaviour handling PR"})}),"\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://github.com/cosmos/interchain-security/pull/1232",children:"Consumer double voting handler PR"})}),"\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://docs.google.com/document/d/1fe1uSJl1ZIYWXoME3Yf4Aodvz7V597Ric875JH-rigM/edit#heading=h.rv4t8i6d6jfn",children:"Architectural diagrams"})}),"\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-013-equivocation-slashing.md",children:"ADR on equivocation slashing"})}),"\n"]})]})}function d(e={}){const{wrapper:i}={...(0,s.a)(),...e.components};return i?(0,n.jsx)(i,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},1151:(e,i,t)=>{t.d(i,{Z:()=>c,a:()=>a});var n=t(7294);const s={},o=n.createContext(s);function a(e){const i=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function c(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),n.createElement(o.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/4f50acdf.f5850848.js b/assets/js/4f50acdf.f5850848.js new file mode 100644 index 0000000000..1e4da13a7e --- /dev/null +++ b/assets/js/4f50acdf.f5850848.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9815],{7125:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var i=s(5893),t=s(1151);const r={sidebar_position:2,title:"Joining Interchain Security testnet"},o=void 0,a={id:"validators/joining-testnet",title:"Joining Interchain Security testnet",description:"Introduction",source:"@site/docs/validators/joining-testnet.md",sourceDirName:"validators",slug:"/validators/joining-testnet",permalink:"/interchain-security/validators/joining-testnet",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"Joining Interchain Security testnet"},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/validators/overview"},next:{title:"Consumer chain validator rewards",permalink:"/interchain-security/validators/withdraw_rewards"}},c={},d=[{value:"Introduction",id:"introduction",level:2},{value:"Joining the provider chain",id:"joining-the-provider-chain",level:2},{value:"Initialization",id:"initialization",level:2},{value:"Joining consumer chains",id:"joining-consumer-chains",level:2},{value:"Re-using consensus key",id:"re-using-consensus-key",level:2},{value:"Assigning consensus keys",id:"assigning-consensus-keys",level:2}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,t.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,i.jsxs)(n.p,{children:["This short guide will teach you how to join the ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/testnets/tree/master/interchain-security",children:"Interchain Security testnet"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"The experience gained in the testnet will prepare you for validating interchain secured chains."}),"\n",(0,i.jsxs)(n.admonition,{type:"tip",children:[(0,i.jsx)(n.p,{children:"Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set."}),(0,i.jsxs)(n.p,{children:["For general information about running cosmos-sdk based chains check out the ",(0,i.jsx)(n.a,{href:"https://hub.cosmos.network/main/validators/validator-setup",children:"validator basics"})," and ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/main/run-node/run-node",children:"Running a Node section"})," of Cosmos SDK docs"]})]}),"\n",(0,i.jsx)(n.h2,{id:"joining-the-provider-chain",children:"Joining the provider chain"}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsx)(n.p,{children:"At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain."})}),"\n",(0,i.jsxs)(n.p,{children:["A comprehensive guide is available ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/testnets/tree/master/interchain-security/provider",children:"here"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"initialization",children:"Initialization"}),"\n",(0,i.jsxs)(n.p,{children:["First, initialize your ",(0,i.jsx)(n.code,{children:"$NODE_HOME"})," using the ",(0,i.jsx)(n.code,{children:"provider"})," chain binary."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"NODE_MONIKER=<your_node>\nCHAIN_ID=provider\nNODE_HOME=<path_to_your_home>\n\ngaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Add your key to the keyring - more details available ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/main/run-node/keyring",children:"here"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["In this example we will use the ",(0,i.jsx)(n.code,{children:"test"})," keyring-backend. This option is not safe to use in production."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad keys add <key_moniker> --keyring-backend test\n\n# save the address as variable for later use\nMY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Before issuing any transactions, use the ",(0,i.jsx)(n.code,{children:"provider"})," testnet faucet to add funds to your address."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider\n\n# example output:\n{\n "address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",\n "amount": "10000000uatom",\n "chain": "provider",\n "hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",\n "status": "success"\n}\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Then, use the account associated with the keyring to issue a ",(0,i.jsx)(n.code,{children:"create-validator"})," transaction which will register your validator on chain."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'gaiad tx staking create-validator \\\n --amount=1000000uatom \\\n --pubkey=$(gaiad tendermint show-validator) \\\n --moniker="choose a moniker" \\\n --chain-id=$CHAIN_ID" \\\n --commission-rate="0.10" \\\n --commission-max-rate="0.20" \\\n --commission-max-change-rate="0.01" \\\n --min-self-delegation="1000000" \\\n --gas="auto" \\\n --gas-prices="0.0025uatom" \\\n --from=<key_moniker>\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["Check this ",(0,i.jsx)(n.a,{href:"https://hub.cosmos.network/main/validators/validator-setup#edit-validator-description",children:"guide"})," to edit your validator."]})}),"\n",(0,i.jsxs)(n.p,{children:["After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use ",(0,i.jsx)(n.code,{children:"statesync"})," to catch up to the rest of the network."]}),"\n",(0,i.jsxs)(n.p,{children:["You can use this script to modify your ",(0,i.jsx)(n.code,{children:"config.toml"})," with the required statesync parameters."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"# create the statesync script\n$: cd $NODE_HOME\n$: touch statesync.sh\n$ chmod 700 statesync.sh # make executable\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Paste the following instructions into the ",(0,i.jsx)(n.code,{children:"statesync.sh"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'#!/bin/bash\n\nSNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"\n\nLATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \\\nBLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \\\nTRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)\n\nsed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\\1true| ; \\\ns|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\\1\\"$SNAP_RPC,$SNAP_RPC\\"| ; \\\ns|^(trust_height[[:space:]]+=[[:space:]]+).*$|\\1$BLOCK_HEIGHT| ; \\\ns|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\\1\\"$TRUST_HASH\\"|" $NODE_HOME/config/config.toml\n'})}),"\n",(0,i.jsx)(n.p,{children:"Then, you can execute the script:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"$: ./statesync.sh # setup config.toml for statesync\n"})}),"\n",(0,i.jsx)(n.p,{children:"Finally, copy the provider genesis and start your node:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/interchain-security/provider/provider-genesis.json\n$: wget $GENESIS_URL -O genesis.json\n$: genesis.json $NODE_HOME/config/genesis.json\n# start the service\n$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Additional scripts to setup your nodes are available ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/provider/join-ics-provider.sh",children:"here"})," and ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/provider/join-ics-provider-cv.sh",children:"here"}),". The scripts will configure your node and create the required services - the scripts only work in linux environments."]}),"\n",(0,i.jsx)(n.h2,{id:"joining-consumer-chains",children:"Joining consumer chains"}),"\n",(0,i.jsxs)(n.admonition,{type:"tip",children:[(0,i.jsx)(n.p,{children:"Once you reach the active set on the provider chain, you will be required to validate all available consumer chains."}),(0,i.jsxs)(n.p,{children:["We strongly recommend that you assign a separate key for each consumer chain.\nCheck out this ",(0,i.jsx)(n.a,{href:"/interchain-security/features/key-assignment",children:"guide"})," to learn more about key assignment in interchain security."]})]}),"\n",(0,i.jsx)(n.p,{children:"To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries."}),"\n",(0,i.jsxs)(n.admonition,{type:"info",children:[(0,i.jsxs)(n.p,{children:["When running the provider chain and consumers on the same machine please update the ",(0,i.jsx)(n.code,{children:"PORT"})," numbers for each of them and make sure they do not overlap (otherwise the binaries will not start)."]}),(0,i.jsx)(n.p,{children:"Important ports to re-configure:"}),(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"--rpc.laddr"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"--p2p.laddr"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"--api.address"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"--grpc.address"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"--grpc-web.address"})}),"\n"]})]}),"\n",(0,i.jsx)(n.h2,{id:"re-using-consensus-key",children:"Re-using consensus key"}),"\n",(0,i.jsxs)(n.p,{children:["To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the ",(0,i.jsx)(n.code,{children:"priv_validator_key.json"})," into the home directory of your consumer chain (",(0,i.jsx)(n.code,{children:"<consumer_home>/config/priv_validator_key.json"}),")."]}),"\n",(0,i.jsx)(n.p,{children:"When you start the chain, the consensus key will be the same on the provider and the consumer chain."}),"\n",(0,i.jsx)(n.h2,{id:"assigning-consensus-keys",children:"Assigning consensus keys"}),"\n",(0,i.jsx)(n.p,{children:"Whenever you initialize a new node, it will be configured with a consensus key you can use."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'# machine running consumer chain\nconsumerd init <node_moniker> --home <home_path> --chain-id consumer-1\n\n# use the output of this command to get the consumer chain consensus key\nconsumerd tendermint show-validator\n# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}\n'})}),"\n",(0,i.jsx)(n.p,{children:"Then, let the provider know which key you will be using for the consumer chain:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"# machine running the provider chain\ngaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b sync -y -o json\n"})}),"\n",(0,i.jsxs)(n.p,{children:["After this step, you are ready to copy the consumer genesis into your nodes's ",(0,i.jsx)(n.code,{children:"/config"})," folder, start your consumer chain node and catch up to the network."]})]})}function l(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},1151:(e,n,s)=>{s.d(n,{Z:()=>a,a:()=>o});var i=s(7294);const t={},r=i.createContext(t);function o(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/53123775.fe1cc72c.js b/assets/js/53123775.fe1cc72c.js new file mode 100644 index 0000000000..a4f9de860f --- /dev/null +++ b/assets/js/53123775.fe1cc72c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2234],{8621:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>p,frontMatter:()=>o,metadata:()=>t,toc:()=>c});var s=r(5893),i=r(1151);const o={sidebar_position:1},a="Upgrading to ICS v5.0.0",t={id:"upgrading/migrate_v4_v5",title:"Upgrading to ICS v5.0.0",description:"This ICS version uses cosmos-sdk v0.50.x and ibc-go v8.x.",source:"@site/versioned_docs/version-v5.0.0/upgrading/migrate_v4_v5.md",sourceDirName:"upgrading",slug:"/upgrading/migrate_v4_v5",permalink:"/interchain-security/v5.0.0/upgrading/migrate_v4_v5",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Technical Specification",permalink:"/interchain-security/v5.0.0/introduction/technical-specification"},next:{title:"Key Assignment",permalink:"/interchain-security/v5.0.0/features/key-assignment"}},d={},c=[{value:"Provider",id:"provider",level:2},{value:"Keeper initialization",id:"keeper-initialization",level:3},{value:"Protocol changes",id:"protocol-changes",level:3},{value:"Revert <code>AfterUnbondingInitiated</code>",id:"revert-afterunbondinginitiated",level:4},{value:"Migration (v4 -> v5)",id:"migration-v4---v5",level:3},{value:"Additions",id:"additions",level:3},{value:"MsgUpdateParams transaction",id:"msgupdateparams-transaction",level:3},{value:"Governance proposals",id:"governance-proposals",level:3},{value:"Consumer",id:"consumer",level:2},{value:"Keeper initialization",id:"keeper-initialization-1",level:3},{value:"Additions",id:"additions-1",level:3},{value:"<code>MsgUpdateParams</code> transaction",id:"msgupdateparams-transaction-1",level:4},{value:"Params Query",id:"params-query",level:4},{value:"Migration (v2 -> v3)",id:"migration-v2---v3",level:3},{value:"Interface method changes",id:"interface-method-changes",level:3},{value:"Democracy",id:"democracy",level:2},{value:"Note:",id:"note",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"upgrading-to-ics-v500",children:"Upgrading to ICS v5.0.0"}),"\n",(0,s.jsx)(n.p,{children:"This ICS version uses cosmos-sdk v0.50.x and ibc-go v8.x."}),"\n",(0,s.jsxs)(n.p,{children:["To migrate you application to cosmos-sdk v0.50.x please use this ",(0,s.jsx)(n.a,{href:"https://docs.cosmos.network/v0.50/build/migrations/upgrading",children:"guide"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"To migrate your application to ibc-go v8.x.y please use the following guides:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://ibc.cosmos.network/main/migrations/v7-to-v8",children:"migrate ibc-go to v8.0.0"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://ibc.cosmos.network/main/migrations/v8-to-v8_1",children:"migrate ibc-go to v8.1.0"})}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"ICS specific changes are outlined below."}),"\n",(0,s.jsxs)(n.p,{children:["Pre-requisite version for this upgrade: ",(0,s.jsx)(n.code,{children:"v4.x"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"provider",children:"Provider"}),"\n",(0,s.jsx)(n.h3,{id:"keeper-initialization",children:"Keeper initialization"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-diff",children:"// app.go\n\napp.ProviderKeeper = ibcproviderkeeper.NewKeeper(\n appCodec,\n keys[providertypes.StoreKey],\n app.GetSubspace(providertypes.ModuleName),\n scopedIBCProviderKeeper,\n app.IBCKeeper.ChannelKeeper,\n- app.IBCKeeper.PortKeeper\n+ app.IBCKeeper.PortKeeper,\n app.IBCKeeper.ConnectionKeeper,\n app.IBCKeeper.ClientKeeper,\n app.StakingKeeper,\n app.SlashingKeeper,\n app.AccountKeeper,\n app.DistrKeeper,\n app.BankKeeper,\n *app.GovKeeper,\n+ authtypes.NewModuleAddress(govtypes.ModuleName).String(),\n+ authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),\n+ authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()),\n authtypes.FeeCollectorName,\n)\n"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"authority"})," was added - requirement for executing ",(0,s.jsx)(n.code,{children:"MsgUpdateParams"})]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["uses ",(0,s.jsx)(n.code,{children:"x/gov"})," module address by default"]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"validatorAddressCodec"})," & ",(0,s.jsx)(n.code,{children:"consensusAddressCodec"})," were added - they must match the bech32 address codec used by ",(0,s.jsx)(n.code,{children:"x/auth"}),", ",(0,s.jsx)(n.code,{children:"x/bank"}),", ",(0,s.jsx)(n.code,{children:"x/staking"})]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"protocol-changes",children:"Protocol changes"}),"\n",(0,s.jsxs)(n.h4,{id:"revert-afterunbondinginitiated",children:["Revert ",(0,s.jsx)(n.code,{children:"AfterUnbondingInitiated"})]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"AfterUnbondingInitiated"})," behavior was reverted to ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/v1.2.0-multiden/x/ccv/provider/keeper/hooks.go#L53",children:"ICS@v1.2.0-multiden"})]}),"\n",(0,s.jsx)(n.p,{children:"The revert re-introduces an additional state check."}),"\n",(0,s.jsxs)(n.p,{children:["See this ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/1045",children:"issue"})," for more context and the actions taken."]}),"\n",(0,s.jsx)(n.h3,{id:"migration-v4---v5",children:"Migration (v4 -> v5)"}),"\n",(0,s.jsxs)(n.p,{children:["ConensusVersion was bumped to ",(0,s.jsx)(n.code,{children:"5"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["The migration allows storing the provider module params in the ",(0,s.jsx)(n.code,{children:"x/ccv/provider"})," module store instead of relying on legacy ",(0,s.jsx)(n.code,{children:"x/param"})," store."]}),"\n",(0,s.jsx)(n.p,{children:"There are no special requirements for executing this migration."}),"\n",(0,s.jsx)(n.h3,{id:"additions",children:"Additions"}),"\n",(0,s.jsx)(n.h3,{id:"msgupdateparams-transaction",children:"MsgUpdateParams transaction"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"x/gov"})," module account is selected as the default ",(0,s.jsx)(n.code,{children:"authority"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["It is available when using ",(0,s.jsx)(n.code,{children:"gov"})," CLI commands:"]}),"\n",(0,s.jsx)(n.p,{children:"Drafting a proposal:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:'interchain-security-pd tx gov draft-proposal\n# select "other"\n# find and select "/interchain_security.ccv.provider.v1.MsgUpdateParams"\n'})}),"\n",(0,s.jsx)(n.p,{children:"Submitting a proposal:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:"interchain-security-pd tx gov submit-proposal <proposal-message.json>\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Example ",(0,s.jsx)(n.code,{children:"proposal-message.json"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "messages": [\n {\n "@type": "/interchain_security.ccv.provider.v1.MsgUpdateParams",\n "authority": "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn",\n "params": {\n "trusting_period_fraction": "0.66",\n "ccv_timeout_period": "2419200s",\n "init_timeout_period": "604800s",\n "vsc_timeout_period": "3024000s",\n "slash_meter_replenish_period": "3s",\n "slash_meter_replenish_fraction": "1.0",\n "consumer_reward_denom_registration_fee": {\n "denom": "stake",\n "amount": "10000000"\n },\n "blocks_per_epoch": "600"\n }\n }\n ],\n "metadata": "ipfs://CID",\n "deposit": "10000stake",\n "title": "Update Provider params",\n "summary": "Update Provider params",\n "expedited": false\n}\n'})}),"\n",(0,s.jsx)(n.h3,{id:""}),"\n",(0,s.jsxs)(n.p,{children:["When updating parameters ",(0,s.jsx)(n.strong,{children:"all"})," parameters fields must be specified. Make sure you are only changing parameters that you are interested in."]}),"\n",(0,s.jsx)(n.p,{children:"To avoid accidentally changing parameters you can first check the current on-chain provider params using:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:'interchain-security-pd q provider params -o json\n\n{\n "template_client": {...},\n "trusting_period_fraction": "0.66",\n "ccv_timeout_period": "2419200s",\n "init_timeout_period": "604800s",\n "vsc_timeout_period": "3024000s",\n "slash_meter_replenish_period": "3s",\n "slash_meter_replenish_fraction": "1.0",\n "consumer_reward_denom_registration_fee": {\n "denom": "stake",\n "amount": "10000000"\n },\n "blocks_per_epoch": "600"\n}\n'})}),"\n",(0,s.jsx)(n.h3,{id:"governance-proposals",children:"Governance proposals"}),"\n",(0,s.jsx)(n.p,{children:"Submitting the following legacy proposals is still supported:"}),"\n",(0,s.jsx)(n.h1,{id:"consumer-addition-proposal",children:"Consumer addition proposal"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:"interchain-security-pd tx gov submit-legacy-proposal consumer-addition <proposal_file.json>\n"})}),"\n",(0,s.jsx)(n.h1,{id:"consumer-removal-proposal",children:"Consumer removal proposal"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:"interchain-security-pd tx gov submit-legacy-proposal consumer-removal <proposal_file.json>\n"})}),"\n",(0,s.jsx)(n.h1,{id:"consumer-addition-proposal-1",children:"Consumer addition proposal"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:"interchain-security-pd tx gov submit-legacy-proposal change-reward-denoms <proposal_file.json>\n"})}),"\n",(0,s.jsxs)(n.p,{children:["You may also submit proposal messages above using ",(0,s.jsx)(n.code,{children:"submit-proposal"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"consumer",children:"Consumer"}),"\n",(0,s.jsx)(n.h3,{id:"keeper-initialization-1",children:"Keeper initialization"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-diff",children:"// pre-initialize ConsumerKeeper to satsfy ibckeeper.NewKeeper\napp.ConsumerKeeper = ibcconsumerkeeper.NewNonZeroKeeper(\n appCodec,\n keys[ibcconsumertypes.StoreKey],\n app.GetSubspace(ibcconsumertypes.ModuleName),\n)\n\napp.IBCKeeper = ibckeeper.NewKeeper(\n appCodec,\n keys[ibchost.StoreKey],\n app.GetSubspace(ibchost.ModuleName),\n app.ConsumerKeeper,\n app.UpgradeKeeper,\n scopedIBCKeeper,\n authtypes.NewModuleAddress(govtypes.ModuleName).String(),\n)\n\n// initialize the actual consumer keeper\napp.ConsumerKeeper = ibcconsumerkeeper.NewKeeper(\n appCodec,\n keys[ibcconsumertypes.StoreKey],\n app.GetSubspace(ibcconsumertypes.ModuleName),\n scopedIBCConsumerKeeper,\n app.IBCKeeper.ChannelKeeper,\n- &app.IBCKeeper.PortKeeper,\n+ app.IBCKeeper.PortKeeper,\n app.IBCKeeper.ConnectionKeeper,\n app.IBCKeeper.ClientKeeper,\n app.SlashingKeeper,\n app.BankKeeper,\n app.AccountKeeper,\n &app.TransferKeeper,\n app.IBCKeeper,\n authtypes.FeeCollectorName,\n\n // make sure the authority address makes sense for your chain\n // the exact module account may differ depending on your setup (x/gov, x/admin or custom module)\n // for x/ccv/democracy using the x/gov module address is correct\n // if you don't have a way of updating consumer params you may still use the line below as it will have no affect\n+ authtypes.NewModuleAddress(govtypes.ModuleName).String(),\n \n // add address codecs \n+ authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),\n+ authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()),\n)\n"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"authority"})," was added - requirement for executing ",(0,s.jsx)(n.code,{children:"MsgUpdateParams"})]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"make sure the authority address makes sense for your chain"}),"\n",(0,s.jsxs)(n.li,{children:["the exact module account may differ depending on your setup (",(0,s.jsx)(n.code,{children:"x/gov"}),", ",(0,s.jsx)(n.code,{children:"x/admin"})," or custom module)"]}),"\n",(0,s.jsxs)(n.li,{children:["for ",(0,s.jsx)(n.code,{children:"x/ccv/democracy"})," using the ",(0,s.jsx)(n.code,{children:"x/gov"})," module address is correct"]}),"\n",(0,s.jsxs)(n.li,{children:["if you don't have a way of updating consumer params you may use ",(0,s.jsx)(n.code,{children:"authtypes.NewModuleAddress(govtypes.ModuleName).String()"})," (has no effect on functionality)"]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"validatorAddressCodec"})," & ",(0,s.jsx)(n.code,{children:"consensusAddressCodec"})," were added - they must match the bech32 address codec used by ",(0,s.jsx)(n.code,{children:"x/auth"}),", ",(0,s.jsx)(n.code,{children:"x/bank"}),", ",(0,s.jsx)(n.code,{children:"x/staking"})]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"additions-1",children:"Additions"}),"\n",(0,s.jsxs)(n.h4,{id:"msgupdateparams-transaction-1",children:[(0,s.jsx)(n.code,{children:"MsgUpdateParams"})," transaction"]}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsxs)(n.strong,{children:["This functionality is not supported on ",(0,s.jsx)(n.code,{children:"x/ccv/consumer"})," without additional configuration."]})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["if you are using ",(0,s.jsx)(n.code,{children:"x/ccv/democracy"})," the feature is supported out of the box"]}),"\n",(0,s.jsxs)(n.li,{children:["if you are using custom logic for changing consumer params, please update your code by providing the appropriate ",(0,s.jsx)(n.code,{children:"authority"})," module account during ",(0,s.jsx)(n.code,{children:"ConsumerKeeper"})," initialization in ",(0,s.jsx)(n.code,{children:"app.go"}),"."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsxs)(n.strong,{children:["You must add ",(0,s.jsx)(n.code,{children:'"/interchain_security.ccv.consumer.v1.MsgUpdateParams"'})," to your parameters whitelist to be able to change ",(0,s.jsx)(n.code,{children:"ccvconsumer"})," parameters via governance."]})}),"\n",(0,s.jsxs)(n.p,{children:["It is available when using ",(0,s.jsx)(n.code,{children:"gov"})," CLI commands:"]}),"\n",(0,s.jsx)(n.p,{children:"Drafting a proposal:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:'interchain-security-cd tx gov draft-proposal\n# select "other"\n# find and select "/interchain_security.ccv.consumer.v1.MsgUpdateParams"\n'})}),"\n",(0,s.jsx)(n.p,{children:"Submitting a proposal:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsxs)(n.strong,{children:["this proposal cannot be executed on chains without access to ",(0,s.jsx)(n.code,{children:"x/gov"})," or other modules for managing governance"]})}),"\n"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:"\ninterchain-security-cdd tx gov submit-proposal <proposal-message.json>\n\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Example ",(0,s.jsx)(n.code,{children:"proposal-message.json"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "messages": [\n {\n "@type": "/interchain_security.ccv.consumer.v1.MsgUpdateParams",\n "authority": "consumer10d07y265gmmuvt4z0w9aw880jnsr700jlh7295",\n "params": {\n "enabled": true,\n "blocks_per_distribution_transmission": "20",\n "distribution_transmission_channel": "channel-1",\n "provider_fee_pool_addr_str": "",\n "ccv_timeout_period": "2419200s",\n "transfer_timeout_period": "3000s",\n "consumer_redistribution_fraction": "0.75",\n "historical_entries": "10000",\n "unbonding_period": "1209600s",\n "soft_opt_out_threshold": "0.05",\n "reward_denoms": [],\n "provider_reward_denoms": [],\n "retry_delay_period": "3000s"\n }\n }\n ],\n "metadata": "ipfs://CID",\n "deposit": "1000uatom",\n "title": "Update Consumer Params -- change transfer_timeout_period to 3000s",\n "summary": "Test Update Consumer Params",\n "expedited": false\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["When updating parameters ",(0,s.jsx)(n.strong,{children:"all"})," parameters fields must be specified. Make sure you are only changing parameters that you are interested in."]}),"\n",(0,s.jsx)(n.p,{children:"To avoid accidentally changing parameters you can first check the current on-chain consumer params using:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:"interchain-security-pd q ccvconsumer params -o json\n"})}),"\n",(0,s.jsx)(n.h4,{id:"params-query",children:"Params Query"}),"\n",(0,s.jsx)(n.p,{children:"Consumer params query was added:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-shell",children:'interchain-security-cd q ccvconsumer params -o json\n\n{\n "params": {\n "enabled": true,\n "blocks_per_distribution_transmission": "1000",\n "distribution_transmission_channel": "",\n "provider_fee_pool_addr_str": "",\n "ccv_timeout_period": "2419200s",\n "transfer_timeout_period": "3600s",\n "consumer_redistribution_fraction": "0.75",\n "historical_entries": "10000",\n "unbonding_period": "1209600s",\n "soft_opt_out_threshold": "0.05",\n "reward_denoms": [],\n "provider_reward_denoms": [],\n "retry_delay_period": "3600s"\n }\n}\n'})}),"\n",(0,s.jsx)(n.h3,{id:"migration-v2---v3",children:"Migration (v2 -> v3)"}),"\n",(0,s.jsxs)(n.p,{children:["ConensusVersion was bumped to ",(0,s.jsx)(n.code,{children:"3"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["The migration allows storing the consumer module params in the ",(0,s.jsx)(n.code,{children:"x/ccv/consumer"})," module store instead of relying on legacy ",(0,s.jsx)(n.code,{children:"x/param"})," store."]}),"\n",(0,s.jsx)(n.p,{children:"There are no special requirements for executing this migration."}),"\n",(0,s.jsx)(n.h3,{id:"interface-method-changes",children:"Interface method changes"}),"\n",(0,s.jsxs)(n.p,{children:["Consumer methods were changed to match the cosmos-sdk ",(0,s.jsx)(n.code,{children:"StakingKeeper"})," interface.\nYou will not need to change your code, unless you are using the ",(0,s.jsx)(n.code,{children:"ConsumerKeeper"})," inside custom tests or you have developed custom app functionality that relies on ",(0,s.jsx)(n.code,{children:"ConsumerKeeper"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"Please check the list below if you are using any of the consumer methods:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-go",children:"type StakingKeeper interface {\n UnbondingTime(ctx context.Context) (time.Duration, error)\n GetValidatorByConsAddr(ctx context.Context, consAddr sdk.ConsAddress) (stakingtypes.Validator, error)\n GetLastValidatorPower(ctx context.Context, operator sdk.ValAddress) (int64, error)\n Jail(context.Context, sdk.ConsAddress) error // jail a validator\n Slash(ctx context.Context, consAddr sdk.ConsAddress, infractionHeight, power int64, slashFactor math.LegacyDec) (math.Int, error)\n SlashWithInfractionReason(ctx context.Context, consAddr sdk.ConsAddress, infractionHeight, power int64, slashFactor math.LegacyDec, infraction stakingtypes.Infraction) (math.Int, error)\n Unjail(ctx context.Context, addr sdk.ConsAddress) error\n GetValidator(ctx context.Context, addr sdk.ValAddress) (stakingtypes.Validator, error)\n IterateLastValidatorPowers(ctx context.Context, cb func(addr sdk.ValAddress, power int64) (stop bool)) error\n IterateValidators(ctx context.Context, f func(index int64, validator stakingtypes.ValidatorI) (stop bool)) error\n Validator(ctx context.Context, addr sdk.ValAddress) (stakingtypes.ValidatorI, error)\n IsValidatorJailed(ctx context.Context, addr sdk.ConsAddress) (bool, error)\n ValidatorByConsAddr(ctx context.Context, consAddr sdk.ConsAddress) (stakingtypes.ValidatorI, error)\n Delegation(ctx context.Context, addr sdk.AccAddress, valAddr sdk.ValAddress) (stakingtypes.DelegationI, error)\n MaxValidators(ctx context.Context) (uint32, error)\n}\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The consumer implements the ",(0,s.jsx)(n.code,{children:"StakingKeeper"})," interface shown above."]}),"\n",(0,s.jsx)(n.h2,{id:"democracy",children:"Democracy"}),"\n",(0,s.jsxs)(n.p,{children:["Changes in ",(0,s.jsx)(n.code,{children:"Consumer"})," also apply to ",(0,s.jsx)(n.code,{children:"Democracy"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["Democracy ",(0,s.jsx)(n.code,{children:"x/staking"}),", ",(0,s.jsx)(n.code,{children:"x/distribution"})," and ",(0,s.jsx)(n.code,{children:"x/gov"})," were updated to reflect changes in ",(0,s.jsx)(n.code,{children:"cosmos-sdk v0.50.x"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["There were no notable changes arising to the module functionality aside from conforming to ",(0,s.jsx)(n.code,{children:"cosmos-sdk v0.50.x"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"note",children:"Note:"}),"\n",(0,s.jsxs)(n.p,{children:["You must add ",(0,s.jsx)(n.code,{children:'"/interchain_security.ccv.consumer.v1.MsgUpdateParams"'})," to your parameters whitelist to be able to change ",(0,s.jsx)(n.code,{children:"consumer"})," parameters via governance."]})]})}function p(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},1151:(e,n,r)=>{r.d(n,{Z:()=>t,a:()=>a});var s=r(7294);const i={},o=s.createContext(i);function a(e){const n=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function t(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/536acd9c.29001796.js b/assets/js/536acd9c.29001796.js new file mode 100644 index 0000000000..2add7ac9ef --- /dev/null +++ b/assets/js/536acd9c.29001796.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4279],{8276:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>s,metadata:()=>r,toc:()=>c});var i=a(5893),t=a(1151);const s={sidebar_position:4},o="Validator Instructions for Changeover Procedure",r={id:"validators/changeover-procedure",title:"Validator Instructions for Changeover Procedure",description:"More details available in Changeover Procedure documentation.",source:"@site/versioned_docs/version-v4.2.0-docs/validators/changeover-procedure.md",sourceDirName:"validators",slug:"/validators/changeover-procedure",permalink:"/interchain-security/v4.2.0/validators/changeover-procedure",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Withdrawing consumer chain validator rewards",permalink:"/interchain-security/v4.2.0/validators/withdraw_rewards"},next:{title:"Joining Neutron",permalink:"/interchain-security/v4.2.0/validators/joining-neutron"}},d={},c=[{value:"Timeline",id:"timeline",level:2},{value:"1. <code>ConsumerAdditionProposal</code> on provider chain",id:"1-consumeradditionproposal-on-provider-chain",level:3},{value:"2. <code>SoftwareUpgradeProposal</code> on the standalone/consumer chain",id:"2-softwareupgradeproposal-on-the-standaloneconsumer-chain",level:3},{value:"3. Assigning a consumer key",id:"3-assigning-a-consumer-key",level:3},{value:"4. Perform the software upgrade on standalone chain",id:"4-perform-the-software-upgrade-on-standalone-chain",level:3},{value:"FAQ",id:"faq",level:2},{value:"Can I reuse the same validator key for the <code>consumer</code> chain that I am already using on the <code>standalone</code> chain? Will I need to perform a <code>AssignConsumerKey</code> tx with this key before spawn time?",id:"can-i-reuse-the-same-validator-key-for-the-consumer-chain-that-i-am-already-using-on-the-standalone-chain-will-i-need-to-perform-a-assignconsumerkey-tx-with-this-key-before-spawn-time",level:3},{value:"Can I continue using the same node that was validating the <code>standalone</code> chain?",id:"can-i-continue-using-the-same-node-that-was-validating-the-standalone-chain",level:3},{value:"Can I set up a new node to validate the <code>standalone/consumer</code> chain after it transitions to replicated security?",id:"can-i-set-up-a-new-node-to-validate-the-standaloneconsumer-chain-after-it-transitions-to-replicated-security",level:3},{value:"What happens to the <code>standalone</code> validator set after it transitions to replicated security?",id:"what-happens-to-the-standalone-validator-set-after-it-transitions-to-replicated-security",level:3},{value:"Credits",id:"credits",level:2}];function l(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"validator-instructions-for-changeover-procedure",children:"Validator Instructions for Changeover Procedure"}),"\n",(0,i.jsxs)(n.p,{children:["More details available in ",(0,i.jsx)(n.a,{href:"/interchain-security/v4.2.0/consumer-development/changeover-procedure",children:"Changeover Procedure documentation"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"A major difference between launching a new consumer chain vs. onboarding a standalone chain to ICS is that there is no consumer genesis available for the standalone chain. Since a standalone chain already exists, its state must be preserved once it transitions to being a consumer chain."}),"\n",(0,i.jsx)(n.h2,{id:"timeline",children:"Timeline"}),"\n",(0,i.jsxs)(n.p,{children:["Upgrading standalone chains can be best visualised using a timeline, such as the one available ",(0,i.jsx)(n.a,{href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt",children:"Excalidraw graphic by Stride"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"There is some flexibility with regards to how the changeover procedure is executed, so please make sure to follow the guides provided by the team doing the changeover."}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Standalone to consumer transition timeline",src:a(7509).Z+"",width:"5307",height:"2157"})}),"\n",(0,i.jsxs)(n.h3,{id:"1-consumeradditionproposal-on-provider-chain",children:["1. ",(0,i.jsx)(n.code,{children:"ConsumerAdditionProposal"})," on provider chain"]}),"\n",(0,i.jsxs)(n.p,{children:["This step will add the standalone chain to the list of consumer chains secured by the provider.\nThis step dictates the ",(0,i.jsx)(n.code,{children:"spawn_time"}),". After ",(0,i.jsx)(n.code,{children:"spawn_time"})," the CCV state (initial validator set of the provider) will be available to the consumer."]}),"\n",(0,i.jsx)(n.p,{children:"To obtain it from the provider use:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad q provider consumer-genesis stride-1 -o json > ccv-state.json\njq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' genesis.json ccv-state.json > ccv.json\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Transformation of the exported consumer genesis state to the target version of the consumer might be needed in case the provider and consumer formats are incompatible.\nRefer to the compatibility notes ",(0,i.jsx)(n.a,{href:"../../../RELEASES.md#backwards-compatibility",children:"here"})," to check if data transformation is needed for your case.\nInstructions on how to transform the exported CCV genesis state (",(0,i.jsx)(n.code,{children:"ccv-state.json"})," in the example above) to the required target version can be found ",(0,i.jsx)(n.a,{href:"/interchain-security/v4.2.0/consumer-development/consumer-genesis-transformation",children:"here"})]}),"\n",(0,i.jsxs)(n.h3,{id:"2-softwareupgradeproposal-on-the-standaloneconsumer-chain",children:["2. ",(0,i.jsx)(n.code,{children:"SoftwareUpgradeProposal"})," on the standalone/consumer chain"]}),"\n",(0,i.jsx)(n.p,{children:"This upgrade proposal will introduce ICS to the standalone chain, making it a consumer."}),"\n",(0,i.jsx)(n.h3,{id:"3-assigning-a-consumer-key",children:"3. Assigning a consumer key"}),"\n",(0,i.jsxs)(n.p,{children:["After ",(0,i.jsx)(n.code,{children:"spawn_time"}),", make sure to assign a consumer key if you intend to use one."]}),"\n",(0,i.jsxs)(n.p,{children:["Instructions are available ",(0,i.jsx)(n.a,{href:"/interchain-security/v4.2.0/features/key-assignment",children:"here"})]}),"\n",(0,i.jsx)(n.h3,{id:"4-perform-the-software-upgrade-on-standalone-chain",children:"4. Perform the software upgrade on standalone chain"}),"\n",(0,i.jsx)(n.p,{children:"Please use instructions provided by the standalone chain team and make sure to reach out if you are facing issues.\nThe upgrade preparation depends on your setup, so please make sure you prepare ahead of time."}),"\n",(0,i.jsxs)(n.admonition,{type:"danger",children:[(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"ccv.json"})," from step 1. must be made available on the machine running the standalone/consumer chain at standalone chain ",(0,i.jsx)(n.code,{children:"upgrade_height"}),". This file contains the initial validator set and parameters required for normal ICS operation."]}),(0,i.jsxs)(n.p,{children:["Usually, the file is placed in ",(0,i.jsx)(n.code,{children:"$NODE_HOME/config"})," but this is not a strict requirement. The exact details are available in the upgrade code of the standalone/consumer chain."]})]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Performing this upgrade will transition the standalone chain to be a consumer chain."})}),"\n",(0,i.jsxs)(n.p,{children:['After 3 blocks, the standalone chain will stop using the "old" validator set and begin using the ',(0,i.jsx)(n.code,{children:"provider"})," validator set."]}),"\n",(0,i.jsx)(n.h2,{id:"faq",children:"FAQ"}),"\n",(0,i.jsxs)(n.h3,{id:"can-i-reuse-the-same-validator-key-for-the-consumer-chain-that-i-am-already-using-on-the-standalone-chain-will-i-need-to-perform-a-assignconsumerkey-tx-with-this-key-before-spawn-time",children:["Can I reuse the same validator key for the ",(0,i.jsx)(n.code,{children:"consumer"})," chain that I am already using on the ",(0,i.jsx)(n.code,{children:"standalone"})," chain? Will I need to perform a ",(0,i.jsx)(n.code,{children:"AssignConsumerKey"})," tx with this key before spawn time?"]}),"\n",(0,i.jsxs)(n.p,{children:["Validators must either assign a key or use the same key as on the ",(0,i.jsx)(n.code,{children:"provider"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["If you are validating both the ",(0,i.jsx)(n.code,{children:"standalone"})," and the ",(0,i.jsx)(n.code,{children:"provider"}),", you ",(0,i.jsx)(n.strong,{children:"can"})," use your current ",(0,i.jsx)(n.code,{children:"standalone"})," key with some caveats:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["you must submit an ",(0,i.jsx)(n.code,{children:"AssignConsumerKey"})," tx with your current ",(0,i.jsx)(n.code,{children:"standalone"})," validator key"]}),"\n",(0,i.jsxs)(n.li,{children:["it is best to submit ",(0,i.jsx)(n.code,{children:"AssignConsumerKey"})," tx before ",(0,i.jsx)(n.code,{children:"spawn_time"})]}),"\n",(0,i.jsxs)(n.li,{children:["if you do not submit the Tx, it is assumed that you will be re-using your ",(0,i.jsx)(n.code,{children:"provider"})," key to validate the ",(0,i.jsx)(n.code,{children:"standalone/consumer"})," chain"]}),"\n"]}),"\n",(0,i.jsxs)(n.h3,{id:"can-i-continue-using-the-same-node-that-was-validating-the-standalone-chain",children:["Can I continue using the same node that was validating the ",(0,i.jsx)(n.code,{children:"standalone"})," chain?"]}),"\n",(0,i.jsx)(n.p,{children:"Yes."}),"\n",(0,i.jsx)(n.p,{children:"Please assign your consensus key as stated above."}),"\n",(0,i.jsxs)(n.h3,{id:"can-i-set-up-a-new-node-to-validate-the-standaloneconsumer-chain-after-it-transitions-to-replicated-security",children:["Can I set up a new node to validate the ",(0,i.jsx)(n.code,{children:"standalone/consumer"})," chain after it transitions to replicated security?"]}),"\n",(0,i.jsx)(n.p,{children:"Yes."}),"\n",(0,i.jsxs)(n.p,{children:["If you are planning to do this please make sure that the node is synced with ",(0,i.jsx)(n.code,{children:"standalone"})," network and to submit ",(0,i.jsx)(n.code,{children:"AssignConsumerKey"})," tx before ",(0,i.jsx)(n.code,{children:"spawn_time"}),"."]}),"\n",(0,i.jsxs)(n.h3,{id:"what-happens-to-the-standalone-validator-set-after-it-transitions-to-replicated-security",children:["What happens to the ",(0,i.jsx)(n.code,{children:"standalone"})," validator set after it transitions to replicated security?"]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"standalone"})," chain validators will stop being validators after the first 3 blocks are created while using replicated security. The ",(0,i.jsx)(n.code,{children:"standalone"})," validators will become ",(0,i.jsx)(n.strong,{children:"governors"})," and still can receive delegations if the ",(0,i.jsx)(n.code,{children:"consumer"})," chain is using the ",(0,i.jsx)(n.code,{children:"consumer-democracy"})," module."]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Governors DO NOT VALIDATE BLOCKS"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"Instead, they can participate in the governance process and take on other chain-specific roles."}),"\n",(0,i.jsx)(n.h2,{id:"credits",children:"Credits"}),"\n",(0,i.jsx)(n.p,{children:"Thank you Stride team for providing detailed instructions about the changeover procedure."})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},7509:(e,n,a)=>{a.d(n,{Z:()=>i});const i=a.p+"assets/images/ics_changeover_timeline_stride-9bcad1834fef24a0fea7f2c80c9ccd71.png"},1151:(e,n,a)=>{a.d(n,{Z:()=>r,a:()=>o});var i=a(7294);const t={},s=i.createContext(t);function o(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/54e4400b.e2f60025.js b/assets/js/54e4400b.e2f60025.js new file mode 100644 index 0000000000..9b22e744f6 --- /dev/null +++ b/assets/js/54e4400b.e2f60025.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2344],{6064:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>d,contentTitle:()=>i,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>c});var r=s(5893),t=s(1151);const a={sidebar_position:3,title:"Key Assignment"},i="ADR 001: Key Assignment",o={id:"adrs/adr-001-key-assignment",title:"Key Assignment",description:"Changelog",source:"@site/docs/adrs/adr-001-key-assignment.md",sourceDirName:"adrs",slug:"/adrs/adr-001-key-assignment",permalink:"/interchain-security/adrs/adr-001-key-assignment",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Key Assignment"},sidebar:"tutorialSidebar",previous:{title:"Pause validator unbonding during equivocation proposal",permalink:"/interchain-security/adrs/adr-007-pause-unbonding-on-eqv-prop"},next:{title:"Jail Throttling",permalink:"/interchain-security/adrs/adr-002-throttle"}},d={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"State required",id:"state-required",level:3},{value:"Protocol overview",id:"protocol-overview",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,t.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"adr-001-key-assignment",children:"ADR 001: Key Assignment"}),"\n",(0,r.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"2022-12-01: Initial Draft"}),"\n",(0,r.jsx)(n.li,{children:"2024-03-01: Updated to take into account they key-assigment-replacement deprecation."}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,r.jsx)(n.p,{children:"Accepted"}),"\n",(0,r.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,r.jsx)(n.p,{children:"KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate."}),"\n",(0,r.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,r.jsxs)(n.p,{children:["It is possible to change the keys at any time by submitting a transaction (i.e., ",(0,r.jsx)(n.code,{children:"MsgAssignConsumerKey"}),")."]}),"\n",(0,r.jsx)(n.h3,{id:"state-required",children:"State required"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"ValidatorConsumerPubKey"})," - Stores the validator assigned keys for every consumer chain."]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey\n"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"ValidatorByConsumerAddr"})," - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol."]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress\n"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"ConsumerAddrsToPrune"})," - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ",(0,r.jsx)(n.code,{children:"ValidatorByConsumerAddr"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses\n"})}),"\n",(0,r.jsx)(n.h3,{id:"protocol-overview",children:"Protocol overview"}),"\n",(0,r.jsxs)(n.p,{children:["On receiving a ",(0,r.jsx)(n.code,{children:"MsgAssignConsumerKey(chainID, providerAddr, consumerKey)"})," message:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"// get validator from staking module \nvalidator, found := stakingKeeper.GetValidator(providerAddr)\nif !found {\n return ErrNoValidatorFound\n}\nproviderConsAddr := validator.GetConsAddr()\n\n// make sure consumer key is not in use\nconsumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)\nif _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {\n return ErrInvalidConsumerConsensusPubKey\n}\n\n// check whether the consumer chain is already registered\n// i.e., a client to the consumer was already created\nif _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {\n // get the previous key assigned for this validator on this consumer chain\n oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)\n if found {\n // mark this old consumer key as prunable once the VSCMaturedPacket\n // for the current VSC ID is received\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n vscID := GetValidatorSetUpdateId()\n AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)\n }\n} else {\n // if the consumer chain is not registered, then remove the previous reverse mapping\n if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)\n }\n}\n\n\n// set the mapping from this validator's provider address to the new consumer key\nSetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)\n\n// set the reverse mapping: from this validator's new consensus address \n// on the consumer to its consensus address on the provider\nSetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)\n"})}),"\n",(0,r.jsxs)(n.p,{children:["When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see ",(0,r.jsx)(n.code,{children:"MakeConsumerGenesis"}),")."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {\n // ...\n // get initial valset from the staking module\n var updates []abci.ValidatorUpdate{}\n stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {\n validator := stakingKeeper.GetValidator(providerAddr)\n providerKey := validator.TmConsPublicKey()\n\t\tupdates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})\n\t\treturn false\n\t})\n\n // applies the key assignment to the initial validator\n\tfor i, update := range updates {\n\t\tproviderAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)\n\t\tif consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {\n\t\t\tupdates[i].PubKey = consumerKey\n\t\t}\n\t}\n gen.InitialValSet = updates\n\n // get a hash of the consumer validator set from the update\n\tupdatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)\n\thash := tendermint.NewValidatorSet(updatesAsValSet).Hash()\n\n\treturn gen, hash, nil\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Note that key assignment works hand-in-hand with ",(0,r.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-014-epochs.md",children:"epochs"}),".\nFor each consumer chain, we store the consumer validator set that is currently (i.e., in this epoch) validating the consumer chain.\nSpecifically, for each validator in the set we store among others, the public key that it is using on the consumer chain during the current (i.e., ongoing) epoch.\nAt the end of every epoch, if there were validator set changes on the provider, then for every consumer chain, we construct a ",(0,r.jsx)(n.code,{children:"VSCPacket"}),"\nwith all the validator updates and add it to the list of ",(0,r.jsx)(n.code,{children:"PendingVSCPacket"}),"s. We compute the validator updates needed by a consumer chain by\ncomparing the stored list of consumer validators with the current bonded validators on the provider, with something similar to this:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"// get the valset that has been validating the consumer chain during this epoch \ncurrentValidators := GetConsumerValSet(consumerChain)\n// generate the validator updates needed to be sent through a `VSCPacket` by comparing the current validators \n// in the epoch with the latest bonded validators\nvalUpdates := DiffValidators(currentValidators, stakingmodule.GetBondedValidators())\n// update the current validators set for the upcoming epoch to be the latest bonded validators instead\nSetConsumerValSet(stakingmodule.GetBondedValidators())\n"})}),"\n",(0,r.jsxs)(n.p,{children:["where ",(0,r.jsx)(n.code,{children:"DiffValidators"})," internally checks if the consumer public key for a validator has changed since the last\nepoch and if so generates a validator update. This way, a validator can change its consumer public key for a consumer\nchain an arbitrary amount of times and only the last set consumer public key would be taken into account."]}),"\n",(0,r.jsxs)(n.p,{children:["On receiving a ",(0,r.jsx)(n.code,{children:"SlashPacket"})," from a consumer chain with id ",(0,r.jsx)(n.code,{children:"chainID"})," for a infraction of a validator ",(0,r.jsx)(n.code,{children:"data.Validator"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {\n // ...\n // the slash packet validator address may be known only on the consumer chain;\n\t// in this case, it must be mapped back to the consensus address on the provider chain\n consumerAddr := sdk.ConsAddress(data.Validator.Address)\n providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)\n if !found {\n // the validator has the same key on the consumer as on the provider\n providerAddr = consumerAddr\n }\n // ...\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["On receiving a ",(0,r.jsx)(n.code,{children:"VSCMatured"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {\n // ...\n // prune previous consumer validator address that are no longer needed\n consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n\tfor _, addr := range consumerAddrs {\n\t\tDeleteValidatorByConsumerAddr(chainID, addr)\n\t}\n\tDeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n // ...\n}\n"})}),"\n",(0,r.jsx)(n.p,{children:"On stopping a consumer chain:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {\n // ...\n // deletes all the state needed for key assignments on this consumer chain\n // ...\n}\n"})}),"\n",(0,r.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,r.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Validators can use different consensus keys on the consumer chains."}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"None"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["The consensus state necessary to create a client to the consumer chain must use the hash returned by the ",(0,r.jsx)(n.code,{children:"MakeConsumerGenesis"})," method as the ",(0,r.jsx)(n.code,{children:"nextValsHash"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:["The consumer chain can no longer check the initial validator set against the consensus state on ",(0,r.jsx)(n.code,{children:"InitGenesis"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/26",children:"Key assignment issue"})}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},1151:(e,n,s)=>{s.d(n,{Z:()=>o,a:()=>i});var r=s(7294);const t={},a=r.createContext(t);function i(e){const n=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:i(e.components),r.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/578fb1aa.9d55eaef.js b/assets/js/578fb1aa.9d55eaef.js new file mode 100644 index 0000000000..2d61664424 --- /dev/null +++ b/assets/js/578fb1aa.9d55eaef.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2323],{8522:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>l,frontMatter:()=>s,metadata:()=>a,toc:()=>c});var i=r(5893),t=r(1151);const s={sidebar_position:2},o="Reward Distribution",a={id:"features/reward-distribution",title:"Reward Distribution",description:"Sending and distributing rewards from consumer chains to the provider chain is handled by the Reward Distribution sub-protocol.",source:"@site/docs/features/reward-distribution.md",sourceDirName:"features",slug:"/features/reward-distribution",permalink:"/interchain-security/features/reward-distribution",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/features/key-assignment"},next:{title:"ICS Provider Proposals",permalink:"/interchain-security/features/proposals"}},d={},c=[{value:"Whitelisting Reward Denoms",id:"whitelisting-reward-denoms",level:2}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,t.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"reward-distribution",children:"Reward Distribution"}),"\n",(0,i.jsxs)(n.p,{children:["Sending and distributing rewards from consumer chains to the provider chain is handled by the ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md#reward-distribution",children:"Reward Distribution sub-protocol"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["Consumer chains have the option of sharing (a portion of) their block rewards (inflation tokens and fees) with the provider chain validators and delegators.\nIn Interchain Security, block rewards are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel.\nThis channel is created during consumer chain initialization, unless it is provided via the ",(0,i.jsx)(n.code,{children:"ConsumerAdditionProposal"})," when adding a new consumer chain.\nFor more details, see the ",(0,i.jsx)(n.a,{href:"/interchain-security/introduction/params#reward-distribution-parameters",children:"reward distribution parameters"}),"."]}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["Providing an IBC transfer channel (see ",(0,i.jsx)(n.code,{children:"DistributionTransmissionChannel"}),") enables a consumer chain to re-use one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ",(0,i.jsx)(n.code,{children:"ibc denom"})," that may already be in use.\nThis is especially important for standalone chains transitioning to become consumer chains.\nFor more details, see the ",(0,i.jsx)(n.a,{href:"/interchain-security/consumer-development/changeover-procedure",children:"changeover procedure"}),"."]})}),"\n",(0,i.jsx)(n.p,{children:"Reward distribution on the provider is handled by the distribution module."}),"\n",(0,i.jsx)(n.h2,{id:"whitelisting-reward-denoms",children:"Whitelisting Reward Denoms"}),"\n",(0,i.jsxs)(n.p,{children:["The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the ",(0,i.jsx)(n.code,{children:"ConsumerRewardsPool"}),".\nTo avoid spam, the provider must whitelist denoms before accepting them as ICS rewards.\nOnly whitelisted denoms are transferred from the ",(0,i.jsx)(n.code,{children:"ConsumerRewardsPool"})," to the ",(0,i.jsx)(n.code,{children:"FeePoolAddress"}),", to be distributed to delegators and validators.\nThe whitelisted denoms can be adjusted through governance by sending a ",(0,i.jsx)(n.a,{href:"/interchain-security/features/proposals#changerewarddenomproposal",children:(0,i.jsx)(n.code,{children:"ChangeRewardDenomProposal"})}),"."]}),"\n",(0,i.jsx)(n.p,{children:"To query the list of whitelisted reward denoms on the Cosmos Hub, use the following command:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"> gaiad q provider registered-consumer-reward-denoms\ndenoms:\n- ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5\n- ibc/6B8A3F5C2AD51CD6171FA41A7E8C35AD594AB69226438DB94450436EA57B3A89\n- uatom\n"})}),"\n",(0,i.jsxs)(n.admonition,{type:"tip",children:[(0,i.jsxs)(n.p,{children:["Use the following command to get a human readable denom from the ",(0,i.jsx)(n.code,{children:"ibc/*"})," denom trace format:"]}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"> gaiad query ibc-transfer denom-trace ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5\ndenom_trace:\n base_denom: untrn\n path: transfer/channel-569\n"})})]})]})}function l(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},1151:(e,n,r)=>{r.d(n,{Z:()=>a,a:()=>o});var i=r(7294);const t={},s=i.createContext(t);function o(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/5cdffc34.eacf780d.js b/assets/js/5cdffc34.eacf780d.js new file mode 100644 index 0000000000..533c5b1dbd --- /dev/null +++ b/assets/js/5cdffc34.eacf780d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4895],{8961:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>l,frontMatter:()=>a,metadata:()=>o,toc:()=>h});var s=i(5893),t=i(1151);const a={sidebar_position:1},r="Overview",o={id:"validators/overview",title:"Overview",description:"We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.",source:"@site/versioned_docs/version-v5.0.0/validators/overview.md",sourceDirName:"validators",slug:"/validators/overview",permalink:"/interchain-security/v5.0.0/validators/overview",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Consumer Genesis Transformation",permalink:"/interchain-security/v5.0.0/consumer-development/consumer-genesis-transformation"},next:{title:"Joining Interchain Security testnet",permalink:"/interchain-security/v5.0.0/validators/joining-testnet"}},c={},h=[{value:"Startup sequence overview",id:"startup-sequence-overview",level:2},{value:"1. Consumer Chain init + 2. Genesis generation",id:"1-consumer-chain-init--2-genesis-generation",level:3},{value:"3. Submit Proposal",id:"3-submit-proposal",level:3},{value:"4. CCV Genesis state generation",id:"4-ccv-genesis-state-generation",level:3},{value:"5. Updating the genesis file",id:"5-updating-the-genesis-file",level:3},{value:"6. Chain start",id:"6-chain-start",level:3},{value:"7. Creating IBC connections",id:"7-creating-ibc-connections",level:3},{value:"Downtime Infractions",id:"downtime-infractions",level:2},{value:"Double-signing Infractions",id:"double-signing-infractions",level:2},{value:"Key assignment",id:"key-assignment",level:2},{value:"References:",id:"references",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"overview",children:"Overview"}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["We advise that you join the ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/testnets/tree/master/interchain-security",children:"Replicated Security testnet"})," to gain hands-on experience with running consumer chains."]})}),"\n",(0,s.jsx)(n.p,{children:"At present, replicated security requires all validators of the provider chain (ie. Cosmos Hub) to run validator nodes for all governance-approved consumer chains."}),"\n",(0,s.jsxs)(n.p,{children:["Once a ",(0,s.jsx)(n.code,{children:"ConsumerAdditionProposal"})," passes, validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains."]}),"\n",(0,s.jsx)(n.p,{children:"Provider chain and consumer chains represent standalone chains that only share the validator set ie. the same validator operators are tasked with running all chains."}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsx)(n.p,{children:"To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 180 validators for Cosmos Hub)."})}),"\n",(0,s.jsx)(n.h2,{id:"startup-sequence-overview",children:"Startup sequence overview"}),"\n",(0,s.jsxs)(n.p,{children:["Consumer chains cannot start and be secured by the validator set of the provider unless a ",(0,s.jsx)(n.code,{children:"ConsumerAdditionProposal"})," is passed.\nEach proposal contains defines a ",(0,s.jsx)(n.code,{children:"spawn_time"})," - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider."]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["Validators are required to run consumer chain binaries only after ",(0,s.jsx)(n.code,{children:"spawn_time"})," has passed."]})}),"\n",(0,s.jsx)(n.p,{children:"Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains."}),"\n",(0,s.jsxs)(n.p,{children:["The image below illustrates the startup sequence\n",(0,s.jsx)(n.img,{alt:"startup",src:i(9558).Z+"",width:"942",height:"632"})]}),"\n",(0,s.jsx)(n.h3,{id:"1-consumer-chain-init--2-genesis-generation",children:"1. Consumer Chain init + 2. Genesis generation"}),"\n",(0,s.jsxs)(n.p,{children:["Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ",(0,s.jsx)(n.code,{children:"ConsumerAdditionProposal"})]}),"\n",(0,s.jsx)(n.h3,{id:"3-submit-proposal",children:"3. Submit Proposal"}),"\n",(0,s.jsxs)(n.p,{children:["Consumer chain team (or their advocates) submits a ",(0,s.jsx)(n.code,{children:"ConsumerAdditionProposal"}),".\nThe most important parameters for validators are:"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"spawn_time"})," - the time after which the consumer chain must be started"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"genesis_hash"})," - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and ",(0,s.jsx)(n.code,{children:"spawn_time"})," is reached"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"binary_hash"})," - hash of the consumer chain binary used to validate the software builds"]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"4-ccv-genesis-state-generation",children:"4. CCV Genesis state generation"}),"\n",(0,s.jsxs)(n.p,{children:["After reaching ",(0,s.jsx)(n.code,{children:"spawn_time"})," the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain ",(0,s.jsx)(n.code,{children:"genesis.json"}),". The CCV validator set consists of the validator set on the provider at ",(0,s.jsx)(n.code,{children:"spawn_time"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"The state can be queried on the provider chain (in this case the Cosmos Hub):"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:" gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This is used by the launch coordinator to create the final ",(0,s.jsx)(n.code,{children:"genesis.json"})," that will be distributed to validators in step 5."]}),"\n",(0,s.jsx)(n.h3,{id:"5-updating-the-genesis-file",children:"5. Updating the genesis file"}),"\n",(0,s.jsxs)(n.p,{children:["Upon reaching the ",(0,s.jsx)(n.code,{children:"spawn_time"})," the initial validator set state will become available on the provider chain. The initial validator set is included in the ",(0,s.jsx)(n.strong,{children:"final genesis.json"})," of the consumer chain."]}),"\n",(0,s.jsx)(n.h3,{id:"6-chain-start",children:"6. Chain start"}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsx)(n.p,{children:"The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences."})}),"\n",(0,s.jsxs)(n.p,{children:["The new ",(0,s.jsx)(n.code,{children:"genesis.json"})," containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided ",(0,s.jsx)(n.code,{children:"genesis.json"})," to start their consumer chain node."]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["Please pay attention to any onboarding repositories provided by the consumer chain teams.\nRecommendations are available in ",(0,s.jsx)(n.a,{href:"/interchain-security/v5.0.0/consumer-development/onboarding",children:"Consumer Onboarding Checklist"}),".\nAnother comprehensive guide is available in the ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/CONSUMER_LAUNCH_GUIDE.md",children:"Interchain Security testnet repo"}),"."]})}),"\n",(0,s.jsx)(n.h3,{id:"7-creating-ibc-connections",children:"7. Creating IBC connections"}),"\n",(0,s.jsx)(n.p,{children:"Finally, to fully establish interchain security an IBC relayer is used to establish connections and create the required channels."}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsx)(n.p,{children:"The relayer can establish the connection only after the consumer chain starts producing blocks."})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> \nhermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1\nhermes start\n"})}),"\n",(0,s.jsx)(n.h2,{id:"downtime-infractions",children:"Downtime Infractions"}),"\n",(0,s.jsxs)(n.p,{children:["At present, the consumer chain can report evidence about downtime infractions to the provider chain. The ",(0,s.jsx)(n.code,{children:"min_signed_per_window"})," and ",(0,s.jsx)(n.code,{children:"signed_blocks_window"})," can be different on each consumer chain and are subject to changes via consumer chain governance."]}),"\n",(0,s.jsxs)(n.admonition,{type:"info",children:[(0,s.jsx)(n.p,{children:"Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains."}),(0,s.jsxs)(n.p,{children:["To unjail, the validator must wait for the jailing period to elapse on the provider chain and ",(0,s.jsx)(n.a,{href:"https://hub.cosmos.network/validators/validator-setup#unjail-validator",children:"submit an unjail transaction"})," on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains."]}),(0,s.jsxs)(n.p,{children:["More information is available in ",(0,s.jsx)(n.a,{href:"/interchain-security/v5.0.0/features/slashing#downtime-infractions",children:"Downtime Slashing documentation"})]})]}),"\n",(0,s.jsx)(n.h2,{id:"double-signing-infractions",children:"Double-signing Infractions"}),"\n",(0,s.jsxs)(n.p,{children:["To learn more about equivocation handling in interchain security check out the ",(0,s.jsx)(n.a,{href:"/interchain-security/v5.0.0/features/slashing",children:"Slashing"})," documentation section."]}),"\n",(0,s.jsx)(n.h2,{id:"key-assignment",children:"Key assignment"}),"\n",(0,s.jsx)(n.p,{children:"Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use."}),"\n",(0,s.jsxs)(n.p,{children:["For more information check out the ",(0,s.jsx)(n.a,{href:"/interchain-security/v5.0.0/features/key-assignment",children:"Key assignment overview and guide"})]}),"\n",(0,s.jsx)(n.h2,{id:"references",children:"References:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://hub.cosmos.network/validators/validator-faq",children:"Cosmos Hub Validators FAQ"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://hub.cosmos.network/validators/validator-setup",children:"Cosmos Hub Running a validator"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/CONSUMER_LAUNCH_GUIDE.md#chain-launch",children:"Startup Sequence"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://hub.cosmos.network/validators/validator-setup#unjail-validator",children:"Submit Unjailing Transaction"})}),"\n"]})]})}function l(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},9558:(e,n,i)=>{i.d(n,{Z:()=>s});const s=i.p+"assets/images/hypha-consumer-start-process-2141109f76c584706dd994d7965fd692.svg"},1151:(e,n,i)=>{i.d(n,{Z:()=>o,a:()=>r});var s=i(7294);const t={},a=s.createContext(t);function r(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:r(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/5cee3276.e8f98637.js b/assets/js/5cee3276.e8f98637.js new file mode 100644 index 0000000000..c4ed92676d --- /dev/null +++ b/assets/js/5cee3276.e8f98637.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1996],{434:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>l});var i=t(5893),o=t(1151);const r={sidebar_position:1},a="Overview",s={id:"introduction/overview",title:"Overview",description:"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.",source:"@site/versioned_docs/version-v5.0.0/introduction/overview.md",sourceDirName:"introduction",slug:"/introduction/overview",permalink:"/interchain-security/v5.0.0/introduction/overview",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Docs",permalink:"/interchain-security/v5.0.0/"},next:{title:"Terminology",permalink:"/interchain-security/v5.0.0/introduction/terminology"}},c={},l=[{value:"Why Replicated Security?",id:"why-replicated-security",level:2},{value:"Core protocol",id:"core-protocol",level:2},{value:"Downtime Slashing",id:"downtime-slashing",level:3},{value:"Tokenomics and Rewards",id:"tokenomics-and-rewards",level:3}];function d(e){const n={a:"a",admonition:"admonition",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,o.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"overview",children:"Overview"}),"\n",(0,i.jsxs)(n.admonition,{type:"info",children:[(0,i.jsx)(n.p,{children:"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another."}),(0,i.jsx)("br",{}),(0,i.jsx)(n.p,{children:'Replicated security allows anyone to launch a "consumer" blockchain using the same validator set as the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit the full security and decentralization of the provider.'})]}),"\n",(0,i.jsx)(n.h2,{id:"why-replicated-security",children:"Why Replicated Security?"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Full provider security. At launch, consumer chains are secured by the full validator set and market cap of the provider chain."}),"\n",(0,i.jsx)(n.li,{children:"Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum."}),"\n",(0,i.jsx)(n.li,{children:"Projects keep majority of gas fees. Depending on configuration, these fees either go to the project\u2019s community DAO, or can be used in the protocol in other ways."}),"\n",(0,i.jsx)(n.li,{children:"No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. A governance vote will take place for a chain to get adopted by the provider validators which will encourage participation and signal strong buy-in into the project's long-term success."}),"\n",(0,i.jsx)(n.li,{children:"Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set."}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"core-protocol",children:"Core protocol"}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["Protocol specification is available as ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md",children:"ICS-028"})," in the IBC repository."]})}),"\n",(0,i.jsx)(n.p,{children:"Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer."}),"\n",(0,i.jsx)(n.p,{children:"To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider."}),"\n",(0,i.jsx)(n.h3,{id:"downtime-slashing",children:"Downtime Slashing"}),"\n",(0,i.jsx)(n.p,{children:"If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period."}),"\n",(0,i.jsx)(n.h3,{id:"tokenomics-and-rewards",children:"Tokenomics and Rewards"}),"\n",(0,i.jsx)(n.p,{children:"Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance."})]})}function h(e={}){const{wrapper:n}={...(0,o.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>s,a:()=>a});var i=t(7294);const o={},r=i.createContext(o);function a(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function s(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:a(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/5e95c892.e9a018bf.js b/assets/js/5e95c892.e9a018bf.js new file mode 100644 index 0000000000..562d508c4f --- /dev/null +++ b/assets/js/5e95c892.e9a018bf.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9661],{1892:(e,s,r)=>{r.r(s),r.d(s,{default:()=>l});r(7294);var t=r(512),u=r(1944),a=r(5281),c=r(8790),n=r(6040),i=r(5893);function l(e){return(0,i.jsx)(u.FG,{className:(0,t.Z)(a.k.wrapper.docsPages),children:(0,i.jsx)(n.Z,{children:(0,c.H)(e.route.routes)})})}}}]); \ No newline at end of file diff --git a/assets/js/5fa9786a.fa4ac172.js b/assets/js/5fa9786a.fa4ac172.js new file mode 100644 index 0000000000..f6d8b5cc25 --- /dev/null +++ b/assets/js/5fa9786a.fa4ac172.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2341],{5370:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>c,contentTitle:()=>s,default:()=>l,frontMatter:()=>o,metadata:()=>a,toc:()=>d});var i=r(5893),t=r(1151);const o={sidebar_position:6},s="Consumer Genesis Transformation",a={id:"consumer-development/consumer-genesis-transformation",title:"Consumer Genesis Transformation",description:"Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentation on Onboarding and Changeover).",source:"@site/versioned_docs/version-v4.2.0-docs/consumer-development/consumer-genesis-transformation.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-genesis-transformation",permalink:"/interchain-security/v4.2.0/consumer-development/consumer-genesis-transformation",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"tutorialSidebar",previous:{title:"Changeover Procedure",permalink:"/interchain-security/v4.2.0/consumer-development/changeover-procedure"},next:{title:"Overview",permalink:"/interchain-security/v4.2.0/validators/overview"}},c={},d=[{value:"1. Prerequisite",id:"1-prerequisite",level:2},{value:"2. Export the CCV data",id:"2-export-the-ccv-data",level:2},{value:"3. Transform CCV data",id:"3-transform-ccv-data",level:2}];function h(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,t.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"consumer-genesis-transformation",children:"Consumer Genesis Transformation"}),"\n",(0,i.jsxs)(n.p,{children:["Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentation on ",(0,i.jsx)(n.a,{href:"/interchain-security/v4.2.0/consumer-development/onboarding",children:"Onboarding"})," and ",(0,i.jsx)(n.a,{href:"/interchain-security/v4.2.0/consumer-development/changeover-procedure",children:"Changeover"}),").\nIn case that the provider chain is running an older version of the InterChainSecurity (ICS) module than the consumer chain - or vice versa - the exported CCV data might need to be transformed to the format supported by the ICS implementation run on the consumer chain. This is the case if the consumer chain runs version 4 of ICS or later and the provider is running version 3 or older of the ICS module."]}),"\n",(0,i.jsxs)(n.p,{children:["Check the ",(0,i.jsx)(n.a,{href:"../../../RELEASES.md#backwards-compatibility",children:"compatibility notes"})," for known incompatibilities between provider and consumer versions and indications if a consumer genesis transformation is required."]}),"\n",(0,i.jsx)(n.p,{children:"To transform such CCV data follow the instructions below"}),"\n",(0,i.jsx)(n.h2,{id:"1-prerequisite",children:"1. Prerequisite"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["used provider and consumer versions require transformation step as indicated in in the ",(0,i.jsx)(n.a,{href:"../../../RELEASES.md#backwards-compatibility",children:"compatibility notes"})]}),"\n",(0,i.jsx)(n.li,{children:"interchain-security-cd application supports the versions used by the consumer and provider"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"2-export-the-ccv-data",children:"2. Export the CCV data"}),"\n",(0,i.jsxs)(n.p,{children:["Export the CCV data from the provider chain as described in the ",(0,i.jsx)(n.a,{href:"/interchain-security/v4.2.0/consumer-development/onboarding",children:"Onboarding"})," and ",(0,i.jsx)(n.a,{href:"/interchain-security/v4.2.0/consumer-development/changeover-procedure",children:"Changeover"})," your following.\nAs a result the CCV data will be stored in a file in JSON format."]}),"\n",(0,i.jsx)(n.h2,{id:"3-transform-ccv-data",children:"3. Transform CCV data"}),"\n",(0,i.jsx)(n.p,{children:"To transform the CCV data"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["to the format supported by the current version of the consumer run the following command:","\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"interchain-security-cd genesis transform [genesis-file]\n"})}),"\n","where 'genesis-file' is the path to the file containing the CCV data exported in ",(0,i.jsx)(n.a,{href:"#2-export-the-ccv-data",children:"step 2"}),".\nAs a result the CCV data in the new format will be written to standard output."]}),"\n",(0,i.jsxs)(n.li,{children:["a specific target version of a consumer run the following command:","\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"interchain-security-cd genesis transform --to <target_version> [genesis-file]\n\n"})}),"\n","where ",(0,i.jsx)(n.code,{children:"<target_version"})," is the ICS version the consumer chain is running.\nUse ",(0,i.jsx)(n.code,{children:"interchain-security-cd genesis transform --help"})," to get more details about supported target versions and more."]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Use the new CCV data as described in the procedure you're following."})]})}function l(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},1151:(e,n,r)=>{r.d(n,{Z:()=>a,a:()=>s});var i=r(7294);const t={},o=i.createContext(t);function s(e){const n=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:s(e.components),i.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/61e9b0fd.babea3e2.js b/assets/js/61e9b0fd.babea3e2.js new file mode 100644 index 0000000000..bd4e6c5778 --- /dev/null +++ b/assets/js/61e9b0fd.babea3e2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5402],{5615:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>h,contentTitle:()=>o,default:()=>l,frontMatter:()=>s,metadata:()=>a,toc:()=>c});var i=t(5893),r=t(1151);const s={sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},o=void 0,a={id:"frequently-asked-questions",title:"Frequently Asked Questions",description:"What is the meaning of Validator Set Replication?",source:"@site/versioned_docs/version-v5.0.0/frequently-asked-questions.md",sourceDirName:".",slug:"/faq",permalink:"/interchain-security/v5.0.0/faq",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:5,frontMatter:{sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},sidebar:"tutorialSidebar",previous:{title:"Joining Stride",permalink:"/interchain-security/v5.0.0/validators/joining-stride"},next:{title:"ADRs",permalink:"/interchain-security/v5.0.0/adrs/intro"}},h={},c=[{value:"What is the meaning of Validator Set Replication?",id:"what-is-the-meaning-of-validator-set-replication",level:2},{value:"What is a consumer chain?",id:"what-is-a-consumer-chain",level:2},{value:"What happens to consumer if provider is down?",id:"what-happens-to-consumer-if-provider-is-down",level:2},{value:"What happens to provider if consumer is down?",id:"what-happens-to-provider-if-consumer-is-down",level:2},{value:"Can I run the provider and consumer chains on the same machine?",id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine",level:2},{value:"Can the consumer chain have its own token?",id:"can-the-consumer-chain-have-its-own-token",level:2},{value:"How are Tx fees paid on consumer?",id:"how-are-tx-fees-paid-on-consumer",level:2},{value:"Are there any restrictions the consumer chains need to abide by?",id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by",level:2},{value:"What's in it for the validators and stakers?",id:"whats-in-it-for-the-validators-and-stakers",level:2},{value:"Can the consumer chain have its own governance?",id:"can-the-consumer-chain-have-its-own-governance",level:2},{value:"Can validators opt-out of replicated security?",id:"can-validators-opt-out-of-replicated-security",level:2},{value:"How does Equivocation Governance Slashing work?",id:"how-does-equivocation-governance-slashing-work",level:2},{value:"Can Consumer Chains perform Software Upgrades?",id:"can-consumer-chains-perform-software-upgrades",level:2},{value:"How can I connect to the testnets?",id:"how-can-i-connect-to-the-testnets",level:2},{value:"How do I start using ICS?",id:"how-do-i-start-using-ics",level:2},{value:"Which relayers are supported?",id:"which-relayers-are-supported",level:2},{value:"How does key delegation work in ICS?",id:"how-does-key-delegation-work-in-ics",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h2:"h2",li:"li",p:"p",strong:"strong",ul:"ul",...(0,r.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h2,{id:"what-is-the-meaning-of-validator-set-replication",children:"What is the meaning of Validator Set Replication?"}),"\n",(0,i.jsx)(n.p,{children:"VSR simply means that the same validator set is used to secure both the provider and consumer chains. VSR is ensured through ICS protocol which keeps consumers up to date with the validator set of the provider."}),"\n",(0,i.jsx)(n.h2,{id:"what-is-a-consumer-chain",children:"What is a consumer chain?"}),"\n",(0,i.jsx)(n.p,{children:"Consumer chain is blockchain operated by the same validator operators as the provider chain. The ICS protocol ensures the validator set replication properties (informs consumer chain about the current state of the validator set on the provider)"}),"\n",(0,i.jsx)(n.p,{children:"Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements."}),"\n",(0,i.jsx)(n.h2,{id:"what-happens-to-consumer-if-provider-is-down",children:"What happens to consumer if provider is down?"}),"\n",(0,i.jsx)(n.p,{children:"In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set."}),"\n",(0,i.jsx)(n.p,{children:"The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness."}),"\n",(0,i.jsxs)(n.p,{children:["However, if the ",(0,i.jsx)(n.code,{children:"trusting_period"})," (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain.\nThis means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about."]}),"\n",(0,i.jsx)(n.p,{children:'Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point.\nAt the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.'}),"\n",(0,i.jsx)(n.h2,{id:"what-happens-to-provider-if-consumer-is-down",children:"What happens to provider if consumer is down?"}),"\n",(0,i.jsx)(n.p,{children:"Consumer chains do not impact the provider chain.\nThe ICS protocol is concerned only with validator set replication and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events)."}),"\n",(0,i.jsx)(n.h2,{id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine",children:"Can I run the provider and consumer chains on the same machine?"}),"\n",(0,i.jsx)(n.p,{children:"Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation."}),"\n",(0,i.jsx)(n.h2,{id:"can-the-consumer-chain-have-its-own-token",children:"Can the consumer chain have its own token?"}),"\n",(0,i.jsx)(n.p,{children:"As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees."}),"\n",(0,i.jsx)(n.h2,{id:"how-are-tx-fees-paid-on-consumer",children:"How are Tx fees paid on consumer?"}),"\n",(0,i.jsx)(n.p,{children:"The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations."}),"\n",(0,i.jsx)(n.h2,{id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by",children:"Are there any restrictions the consumer chains need to abide by?"}),"\n",(0,i.jsx)(n.p,{children:"No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way.\nThe only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain."}),"\n",(0,i.jsx)(n.h2,{id:"whats-in-it-for-the-validators-and-stakers",children:"What's in it for the validators and stakers?"}),"\n",(0,i.jsxs)(n.p,{children:["The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by ",(0,i.jsx)(n.code,{children:"ConsumerRedistributionFraction"}),". The rewards are distributed (sent to the provider) every ",(0,i.jsx)(n.code,{children:"BlocksPerDistributionTransmission"}),"."]}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"ConsumerRedistributionFraction"})," and ",(0,i.jsx)(n.code,{children:"BlocksPerDistributionTransmission"})," are parameters defined in the ",(0,i.jsx)(n.code,{children:"ConsumerAdditionProposal"})," used to create the consumer chain. These parameters can be changed via consumer chain governance."]})}),"\n",(0,i.jsx)(n.h2,{id:"can-the-consumer-chain-have-its-own-governance",children:"Can the consumer chain have its own governance?"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Yes."})}),"\n",(0,i.jsx)(n.p,{children:'In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.'}),"\n",(0,i.jsx)(n.p,{children:"Validators can also be representatives but representatives are not required to run validator nodes."}),"\n",(0,i.jsx)(n.p,{children:"This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance."}),"\n",(0,i.jsx)(n.h2,{id:"can-validators-opt-out-of-replicated-security",children:"Can validators opt-out of replicated security?"}),"\n",(0,i.jsx)(n.p,{children:"At present, the validators cannot opt-out of validating consumer chains."}),"\n",(0,i.jsx)(n.p,{children:"There are multiple opt-out mechanisms under active research."}),"\n",(0,i.jsx)(n.h2,{id:"how-does-equivocation-governance-slashing-work",children:"How does Equivocation Governance Slashing work?"}),"\n",(0,i.jsx)(n.p,{children:"To avoid potential attacks directed at provider chain validators, a new mechanism was introduced:"}),"\n",(0,i.jsx)(n.p,{children:"When a validator double-signs on the consumer chain, a special type of slash packet is relayed to the provider chain. The provider will store information about the double signing validator and allow a governance proposal to be submitted.\nIf the double-signing proposal passes, the offending validator will be slashed on the provider chain and tombstoned. Tombstoning will permanently exclude the validator from the active set of the provider."}),"\n",(0,i.jsx)(n.admonition,{type:"caution",children:(0,i.jsx)(n.p,{children:"An equivocation proposal cannot be submitted for a validator that did not double sign on any of the consumer chains."})}),"\n",(0,i.jsx)(n.h2,{id:"can-consumer-chains-perform-software-upgrades",children:"Can Consumer Chains perform Software Upgrades?"}),"\n",(0,i.jsx)(n.p,{children:"Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM)."}),"\n",(0,i.jsx)(n.p,{children:"Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module."}),"\n",(0,i.jsx)(n.h2,{id:"how-can-i-connect-to-the-testnets",children:"How can I connect to the testnets?"}),"\n",(0,i.jsxs)(n.p,{children:["Check out the ",(0,i.jsx)(n.a,{href:"/interchain-security/v5.0.0/validators/joining-testnet",children:"Joining Replicated Security testnet"})," section."]}),"\n",(0,i.jsx)(n.h2,{id:"how-do-i-start-using-ics",children:"How do I start using ICS?"}),"\n",(0,i.jsxs)(n.p,{children:["To become a consumer chain use this ",(0,i.jsx)(n.a,{href:"/interchain-security/v5.0.0/consumer-development/onboarding",children:"checklist"})," and check the ",(0,i.jsx)(n.a,{href:"/interchain-security/v5.0.0/consumer-development/app-integration",children:"App integration section"})]}),"\n",(0,i.jsx)(n.h2,{id:"which-relayers-are-supported",children:"Which relayers are supported?"}),"\n",(0,i.jsx)(n.p,{children:"Currently supported versions:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Hermes 1.4.1"}),"\n",(0,i.jsxs)(n.li,{children:["Support for the CCV module was added to the Go ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/relayer",children:"relayer"})," in v2.2.0 but v2.4.0 has significant performance fixes which makes it the earliest suggested version to use."]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"how-does-key-delegation-work-in-ics",children:"How does key delegation work in ICS?"}),"\n",(0,i.jsxs)(n.p,{children:["You can check the ",(0,i.jsx)(n.a,{href:"/interchain-security/v5.0.0/features/key-assignment",children:"Key Assignment Guide"})," for specific instructions."]})]})}function l(e={}){const{wrapper:n}={...(0,r.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>a,a:()=>o});var i=t(7294);const r={},s=i.createContext(r);function o(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/624b8b53.ef004408.js b/assets/js/624b8b53.ef004408.js new file mode 100644 index 0000000000..ba2f068468 --- /dev/null +++ b/assets/js/624b8b53.ef004408.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9709],{1461:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>l,contentTitle:()=>t,default:()=>h,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var i=s(5893),o=s(1151);const r={sidebar_position:13,title:"Separate Releasing"},t="ADR 012: Separate Releasing",a={id:"adrs/adr-012-separate-releasing",title:"Separate Releasing",description:"Changelog",source:"@site/versioned_docs/version-v5.0.0/adrs/adr-012-separate-releasing.md",sourceDirName:"adrs",slug:"/adrs/adr-012-separate-releasing",permalink:"/interchain-security/v5.0.0/adrs/adr-012-separate-releasing",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:13,frontMatter:{sidebar_position:13,title:"Separate Releasing"},sidebar:"tutorialSidebar",previous:{title:"Improving testing and increasing confidence",permalink:"/interchain-security/v5.0.0/adrs/adr-011-improving-test-confidence"},next:{title:"Slashing on the provider for consumer equivocation",permalink:"/interchain-security/v5.0.0/adrs/adr-013-equivocation-slashing"}},l={},d=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Spike results",id:"spike-results",level:3},{value:"Why go.mod split is not the way to go",id:"why-gomod-split-is-not-the-way-to-go",level:3},{value:"Why separate repos is cool but also not the way to go",id:"why-separate-repos-is-cool-but-also-not-the-way-to-go",level:3},{value:"Decision",id:"decision",level:2},{value:"Example release flow",id:"example-release-flow",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function c(e){const n={a:"a",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",strong:"strong",ul:"ul",...(0,o.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"adr-012-separate-releasing",children:"ADR 012: Separate Releasing"}),"\n",(0,i.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[8/18/22,": Initial draft of idea in ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/801",children:"#801"})]}),"\n",(0,i.jsxs)(n.li,{children:[8/22/22,": Put idea in this ADR"]}),"\n",(0,i.jsxs)(n.li,{children:[.05,": Reject this ADR"]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(n.p,{children:"Rejected"}),"\n",(0,i.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,i.jsx)(n.h3,{id:"spike-results",children:"Spike results"}),"\n",(0,i.jsxs)(n.p,{children:["I explored the idea of ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/801",children:"#801"})," with this ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/tree/shawn%2Fgo-mod-split-aug-spike",children:"spike branch"}),". Here's my conclusions:"]}),"\n",(0,i.jsxs)(n.p,{children:["Splitting this repo to have multiple go.mods is possible. However there are various intricacies involved in decoupling the package hierarchy to have ",(0,i.jsx)(n.code,{children:"x/ccv/types"})," as the lowest level dep, with ",(0,i.jsx)(n.code,{children:"x/ccv/consumer"})," and ",(0,i.jsx)(n.code,{children:"x/ccv/provider"})," being one dep layer above, with high-level tests depending on all three of the mentioned packages. I'd estimate this decoupling would take 2-5 workdays to finish, and require significant review effort."]}),"\n",(0,i.jsx)(n.h3,{id:"why-gomod-split-is-not-the-way-to-go",children:"Why go.mod split is not the way to go"}),"\n",(0,i.jsxs)(n.p,{children:["Let's take a step back and remember the issue we're trying to solve - ",(0,i.jsx)(n.strong,{children:"We need a clean way to decouple semver/releasing for the consumer and provider modules"}),". After more consideration, splitting up go.mods gives us little benefit in achieving this. Reasons:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["The ",(0,i.jsx)(n.code,{children:"go.mod"})," dependency system is tied to git tags for the entire repo (ex: ",(0,i.jsx)(n.code,{children:"require github.com/cometbft/cometbft v0.37.2"})," refers to a historical tag for the entire cometbft repo)."]}),"\n",(0,i.jsx)(n.li,{children:"It'd be an odd dev experience to allow modules to reference past releases of other modules in the same repo. When would we ever want the consumer module to reference a past release of the types module for example?"}),"\n",(0,i.jsxs)(n.li,{children:["If we allow for ",(0,i.jsx)(n.code,{children:"go.mod"})," replace statements to build from local source code, why split up the package deps at all?"]}),"\n",(0,i.jsxs)(n.li,{children:["Splitting go.mods adds a bunch of complexity with ",(0,i.jsx)(n.code,{children:"go.work"})," files and all that shiz. VSCode does not play well with multiple module repos either."]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"why-separate-repos-is-cool-but-also-not-the-way-to-go",children:"Why separate repos is cool but also not the way to go"}),"\n",(0,i.jsxs)(n.p,{children:["All this considered, the cleanest solution to decoupling semver/releasing for the consumer and provider modules would be to have multiple repos, each with their own go.mod (3-4 repos total including high level tests). With this scheme we could separately tag each repo as changes are merged, they could share some code from ",(0,i.jsx)(n.code,{children:"types"})," being an external dep, etc."]}),"\n",(0,i.jsx)(n.p,{children:"I don't think any of us want to split up the monorepo, that's a lot of work and seems like bikeshedding. There's another solution that's very simple.."}),"\n",(0,i.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,i.jsxs)(n.p,{children:["Slightly adapting ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/cca008d856e3ffc60ec1a486871d0faa702abe26/CONTRIBUTING.md#semantic-versioning",children:"the current semver ruleset"}),":"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"A library API breaking change to EITHER the provider or consumer module will result in an increase of the MAJOR version number for BOTH modules (X.y.z-provider AND X.y.z-consumer)."}),"\n",(0,i.jsx)(n.li,{children:"A state breaking change (change requiring coordinated upgrade and/or state migration) will result in an increase of the MINOR version number for the AFFECTED module(s) (x.Y.z-provider AND/OR x.Y.z-consumer)."}),"\n",(0,i.jsx)(n.li,{children:"Any other changes (including node API breaking changes) will result in an increase of the PATCH version number for the AFFECTED module(s) (x.y.Z-provider AND/OR x.y.Z-consumer)."}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"example-release-flow",children:"Example release flow"}),"\n",(0,i.jsxs)(n.p,{children:["We upgrade ",(0,i.jsx)(n.code,{children:"main"})," to use a new version of SDK. This is a major version bump, triggering a new release for both the provider and consumer modules, ",(0,i.jsx)(n.code,{children:"v5.0.0-provider"})," and ",(0,i.jsx)(n.code,{children:"v5.0.0-consumer"}),"."]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["A state breaking change is merged to ",(0,i.jsx)(n.code,{children:"main"})," for the provider module. We release only a ",(0,i.jsx)(n.code,{children:"v5.1.0-provider"})," off main."]}),"\n",(0,i.jsxs)(n.li,{children:["Another state breaking change is merged to ",(0,i.jsx)(n.code,{children:"main"})," for the provider module. We release only a ",(0,i.jsx)(n.code,{children:"v5.2.0-provider"})," off main."]}),"\n",(0,i.jsxs)(n.li,{children:["At this point, the latest consumer version is still ",(0,i.jsx)(n.code,{children:"v5.0.0-consumer"}),". We now merge a state breaking change for the consumer module to ",(0,i.jsx)(n.code,{children:"main"}),", and consequently release ",(0,i.jsx)(n.code,{children:"v5.1.0-consumer"}),". Note that ",(0,i.jsx)(n.code,{children:"v5.1.0-consumer"})," is tagged off a LATER commit from main than ",(0,i.jsx)(n.code,{children:"v5.2.0-provider"}),". This is fine, as the consumer module should not be affected by the provider module's state breaking changes."]}),"\n",(0,i.jsxs)(n.li,{children:["Once either module sees a library API breaking change, we bump the major version for both modules. For example, we merge a library API breaking change to ",(0,i.jsx)(n.code,{children:"main"})," for the provider module. We release ",(0,i.jsx)(n.code,{children:"v6.0.0-provider"})," and ",(0,i.jsx)(n.code,{children:"v6.0.0-consumer"})," off main. Note that most often, a library API breaking change will affect both modules simultaneously (example being bumping sdk version)."]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,i.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Consumer repos have clear communication of what tagged versions are relevant to them. Consumer devs should know to never reference an ICS version that starts with ",(0,i.jsx)(n.code,{children:"provider"}),", even if it'd technically build."]}),"\n",(0,i.jsx)(n.li,{children:"Consumer and provider modules do not deviate as long as we continually release off a shared main branch. Backporting remains relatively unchanged besides being explicit about what module(s) your changes should affect."}),"\n",(0,i.jsx)(n.li,{children:"No code changes, just changes in process. Very simple."}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"~~Slightly more complexity.~~Considerably more complex to manage the ICS library.\nThis is because ICS needs to support multiple versions of SDK (e.g., 0.45, 0.47, 0.50).\nIn addition, ICS needs to support a special fork of SDK (with LSM included) for the Cosmos Hub.\nThis means that instead of focusing on main the development team needs to manage multiple release\nbranches with different dependency trees."}),"\n",(0,i.jsx)(n.li,{children:"This solution does not allow having provider and consumer on separate versions of e.g. the Cosmos SDK."}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,i.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsx)(n.p,{children:"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!"}),"\n"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/801",children:"#801"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/801#issuecomment-1683349298",children:"#801 comment"})}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,o.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},1151:(e,n,s)=>{s.d(n,{Z:()=>a,a:()=>t});var i=s(7294);const o={},r=i.createContext(o);function t(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:t(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/6382e28e.7f81451b.js b/assets/js/6382e28e.7f81451b.js new file mode 100644 index 0000000000..51ad8dae5e --- /dev/null +++ b/assets/js/6382e28e.7f81451b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1660],{3501:(e,o,n)=>{n.r(o),n.d(o,{assets:()=>c,contentTitle:()=>s,default:()=>p,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var t=n(5893),i=n(1151);const r={sidebar_position:4,title:"Offboarding Checklist"},s="Consumer Offboarding",a={id:"consumer-development/offboarding",title:"Offboarding Checklist",description:"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).",source:"@site/versioned_docs/version-v4.2.0-docs/consumer-development/offboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/offboarding",permalink:"/interchain-security/v4.2.0/consumer-development/offboarding",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Offboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Onboarding Checklist",permalink:"/interchain-security/v4.2.0/consumer-development/onboarding"},next:{title:"Changeover Procedure",permalink:"/interchain-security/v4.2.0/consumer-development/changeover-procedure"}},c={},d=[];function l(e){const o={code:"code",h1:"h1",p:"p",pre:"pre",...(0,i.a)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(o.h1,{id:"consumer-offboarding",children:"Consumer Offboarding"}),"\n",(0,t.jsxs)(o.p,{children:["To offboard a consumer chain simply submit a ",(0,t.jsx)(o.code,{children:"ConsumerRemovalProposal"})," governance proposal listing a ",(0,t.jsx)(o.code,{children:"stop_time"}),". After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates)."]}),"\n",(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-js",children:'// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.\n// If it passes, all the consumer chain\'s state is removed from the provider chain. The outstanding unbonding\n// operation funds are released.\n{\n // the title of the proposal\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n}\n'})}),"\n",(0,t.jsx)(o.p,{children:"More information will be listed in a future version of this document."})]})}function p(e={}){const{wrapper:o}={...(0,i.a)(),...e.components};return o?(0,t.jsx)(o,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},1151:(e,o,n)=>{n.d(o,{Z:()=>a,a:()=>s});var t=n(7294);const i={},r=t.createContext(i);function s(e){const o=t.useContext(r);return t.useMemo((function(){return"function"==typeof e?e(o):{...o,...e}}),[o,e])}function a(e){let o;return o=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:s(e.components),t.createElement(r.Provider,{value:o},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/68191a78.4b39d7fe.js b/assets/js/68191a78.4b39d7fe.js new file mode 100644 index 0000000000..2a7e739619 --- /dev/null +++ b/assets/js/68191a78.4b39d7fe.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4438],{266:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>o,default:()=>h,frontMatter:()=>r,metadata:()=>d,toc:()=>c});var i=t(5893),s=t(1151);const r={sidebar_position:12,title:"Improving testing and increasing confidence"},o="ADR 011: Improving testing and increasing confidence",d={id:"adrs/adr-011-improving-test-confidence",title:"Improving testing and increasing confidence",description:"Changelog",source:"@site/docs/adrs/adr-011-improving-test-confidence.md",sourceDirName:"adrs",slug:"/adrs/adr-011-improving-test-confidence",permalink:"/interchain-security/adrs/adr-011-improving-test-confidence",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:12,frontMatter:{sidebar_position:12,title:"Improving testing and increasing confidence"},sidebar:"tutorialSidebar",previous:{title:"Standalone to Consumer Changeover",permalink:"/interchain-security/adrs/adr-010-standalone-changeover"},next:{title:"Separate Releasing",permalink:"/interchain-security/adrs/adr-012-separate-releasing"}},a={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Current state of testing",id:"current-state-of-testing",level:4},{value:"Unit testing",id:"unit-testing",level:3},{value:"Integration testing",id:"integration-testing",level:3},{value:"End-to-end testing",id:"end-to-end-testing",level:3},{value:"Decision",id:"decision",level:2},{value:"1. Connect specifications to code and tooling",id:"1-connect-specifications-to-code-and-tooling",level:3},{value:"Decision context and hypothesis",id:"decision-context-and-hypothesis",level:4},{value:"Main benefit",id:"main-benefit",level:4},{value:"2. Improve e2e tooling",id:"2-improve-e2e-tooling",level:3},{value:"Matrix tests",id:"matrix-tests",level:4},{value:"Introducing e2e regression testing",id:"introducing-e2e-regression-testing",level:4},{value:"Introducing e2e CometMock tests",id:"introducing-e2e-cometmock-tests",level:4},{value:"3. Introduce innovative testing approaches",id:"3-introduce-innovative-testing-approaches",level:3},{value:"Model",id:"model",level:4},{value:"Driver",id:"driver",level:4},{value:"Harness",id:"harness",level:4},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function l(e){const n={a:"a",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",img:"img",li:"li",ol:"ol",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"adr-011-improving-testing-and-increasing-confidence",children:"ADR 011: Improving testing and increasing confidence"}),"\n",(0,i.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"2023-08-11: Proposed, first draft of ADR."}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(n.p,{children:"Proposed"}),"\n",(0,i.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,i.jsx)(n.p,{children:"Testing, QA, and maintenance of interchain-security libraries is an ever-evolving area of software engineering we have to keep incrementally improving. The purpose of the QA process is to catch bugs as early as possible. In an ideal development workflow a bug should never reach production. A bug found in the specification stage is a lot cheaper to resolve than a bug discovered in production (or even in testnet). Ideally, all bugs should be found during the CI execution, and we hope that no bugs will ever even reach the testnet (although nothing can replace actual system stress test under load interacting with users)."}),"\n",(0,i.jsx)(n.p,{children:"During development and testnet operation the following types of bugs were the most commonly found:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"improper iterator usage"}),"\n",(0,i.jsx)(n.li,{children:"unbounded array access/iteration"}),"\n",(0,i.jsx)(n.li,{children:"improper input handling and validation"}),"\n",(0,i.jsx)(n.li,{children:"improper cached context usage"}),"\n",(0,i.jsx)(n.li,{children:"non-determinism check (improper use of maps in go, relying on random values)"}),"\n",(0,i.jsx)(n.li,{children:"KV store management and/or how keys are defined"}),"\n",(0,i.jsx)(n.li,{children:"deserialization issues arising from consumer/provider versioning mismatch"}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Such bugs can be discovered earlier with better tooling. Some of these bugs can induce increases in block times, chain halts, state corruption, or introduce an attack surface which is difficult to remove if other systems have started depending on that behavior."}),"\n",(0,i.jsx)(n.h4,{id:"current-state-of-testing",children:"Current state of testing"}),"\n",(0,i.jsx)(n.p,{children:"Our testing suites consist of multiple parts, each with their own trade-offs and benefits with regards to code coverage, complexity and confidence they provide."}),"\n",(0,i.jsx)(n.h3,{id:"unit-testing",children:"Unit testing"}),"\n",(0,i.jsxs)(n.p,{children:["Unit testing is employed mostly for testing single-module functionality. It is the first step in testing and often the most practical. While highly important, unit tests often ",(0,i.jsx)(n.strong,{children:"test a single piece of code"})," and don't test relationships between different moving parts, this makes them less valuable when dealing with multi-module interactions."]}),"\n",(0,i.jsx)(n.p,{children:"Unit tests often employ mocks to abstract parts of the system that are not under test. Mocks are not equivalent to actual models and should not be treated as such."}),"\n",(0,i.jsx)(n.p,{children:"Out of all the approaches used, unit testing has the most tools available and the coverage can simply be displayed as % of code lines tested. Although this is a very nice and very easy to understand metric, it does not speak about the quality of the test coverage."}),"\n",(0,i.jsx)(n.p,{children:"Since distributed systems testing is a lot more involved, unit tests are oftentimes not sufficient to cover complex interactions. Unit tests are still necessary and helpful, but in cases where unit tests are not helpful e2e or integration tests should be favored."}),"\n",(0,i.jsx)(n.h3,{id:"integration-testing",children:"Integration testing"}),"\n",(0,i.jsxs)(n.p,{children:["With integration testing we ",(0,i.jsx)(n.strong,{children:"test the multi-module interactions"})," while isolating them from the remainder of the system.\nIntegration tests can uncover bugs that are often missed by unit tests."]}),"\n",(0,i.jsxs)(n.p,{children:["It is very difficult to gauge the actual test coverage imparted by integration tests and the available tooling is limited.\nIn interchain-security we employ the ",(0,i.jsx)(n.code,{children:"ibc-go/testing"})," framework to test interactions in-memory."]}),"\n",(0,i.jsx)(n.p,{children:"At present, integration testing does not involve the consensus layer - it is only concerned with application level state and logic."}),"\n",(0,i.jsx)(n.h3,{id:"end-to-end-testing",children:"End-to-end testing"}),"\n",(0,i.jsx)(n.p,{children:"In our context end-to-end testing comprises of tests that use the actual application binaries in an isolated environment (e.g. docker container). During test execution the inputs are meant to simulate actual user interaction, either by submitting transactions/queries using the command line or using gRPC/REST APIs and checking for state changes after an action has been performed. With this testing strategy we also include the consensus layer in all of our runs. This is the closest we can get to testing user interactions without starting a full testnet."}),"\n",(0,i.jsx)(n.p,{children:"End-to-end testing strategies vary between different teams and projects and we strive to unify our approach to the best of our ability (at least for ICS and gaia)."}),"\n",(0,i.jsx)(n.p,{children:"The available tooling does not give us significant (or relevant) line of code coverage information since most of the tools are geared towards analyzing unit tests and simple code branch evaluation."}),"\n",(0,i.jsx)(n.p,{children:"We aim to adapt our best practices by learning from other similar systems and projects such as cosmos-sdk, ibc-go and CometBFT."}),"\n",(0,i.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,i.jsx)(n.h3,{id:"1-connect-specifications-to-code-and-tooling",children:"1. Connect specifications to code and tooling"}),"\n",(0,i.jsx)(n.p,{children:"Oftentimes, specifications are disconnected from the development and QA processes. This gives rise to problems where the specification does not reflect the actual state of the system and vice-versa.\nUsually specifications are just text files that are rarely used and go unmaintained after a while, resulting in consistency issues and misleading instructions/expectations about system behavior."}),"\n",(0,i.jsx)(n.h4,{id:"decision-context-and-hypothesis",children:"Decision context and hypothesis"}),"\n",(0,i.jsx)(n.p,{children:"Specifications written in a dedicated and executable specification language are easier to maintain than the ones written entirely in text.\nAdditionally, we can create models based on the specification OR make the model equivalent to a specification."}),"\n",(0,i.jsxs)(n.p,{children:["Models do not care about the intricacies of implementation and neither do specifications. Since both models and specifications care about concisely and accurately describing a system (such as a finite state machine), we see a benefit of adding model based tools (such as ",(0,i.jsx)(n.a,{href:"https://github.com/informalsystems/quint",children:"quint"}),") to our testing and development workflows."]}),"\n",(0,i.jsx)(n.h4,{id:"main-benefit",children:"Main benefit"}),"\n",(0,i.jsx)(n.p,{children:"MBT tooling can be used to generate test traces that can be executed by multiple different testing setups."}),"\n",(0,i.jsx)(n.h3,{id:"2-improve-e2e-tooling",children:"2. Improve e2e tooling"}),"\n",(0,i.jsx)(n.h4,{id:"matrix-tests",children:"Matrix tests"}),"\n",(0,i.jsxs)(n.p,{children:["Instead of only running tests against current ",(0,i.jsx)(n.code,{children:"main"})," branch we should adopt an approach where we also:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"run regression tests against different released software versions"})," (",(0,i.jsx)(n.code,{children:"ICS v1 vs v2 vs v3"}),")"]}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.strong,{children:"run non-determinism tests to uncover issues quickly"})}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["Matrix tests can be implemented using ",(0,i.jsx)(n.a,{href:"https://github.com/informalsystems/CometMock",children:"CometMock"})," and refactoring our current e2e CI setup."]}),"\n",(0,i.jsx)(n.h4,{id:"introducing-e2e-regression-testing",children:"Introducing e2e regression testing"}),"\n",(0,i.jsx)(n.p,{children:"This e2e test suite would execute using a cronjob in our CI (nightly, multiple times a day etc.)"}),"\n",(0,i.jsxs)(n.p,{children:["Briefly, the same set of traces is run against different ",(0,i.jsx)(n.strong,{children:"maintained"})," versions of the software and the ",(0,i.jsx)(n.code,{children:"main"})," branch.\nThis would allow us to discover potential issues during development instead of in a testnet scenarios."]}),"\n",(0,i.jsxs)(n.p,{children:["The most valuable issues that can be discovered in this way are ",(0,i.jsx)(n.strong,{children:"state breaking changes"}),", ",(0,i.jsx)(n.strong,{children:"regressions"})," and ",(0,i.jsx)(n.strong,{children:"version incompatibilities"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["The setup is illustrated by the image below.\n",(0,i.jsx)(n.img,{alt:"e2e matrix tests",src:t(4839).Z+"",width:"2170",height:"1624"})]}),"\n",(0,i.jsx)(n.p,{children:"This table explains which versions are tested against each other for the same set of test traces:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"\u2705 marks a passing test"}),"\n",(0,i.jsx)(n.li,{children:"\u274c marks a failing test"}),"\n"]}),"\n",(0,i.jsxs)(n.table,{children:[(0,i.jsx)(n.thead,{children:(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"USES: ICS v1 PROVIDER"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"start chain"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"add key"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"delegate"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"undelegate"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"redelegate"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"downtime"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"equivocation"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"stop chain"})})]})}),(0,i.jsxs)(n.tbody,{children:[(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"v1 consumer (sdk45,ibc4.3)"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"v2 consumer (sdk45, ibc4.4)"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"v3 consumer (sdk47, ibc7)"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"main consumer"})}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"neutron"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u274c"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"stride"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u274c"})]})]})]}),"\n",(0,i.jsx)(n.h4,{id:"introducing-e2e-cometmock-tests",children:"Introducing e2e CometMock tests"}),"\n",(0,i.jsxs)(n.p,{children:["CometMock is a mock implementation of the ",(0,i.jsx)(n.a,{href:"https://github.com/cometbft/cometbft",children:"CometBFT"})," consensus engine. It supports most operations performed by CometBFT while also being lightweight and relatively easy to use."]}),"\n",(0,i.jsxs)(n.p,{children:['CometMock tests allow more nuanced control of test scenarios because CometMock can "fool" the blockchain app into thinking that a certain number of blocks had passed.\n',(0,i.jsx)(n.strong,{children:"This allows us to test very nuanced scenarios, difficult edge cases and long-running operations (such as unbonding operations)."})]}),"\n",(0,i.jsx)(n.p,{children:"Examples of tests made easier with CometMock are listed below:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"regression tests"}),"\n",(0,i.jsx)(n.li,{children:"non-determinism tests"}),"\n",(0,i.jsx)(n.li,{children:"upgrade tests"}),"\n",(0,i.jsx)(n.li,{children:"state-breaking changes"}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["With CometMock, the ",(0,i.jsx)(n.strong,{children:"matrix test"})," approach can also be used. The image below illustrates a CometMock setup that can be used to discover non-deterministic behavior and state-breaking changes.\n",(0,i.jsx)(n.img,{alt:"e2e matrix tests",src:t(9008).Z+"",width:"3714",height:"2082"})]}),"\n",(0,i.jsx)(n.p,{children:"This table explains which versions are tested against each other for the same set of test traces:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"\u2705 marks a passing test"}),"\n",(0,i.jsx)(n.li,{children:"\u274c marks a failing test"}),"\n"]}),"\n",(0,i.jsxs)(n.table,{children:[(0,i.jsx)(n.thead,{children:(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"SCENARIO"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"start chain"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"add key"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"delegate"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"undelegate"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"redelegate"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"downtime"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"equivocation"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"stop chain"})})]})}),(0,i.jsxs)(n.tbody,{children:[(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"v3 provi + v3 consu"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"main provi + main consu"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"commit provi + commit consu"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"})]})]})]}),"\n",(0,i.jsxs)(n.p,{children:["Briefly; multiple versions of the application are run against the same CometMock instance and any deviations in app behavior would result in ",(0,i.jsx)(n.code,{children:"app hash"})," errors (the apps would be in different states after performing the same set of actions)."]}),"\n",(0,i.jsx)(n.h3,{id:"3-introduce-innovative-testing-approaches",children:"3. Introduce innovative testing approaches"}),"\n",(0,i.jsx)(n.p,{children:"When discussing e2e testing, some very important patterns emerge - especially if test traces are used instead of ad-hoc tests written by hand."}),"\n",(0,i.jsx)(n.p,{children:"We see a unique opportunity to clearly identify concerns and modularize the testing architecture."}),"\n",(0,i.jsxs)(n.p,{children:["The e2e testing frameworks can be split into a ",(0,i.jsx)(n.strong,{children:"pipeline consisting of 3 parts: model, driver and harness"}),"."]}),"\n",(0,i.jsx)(n.h4,{id:"model",children:"Model"}),"\n",(0,i.jsx)(n.p,{children:"Model is the part of the system that can emulate the behavior of the system under test.\nIdeally, it is very close to the specification and is written in a specification language such as quint, TLA+ or similar.\nOne of the purposes of the model is that it can be used to generate test traces."}),"\n",(0,i.jsx)(n.h4,{id:"driver",children:"Driver"}),"\n",(0,i.jsx)(n.p,{children:"The purpose of the driver is to accept test traces (generated by the model or written by hand), process them and provide inputs to the next part of the pipeline."}),"\n",(0,i.jsx)(n.p,{children:"Basically, the driver sits between the model and the actual infrastructure on which the test traces are being executed on."}),"\n",(0,i.jsx)(n.h4,{id:"harness",children:"Harness"}),"\n",(0,i.jsx)(n.p,{children:"Harness is the infrastructure layer of the pipeline that accepts inputs from the driver."}),"\n",(0,i.jsx)(n.p,{children:"There can be multiple harnesses as long as they can perform four things:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"bootstrap a test execution environment (local, docker, k8s\u2026)"}),"\n",(0,i.jsx)(n.li,{children:"accept inputs from drivers"}),"\n",(0,i.jsx)(n.li,{children:"perform the action specified by the driver"}),"\n",(0,i.jsx)(n.li,{children:"report results after performing actions"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,i.jsx)(n.p,{children:"The procedure outlined in this ADR is not an all-or-nothing approach. Concepts introduced here do not rely on each other, so this ADR may only be applied partially without negative impact on test coverage and code confidence."}),"\n",(0,i.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsx)(n.li,{children:"introduction of maintainable MBT solutions"}),"\n"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:'improvement over the current "difftest" setup that relies on an opinionated typescript model and go driver'}),"\n"]}),"\n",(0,i.jsxs)(n.ol,{start:"2",children:["\n",(0,i.jsx)(n.li,{children:"increased code coverage and confidence"}),"\n"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"using CometMock allows us to run more tests in less time"}),"\n",(0,i.jsx)(n.li,{children:"adding matrix e2e tests allows us to quickly pinpoint differences between code versions"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsx)(n.p,{children:"It might be easier to forgo the MBT tooling and instead focus on pure property based testing"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/667",children:"PBT proof of concept"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/flyingmutant/rapid",children:"property based testing in go"})}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:'The solutions are potentially expensive if we increase usage of the CI pipeline - this is fixed by running "expensive" tests using a cronjob, instead of running them on every commit.'}),"\n",(0,i.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,i.jsx)(n.p,{children:"The process of changing development and testing process is not something that can be thought of and delivered quickly. Luckily, the changes can be rolled out incrementally without impacting existing workflows."}),"\n",(0,i.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsx)(n.p,{children:"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!"}),"\n"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/gaia/issues/2427",children:"https://github.com/cosmos/gaia/issues/2427"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/gaia/issues/2420",children:"https://github.com/cosmos/gaia/issues/2420"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/ibc-go/tree/main/e2e",children:"ibc-go e2e tests"})}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},9008:(e,n,t)=>{t.d(n,{Z:()=>i});const i=t.p+"assets/images/cometmock_matrix_test-714f36252aff9df4214823e3145d0ef5.png"},4839:(e,n,t)=>{t.d(n,{Z:()=>i});const i=t.p+"assets/images/matrix_e2e_tests-30681305077301daaf3097e1952b54bb.png"},1151:(e,n,t)=>{t.d(n,{Z:()=>d,a:()=>o});var i=t(7294);const s={},r=i.createContext(s);function o(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/69416719.7aa395e3.js b/assets/js/69416719.7aa395e3.js new file mode 100644 index 0000000000..6a21c9ff88 --- /dev/null +++ b/assets/js/69416719.7aa395e3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6873],{5911:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>l,frontMatter:()=>s,metadata:()=>i,toc:()=>p});var a=n(5893),o=n(1151);const s={sidebar_position:5},r="Democracy modules",i={id:"features/democracy-modules",title:"Democracy modules",description:"This section is relevant for chains transitioning from a standalone chain and new consumer chains that require some functionality from the x/staking module.",source:"@site/docs/features/democracy-modules.md",sourceDirName:"features",slug:"/features/democracy-modules",permalink:"/interchain-security/features/democracy-modules",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/features/slashing"},next:{title:"Partial Set Security",permalink:"/interchain-security/features/partial-set-security"}},c={},p=[{value:"Staking",id:"staking",level:2},{value:"Implications for consumer chains",id:"implications-for-consumer-chains",level:3},{value:"Governators (aka. Governors)",id:"governators-aka-governors",level:4},{value:"Tokenomics",id:"tokenomics",level:4},{value:"Integration",id:"integration",level:3},{value:"1. confirm that no modules are returning validator updates",id:"1-confirm-that-no-modules-are-returning-validator-updates",level:4},{value:"2. wire the module in app.go",id:"2-wire-the-module-in-appgo",level:4},{value:"Governance",id:"governance",level:2},{value:"Integration",id:"integration-1",level:3},{value:"Distribution",id:"distribution",level:2},{value:"How it works",id:"how-it-works",level:3},{value:"Integration",id:"integration-2",level:3}];function d(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,o.a)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h1,{id:"democracy-modules",children:"Democracy modules"}),"\n",(0,a.jsxs)(t.p,{children:["This section is relevant for chains transitioning from a standalone chain and new consumer chains that require some functionality from the ",(0,a.jsx)(t.code,{children:"x/staking"})," module."]}),"\n",(0,a.jsxs)(t.p,{children:["The democracy modules comprise ",(0,a.jsx)(t.code,{children:"x/staking"}),", ",(0,a.jsx)(t.code,{children:"x/distribution"})," and ",(0,a.jsx)(t.code,{children:"x/governance"})," with overrides and extensions required for normal operation when participating in interchain security."]}),"\n",(0,a.jsx)(t.p,{children:"The modules are plug-and-play and only require small wiring changes to be enabled."}),"\n",(0,a.jsxs)(t.p,{children:["For a full integration check the ",(0,a.jsx)(t.code,{children:"consumer-democracy"})," ",(0,a.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/main/app/consumer-democracy/app.go",children:"example app"}),"."]}),"\n",(0,a.jsx)(t.h2,{id:"staking",children:"Staking"}),"\n",(0,a.jsxs)(t.p,{children:["The democracy staking module allows the cosmos-sdk ",(0,a.jsx)(t.code,{children:"x/staking"})," module to be used alongside the interchain security ",(0,a.jsx)(t.code,{children:"consumer"})," module."]}),"\n",(0,a.jsxs)(t.p,{children:["The module uses overrides that allow the full ",(0,a.jsx)(t.code,{children:"x/staking"})," functionality with one notable difference - the staking module will no longer be used to provide the consensus validator set."]}),"\n",(0,a.jsx)(t.h3,{id:"implications-for-consumer-chains",children:"Implications for consumer chains"}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.code,{children:"x/ccv/democracy/staking"})," allows consumer chains to separate governance from block production."]}),"\n",(0,a.jsx)(t.admonition,{type:"info",children:(0,a.jsx)(t.p,{children:"The validator set coming from the provider chain does not need to participate in governance - they only provide infrastructure (create blocks and maintain consensus)."})}),"\n",(0,a.jsx)(t.h4,{id:"governators-aka-governors",children:"Governators (aka. Governors)"}),"\n",(0,a.jsxs)(t.p,{children:["Validators registered with the ",(0,a.jsx)(t.code,{children:"x/staking"}),' module become "Governators".']}),"\n",(0,a.jsx)(t.p,{children:"Unlike Validators, Governators are not required to run any chain infastructure since they are not signing any blocks."}),"\n",(0,a.jsx)(t.p,{children:"However, Governators retain a subset of the validator properties:"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:["new Governators can be created (via ",(0,a.jsx)(t.code,{children:"MsgCreateValidator"}),")"]}),"\n",(0,a.jsx)(t.li,{children:"Governators can accept delegations"}),"\n",(0,a.jsx)(t.li,{children:"Governators can vote on governance proposals (with their self stake and delegations)"}),"\n",(0,a.jsx)(t.li,{children:"Governators earn token rewards"}),"\n"]}),"\n",(0,a.jsx)(t.p,{children:"With these changes, Governators can become community advocates that can specialize in chain governance and they get rewarded for their participation the same way the validators do."}),"\n",(0,a.jsx)(t.p,{children:"Additionally, Governators can choose to provide additional infrastructure such as RPC/API access points, archive nodes, indexers and similar software."}),"\n",(0,a.jsx)(t.h4,{id:"tokenomics",children:"Tokenomics"}),"\n",(0,a.jsx)(t.p,{children:"The consumer chain's token will remain a governance and reward token. The token's parameters (inflation, max supply, burn rate) are not affected."}),"\n",(0,a.jsx)(t.admonition,{type:"info",children:(0,a.jsx)(t.p,{children:"Staking rewards are distributed to all Governators and their delegators after distributing the rewards to the provider chain's validator set."})}),"\n",(0,a.jsx)(t.h3,{id:"integration",children:"Integration"}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.code,{children:"x/ccv/democracy/staking"})," module provides these ",(0,a.jsx)(t.code,{children:"x/staking"})," overrides:"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-golang",children:"\n// InitGenesis delegates the InitGenesis call to the underlying x/staking module,\n// however, it returns no validator updates as validators are tracked via the\n// consumer chain's x/cvv/consumer module and so this module is not responsible for returning the initial validator set.\nfunc (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate {\n\tvar genesisState types.GenesisState\n\n\tcdc.MustUnmarshalJSON(data, &genesisState)\n\t_ = am.keeper.InitGenesis(ctx, &genesisState) // run staking InitGenesis\n\n\treturn []abci.ValidatorUpdate{} // do not return validator updates\n}\n\n// EndBlock delegates the EndBlock call to the underlying x/staking module.\n// However, no validator updates are returned as validators are tracked via the\n// consumer chain's x/cvv/consumer module.\nfunc (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {\n\t_ = am.keeper.BlockValidatorUpdates(ctx) // perform staking BlockValidatorUpdates\n\treturn []abci.ValidatorUpdate{} // do not return validator updates\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["To integrate the ",(0,a.jsx)(t.code,{children:"democracy/staking"})," follow this guide:"]}),"\n",(0,a.jsx)(t.h4,{id:"1-confirm-that-no-modules-are-returning-validator-updates",children:"1. confirm that no modules are returning validator updates"}),"\n",(0,a.jsx)(t.admonition,{type:"tip",children:(0,a.jsxs)(t.p,{children:["Only the ",(0,a.jsx)(t.code,{children:"x/ccv/consumer"})," module should be returning validator updates."]})}),"\n",(0,a.jsx)(t.p,{children:"If some of your modules are returning validator updates please disable them while maintaining your business logic:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-diff",children:"func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate {\n\tvar genesisState types.GenesisState\n\n\tcdc.MustUnmarshalJSON(data, &genesisState)\n-\treturn am.keeper.InitGenesis(ctx, &genesisState)\n+ \t_ = am.keeper.InitGenesis(ctx, &genesisState) // run InitGenesis but drop the result\n+\treturn []abci.ValidatorUpdate{} // return empty validator updates\n}\n\n\nfunc (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {\n-\treturn am.keeper.BlockValidatorUpdates(ctx)\n+ \t_ = am.keeper.BlockValidatorUpdates(ctx) // perform staking BlockValidatorUpdates\n+\treturn []abci.ValidatorUpdate{} // return empty validator updates\n}\n"})}),"\n",(0,a.jsx)(t.h4,{id:"2-wire-the-module-in-appgo",children:"2. wire the module in app.go"}),"\n",(0,a.jsxs)(t.p,{children:["You ",(0,a.jsx)(t.strong,{children:"do not need to remove"})," the cosmos-sdk ",(0,a.jsx)(t.code,{children:"StakingKeeper"})," from your wiring."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-diff",children:'import (\n ...\n+ ccvstaking "github.com/cosmos/interchain-security/v4/x/ccv/democracy/staking"\n)\n\nvar (\n // replace the staking.AppModuleBasic\n\tModuleBasics = module.NewBasicManager(\n\t\tauth.AppModuleBasic{},\n\t\tgenutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator),\n\t\tbank.AppModuleBasic{},\n\t\tcapability.AppModuleBasic{},\n-\t\tsdkstaking.AppModuleBasic{},\n+\t\tccvstaking.AppModuleBasic{}, // replace sdkstaking\n ...\n )\n)\n\n\nfunc NewApp(...) {\n ...\n\n\t// use sdk StakingKeepeer\n\tapp.StakingKeeper = stakingkeeper.NewKeeper(\n\t\tappCodec,\n\t\tkeys[stakingtypes.StoreKey],\n\t\tapp.AccountKeeper,\n\t\tapp.BankKeeper,\n\t\tauthtypes.NewModuleAddress(govtypes.ModuleName).String(),\n\t)\n\n\tapp.MintKeeper = mintkeeper.NewKeeper(\n\t\tappCodec,\n\t\tkeys[minttypes.StoreKey],\n\t\tapp.StakingKeeper,\n\t\tapp.AccountKeeper,\n\t\tapp.BankKeeper,\n\t\tauthtypes.FeeCollectorName,\n\t\tauthtypes.NewModuleAddress(govtypes.ModuleName).String(),\n\t)\n\n\t// no changes required for the distribution keeper\n app.DistrKeeper = distrkeeper.NewKeeper(\n\t\tappCodec,\n\t\tkeys[distrtypes.StoreKey],\n\t\tapp.AccountKeeper,\n\t\tapp.BankKeeper,\n\t\tapp.StakingKeeper, // keep StakingKeeper!\n\t\tauthtypes.FeeCollectorName,\n\t\tauthtypes.NewModuleAddress(govtypes.ModuleName).String(),\n\t)\n\n+ // pre-initialize ConsumerKeeper to satsfy ibckeeper.NewKeeper\n+\tapp.ConsumerKeeper = consumerkeeper.NewNonZeroKeeper(\n+\t\tappCodec,\n+\t\tkeys[consumertypes.StoreKey],\n+\t\tapp.GetSubspace(consumertypes.ModuleName),\n+\t)\n+\n+\tapp.IBCKeeper = ibckeeper.NewKeeper(\n+\t\tappCodec,\n+\t\tkeys[ibchost.StoreKey],\n+\t\tapp.GetSubspace(ibchost.ModuleName),\n+\t\t&app.ConsumerKeeper,\n+\t\tapp.UpgradeKeeper,\n+\t\tscopedIBCKeeper,\n+\t)\n+\n+\t// Create CCV consumer and modules\n+\tapp.ConsumerKeeper = consumerkeeper.NewKeeper(\n+\t\tappCodec,\n+\t\tkeys[consumertypes.StoreKey],\n+\t\tapp.GetSubspace(consumertypes.ModuleName),\n+\t\tscopedIBCConsumerKeeper,\n+\t\tapp.IBCKeeper.ChannelKeeper,\n+\t\t&app.IBCKeeper.PortKeeper,\n+\t\tapp.IBCKeeper.ConnectionKeeper,\n+\t\tapp.IBCKeeper.ClientKeeper,\n+\t\tapp.SlashingKeeper,\n+\t\tapp.BankKeeper,\n+\t\tapp.AccountKeeper,\n+\t\t&app.TransferKeeper,\n+\t\tapp.IBCKeeper,\n+\t\tauthtypes.FeeCollectorName,\n+\t)\n+\n+\t// Setting the standalone staking keeper is only needed for standalone to consumer changeover chains\n+ \t// New chains using the democracy/staking do not need to set this\n+\tapp.ConsumerKeeper.SetStandaloneStakingKeeper(app.StakingKeeper)\n\n\n\n\t// change the slashing keeper dependency\n\tapp.SlashingKeeper = slashingkeeper.NewKeeper(\n\t\tappCodec,\n\t\tlegacyAmino,\n\t\tkeys[slashingtypes.StoreKey],\n-\t\tapp.StakingKeeper,\n+\t\t&app.ConsumerKeeper, // ConsumerKeeper implements StakingKeeper interface\n\t\tauthtypes.NewModuleAddress(govtypes.ModuleName).String(),\n\t)\n\n\t// register slashing module StakingHooks to the consumer keeper\n+\tapp.ConsumerKeeper = *app.ConsumerKeeper.SetHooks(app.SlashingKeeper.Hooks())\n+\tconsumerModule := consumer.NewAppModule(app.ConsumerKeeper, app.GetSubspace(consumertypes.ModuleName))\n\n\t // register the module with module manager\n // replace the x/staking module\n\tapp.MM = module.NewManager(\n\t\t...\n-\t\tsdkstaking.NewAppModule(appCodec, &app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)),\n+\t\tccvstaking.NewAppModule(appCodec, *app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)),\n\t\t...\n\t)\n}\n'})}),"\n",(0,a.jsx)(t.h2,{id:"governance",children:"Governance"}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.code,{children:"x/ccv/democracy/governance"})," module extends the ",(0,a.jsx)(t.code,{children:"x/governance"})," module with the functionality to filter proposals."]}),"\n",(0,a.jsx)(t.admonition,{type:"tip",children:(0,a.jsx)(t.p,{children:"Consumer chains can limit in the types of governance proposals that can be executed on chain to avoid inadvertent changes to interchain security protocol that could affect security properties."})}),"\n",(0,a.jsxs)(t.p,{children:["The module uses ",(0,a.jsx)(t.code,{children:"AnteHandler"})," to limit the types of proposals that can be executed."]}),"\n",(0,a.jsx)(t.h3,{id:"integration-1",children:"Integration"}),"\n",(0,a.jsxs)(t.p,{children:["Add new ",(0,a.jsx)(t.code,{children:"AnteHandler"})," to your ",(0,a.jsx)(t.code,{children:"app"}),"."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-go",children:'\n// app/ante/forbidden_proposals.go\npackage ante\n\nimport (\n\t"fmt"\n\n\tsdk "github.com/cosmos/cosmos-sdk/types"\n\tgovv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"\n\tgovv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"\n\tibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"\n\n\t"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"\n\t"github.com/cosmos/cosmos-sdk/x/params/types/proposal"\n)\n\ntype ForbiddenProposalsDecorator struct {\n\tisLegacyProposalWhitelisted func(govv1beta1.Content) bool\n\tisModuleWhiteList func(string) bool\n}\n\nfunc NewForbiddenProposalsDecorator(\n\twhiteListFn func(govv1beta1.Content) bool,\n\tisModuleWhiteList func(string) bool,\n) ForbiddenProposalsDecorator {\n\treturn ForbiddenProposalsDecorator{\n\t\tisLegacyProposalWhitelisted: whiteListFn,\n\t\tisModuleWhiteList: isModuleWhiteList,\n\t}\n}\n\nfunc (decorator ForbiddenProposalsDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {\n\tcurrHeight := ctx.BlockHeight()\n\n\tfor _, msg := range tx.GetMsgs() {\n\t\t// if the message is MsgSubmitProposal, check if proposal is whitelisted\n\t\tsubmitProposalMgs, ok := msg.(*govv1.MsgSubmitProposal)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tmessages := submitProposalMgs.GetMessages()\n\t\tfor _, message := range messages {\n\t\t\tif sdkMsg, isLegacyProposal := message.GetCachedValue().(*govv1.MsgExecLegacyContent); isLegacyProposal {\n\t\t\t\t// legacy gov proposal content\n\t\t\t\tcontent, err := govv1.LegacyContentFromMessage(sdkMsg)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn ctx, fmt.Errorf("tx contains invalid LegacyContent")\n\t\t\t\t}\n\t\t\t\tif !decorator.isLegacyProposalWhitelisted(content) {\n\t\t\t\t\treturn ctx, fmt.Errorf("tx contains unsupported proposal message types at height %d", currHeight)\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// not legacy gov proposal content and not whitelisted\n\t\t\tif !decorator.isModuleWhiteList(message.TypeUrl) {\n\t\t\t\treturn ctx, fmt.Errorf("tx contains unsupported proposal message types at height %d", currHeight)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn next(ctx, tx, simulate)\n}\n\nfunc IsProposalWhitelisted(content v1beta1.Content) bool {\n\tswitch c := content.(type) {\n\tcase *proposal.ParameterChangeProposal:\n\t\treturn isLegacyParamChangeWhitelisted(c.Changes)\n\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc isLegacyParamChangeWhitelisted(paramChanges []proposal.ParamChange) bool {\n\tfor _, paramChange := range paramChanges {\n\t\t_, found := LegacyWhitelistedParams[legacyParamChangeKey{Subspace: paramChange.Subspace, Key: paramChange.Key}]\n\t\tif !found {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\ntype legacyParamChangeKey struct {\n\tSubspace, Key string\n}\n\n// Legacy params can be whitelisted\nvar LegacyWhitelistedParams = map[legacyParamChangeKey]struct{}{\n\t{Subspace: ibctransfertypes.ModuleName, Key: "SendEnabled"}: {},\n\t{Subspace: ibctransfertypes.ModuleName, Key: "ReceiveEnabled"}: {},\n}\n\n// New proposal types can be whitelisted\nvar WhiteListModule = map[string]struct{}{\n\t"/cosmos.gov.v1.MsgUpdateParams": {},\n\t"/cosmos.bank.v1beta1.MsgUpdateParams": {},\n\t"/cosmos.staking.v1beta1.MsgUpdateParams": {},\n\t"/cosmos.distribution.v1beta1.MsgUpdateParams": {},\n\t"/cosmos.mint.v1beta1.MsgUpdateParams": {},\n}\n\nfunc IsModuleWhiteList(typeUrl string) bool {\n\t_, found := WhiteListModule[typeUrl]\n\treturn found\n}\n'})}),"\n",(0,a.jsxs)(t.p,{children:["Add the ",(0,a.jsx)(t.code,{children:"AnteHandler"})," to the list of supported antehandlers:"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-diff",children:'// app/ante_handler.go\npackage app\n\nimport (\n\t...\n\n+\tdemocracyante "github.com/cosmos/interchain-security/v4/app/consumer-democracy/ante"\n+\tconsumerante "github.com/cosmos/interchain-security/v4/app/consumer/ante"\n+\ticsconsumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper"\n)\n\ntype HandlerOptions struct {\n\tante.HandlerOptions\n\n\tIBCKeeper *ibckeeper.Keeper\n+\tConsumerKeeper ibcconsumerkeeper.Keeper\n}\n\nfunc NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {\n\t....\n\n\tanteDecorators := []sdk.AnteDecorator{\n ...\n+\t\tconsumerante.NewMsgFilterDecorator(options.ConsumerKeeper),\n+\t\tconsumerante.NewDisabledModulesDecorator("/cosmos.evidence", "/cosmos.slashing"),\n+\t\tdemocracyante.NewForbiddenProposalsDecorator(IsProposalWhitelisted, IsModuleWhiteList),\n\t\t...\n\t}\n\n\treturn sdk.ChainAnteDecorators(anteDecorators...), nil\n}\n'})}),"\n",(0,a.jsxs)(t.p,{children:["Wire the module in ",(0,a.jsx)(t.code,{children:"app.go"}),"."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-diff",children:'// app/app.go\npackage app\nimport (\n ...\n sdkgov "github.com/cosmos/cosmos-sdk/x/gov"\n\tgovkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper"\n\tgovtypes "github.com/cosmos/cosmos-sdk/x/gov/types"\n\tgovv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"\n\n+\tccvgov "github.com/cosmos/interchain-security/v4/x/ccv/democracy/governance"\n)\n\nvar (\n\n // use sdk governance module\n\tModuleBasics = module.NewBasicManager(\n\t\t...\n\t\tsdkgov.NewAppModuleBasic(\n\t\t\t[]govclient.ProposalHandler{\n\t\t\t\tparamsclient.ProposalHandler,\n\t\t\t\tupgradeclient.LegacyProposalHandler,\n\t\t\t\tupgradeclient.LegacyCancelProposalHandler,\n\t\t\t},\n\t\t),\n )\n)\n\nfunc NewApp(...) {\n // retain sdk gov router and keeper registrations\n\tsdkgovRouter := govv1beta1.NewRouter()\n\tsdkgovRouter.\n\t\tAddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler).\n\t\tAddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)).\n\t\tAddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(&app.UpgradeKeeper))\n\tgovConfig := govtypes.DefaultConfig()\n\n\tapp.GovKeeper = *govkeeper.NewKeeper(\n\t\tappCodec,\n\t\tkeys[govtypes.StoreKey],\n\t\tapp.AccountKeeper,\n\t\tapp.BankKeeper,\n\t\tapp.StakingKeeper,\n\t\tapp.MsgServiceRouter(),\n\t\tgovConfig,\n\t\tauthtypes.NewModuleAddress(govtypes.ModuleName).String(),\n\t)\n\n\tapp.GovKeeper.SetLegacyRouter(sdkgovRouter)\n\n\n // register the module with module manager\n // replace the x/gov module\n\tapp.MM = module.NewManager(\n-\t\tsdkgov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper, IsProposalWhitelisted, app.GetSubspace(govtypes.ModuleName), IsModuleWhiteList),\n+\t\tccvgov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper, IsProposalWhitelisted, app.GetSubspace(govtypes.ModuleName), IsModuleWhiteList),\n\t\t...\n )\n}\n'})}),"\n",(0,a.jsx)(t.h2,{id:"distribution",children:"Distribution"}),"\n",(0,a.jsx)(t.admonition,{type:"tip",children:(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.code,{children:"democracy/distribution"})," module allows the consumer chain to send rewards to the provider chain while retaining the ",(0,a.jsx)(t.code,{children:"x/distribution"})," module for internal reward distribution to Governators and stakers."]})}),"\n",(0,a.jsx)(t.h3,{id:"how-it-works",children:"How it works"}),"\n",(0,a.jsx)(t.p,{children:"First, a % of rewards to be distributed to the provider chain's validator set is calculated and sent to the provider chain. Only opted-in validators from the provider chain will receive the consumer rewards."}),"\n",(0,a.jsx)(t.p,{children:"Second, the remaining rewards get distributed to the consumer chain's Governators and their delegators."}),"\n",(0,a.jsxs)(t.admonition,{type:"info",children:[(0,a.jsxs)(t.p,{children:["The % that is sent to the provider chain corresponds to ",(0,a.jsx)(t.code,{children:"1 - ConsumerRedistributionFraction"}),"."]}),(0,a.jsxs)(t.p,{children:["e.g. ",(0,a.jsx)(t.code,{children:'ConsumerRedistributionFraction = "0.75"'})]}),(0,a.jsx)(t.p,{children:"means that the consumer chain retains 75% of the rewards, while 25% gets sent to the provider chain to be distributed as rewards to provider chain validators."})]}),"\n",(0,a.jsx)(t.h3,{id:"integration-2",children:"Integration"}),"\n",(0,a.jsxs)(t.p,{children:["Change the wiring in ",(0,a.jsx)(t.code,{children:"app.go"})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-diff",children:'import (\n ...\n distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper"\n\tdistrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"\n sdkdistr "github.com/cosmos/cosmos-sdk/x/distribution"\n\n+ ccvdistr "github.com/cosmos/interchain-security/v4/x/ccv/democracy/distribution"\n)\n\nvar (\n // replace sdk distribution AppModuleBasic\n\tModuleBasics = module.NewBasicManager(\n\t\tauth.AppModuleBasic{},\n\t\tgenutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator),\n\t\tbank.AppModuleBasic{},\n\t\tcapability.AppModuleBasic{},\n\t\tccvstaking.AppModuleBasic{}, // make sure you first swap the staking keeper\n\t\tmint.AppModuleBasic{},\n-\t\tsdkdistr.AppModuleBasic{},\n+\t\tccvdistr.AppModuleBasic{},\n )\n)\n\nfunc NewApp(...) {\n ....\n\n\tapp.DistrKeeper = distrkeeper.NewKeeper(\n\t\tappCodec,\n\t\tkeys[distrtypes.StoreKey],\n\t\tapp.AccountKeeper,\n\t\tapp.BankKeeper,\n\t\tapp.StakingKeeper, // connect to sdk StakingKeeper\n\t\tconsumertypes.ConsumerRedistributeName,\n\t\tauthtypes.NewModuleAddress(govtypes.ModuleName).String(),\n\t)\n\n // register with the module manager\n\tapp.MM = module.NewManager(\n\t\t...\n-\t\tsdkdistr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, *app.StakingKeeper, authtypes.FeeCollectorName, app.GetSubspace(distrtypes.ModuleName)),\n\n+\t\tccvdistr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, *app.StakingKeeper, authtypes.FeeCollectorName, app.GetSubspace(distrtypes.ModuleName)),\n\t\tccvstaking.NewAppModule(appCodec, *app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)),\n\t\t...\n )\n}\n'})})]})}function l(e={}){const{wrapper:t}={...(0,o.a)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(d,{...e})}):d(e)}},1151:(e,t,n)=>{n.d(t,{Z:()=>i,a:()=>r});var a=n(7294);const o={},s=a.createContext(o);function r(e){const t=a.useContext(s);return a.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:r(e.components),a.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/6b52739c.dc8af5b8.js b/assets/js/6b52739c.dc8af5b8.js new file mode 100644 index 0000000000..7b24fe16bf --- /dev/null +++ b/assets/js/6b52739c.dc8af5b8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9419],{6319:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>l,frontMatter:()=>s,metadata:()=>r,toc:()=>d});var n=o(5893),i=o(1151);const s={sidebar_position:16,title:"Partial Set Security"},a="ADR 015: Partial Set Security",r={id:"adrs/adr-015-partial-set-security",title:"Partial Set Security",description:"Changelog",source:"@site/docs/adrs/adr-015-partial-set-security.md",sourceDirName:"adrs",slug:"/adrs/adr-015-partial-set-security",permalink:"/interchain-security/adrs/adr-015-partial-set-security",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:16,frontMatter:{sidebar_position:16,title:"Partial Set Security"},sidebar:"tutorialSidebar",previous:{title:"Epochs",permalink:"/interchain-security/adrs/adr-014-epochs"},next:{title:"Security aggregation",permalink:"/interchain-security/adrs/adr-016-securityaggregation"}},c={},d=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"How do consumer chains join?",id:"how-do-consumer-chains-join",level:3},{value:"State & Query",id:"state--query",level:4},{value:"How do validators opt in?",id:"how-do-validators-opt-in",level:3},{value:"State & Query",id:"state--query-1",level:4},{value:"When do validators opt in?",id:"when-do-validators-opt-in",level:4},{value:"How do validators opt out?",id:"how-do-validators-opt-out",level:3},{value:"State & Query",id:"state--query-2",level:4},{value:"When does a consumer chain start?",id:"when-does-a-consumer-chain-start",level:3},{value:"How do we send the partial validator sets to the consumer chains?",id:"how-do-we-send-the-partial-validator-sets-to-the-consumer-chains",level:3},{value:"How do we distribute rewards?",id:"how-do-we-distribute-rewards",level:3},{value:"Misbehaviour",id:"misbehaviour",level:3},{value:"Fraud votes",id:"fraud-votes",level:4},{value:"Double signing",id:"double-signing",level:4},{value:"Downtime",id:"downtime",level:4},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}];function h(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",pre:"pre",ul:"ul",...(0,i.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"adr-015-partial-set-security",children:"ADR 015: Partial Set Security"}),"\n",(0,n.jsx)(t.h2,{id:"changelog",children:"Changelog"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"2024-01-22: Proposed, first draft of ADR."}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"status",children:"Status"}),"\n",(0,n.jsx)(t.p,{children:"Accepted"}),"\n",(0,n.jsx)(t.h2,{id:"context",children:"Context"}),"\n",(0,n.jsxs)(t.p,{children:["Currently, in ",(0,n.jsx)(t.em,{children:"Replicated Security"}),", the entire validator set of the provider chain is used to secure consumer chains. There are at least three concerns with this approach.\nFirst, a large number of validators might be forced to validate consumer chains they are not interested in securing.\nSecond, it is costly for small validators to secure additional chains. This concern is only partially addressed through ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-009-soft-opt-out.md",children:"soft opt-out"})," that allows small validators to opt out from validating consumer chains.\nThird and for the above reasons, it is challenging for a new consumer chain to join Replicated Security."]}),"\n",(0,n.jsxs)(t.p,{children:["As a solution, we present ",(0,n.jsx)(t.em,{children:"Partial Set Security"})," (PSS). As the name suggests, PSS allows for every consumer chain to be secured by only a subset of the provider validator set.\nIn what follows we propose the exact steps we need to take to implement PSS. This is a first iteration of PSS, and therefore we present the most minimal solution that make PSS possible."]}),"\n",(0,n.jsx)(t.h2,{id:"decision",children:"Decision"}),"\n",(0,n.jsxs)(t.p,{children:["In Replicated Security, all the provider validators have to secure every consumer chain (with the exception of those validators allowed to opt out through the ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-009-soft-opt-out.md",children:"soft opt-out"})," feature)."]}),"\n",(0,n.jsxs)(t.p,{children:["In PSS, we allow validators to opt in and out of validating any given consumer chain.\nThis has one exception: we introduce a parameter ",(0,n.jsx)(t.code,{children:"N"})," for each consumer chain and require that the validators in top ",(0,n.jsx)(t.code,{children:"N%"})," of the provider's voting power have to secure the consumer chain.\nValidators outside of the top ",(0,n.jsx)(t.code,{children:"N%"})," can dynamically opt in if they want to validate on the consumer chain."]}),"\n",(0,n.jsxs)(t.p,{children:["For example, if a consumer chain has ",(0,n.jsx)(t.code,{children:"N = 95%"}),", then it ultimately receives the same security it receives today with Replicated Security (with a default ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-009-soft-opt-out.md",children:"SoftOptOutThreshold"})," of 5%).\nOn the other hand, if a consumer chain has ",(0,n.jsx)(t.code,{children:"N = 0%"}),", then no validator is forced to validate the chain, but validators can opt in to do so instead."]}),"\n",(0,n.jsxs)(t.p,{children:["For the remainder of this ADR, we call a consumer chain ",(0,n.jsx)(t.em,{children:"Top N"})," if it has joined as a Top N chain with ",(0,n.jsx)(t.code,{children:"N > 0"})," and ",(0,n.jsx)(t.em,{children:"Opt In"})," chain otherwise. An Opt In consumer chain is secured only by the validators that have opted in to secure that chain."]}),"\n",(0,n.jsxs)(t.p,{children:["We intend to implement PSS using a feature branch off ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/tree/v4.0.0",children:"v4.0.0 interchain security"}),"."]}),"\n",(0,n.jsx)(t.h3,{id:"how-do-consumer-chains-join",children:"How do consumer chains join?"}),"\n",(0,n.jsxs)(t.p,{children:["As a simplification and to avoid ",(0,n.jsx)(t.a,{href:"https://forum.cosmos.network/t/pss-permissionless-vs-premissioned-lite-opt-in-consumer-chains/12984/17",children:"chain id squatting"}),", a consumer chain can only join PSS through a governance proposal and not in a permissionless way."]}),"\n",(0,n.jsx)(t.p,{children:'However, this proposal type will be modified so that it requires a lower quorum percentage than normal proposal, and every validator who voted "YES" on the proposal will form the consumer chain\'s initial validator set.'}),"\n",(0,n.jsxs)(t.p,{children:["Consumer chains join PSS the same way chains now join Replicated Security, namely through a ",(0,n.jsx)(t.code,{children:"ConsumerAdditionProposal"})," proposal.\nWe extend ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/proto/interchain_security/ccv/provider/v1/provider.proto#L27",children:(0,n.jsx)(t.code,{children:"ConsumerAdditionProposal"})})," with one optional field:"]}),"\n",(0,n.jsxs)(t.p,{children:[(0,n.jsx)(t.code,{children:"uint32 top_N"}),": Corresponds to the percentage of validators that join under the Top N case.\nFor example, ",(0,n.jsx)(t.code,{children:"53"})," corresponds to a Top 53% chain, meaning that the top ",(0,n.jsx)(t.code,{children:"53%"})," provider validators have to validate the proposed consumer chain.\n",(0,n.jsx)(t.code,{children:"top_N"})," can be ",(0,n.jsx)(t.code,{children:"0"})," or include any value in ",(0,n.jsx)(t.code,{children:"[50, 100]"}),". A chain can join with ",(0,n.jsx)(t.code,{children:"top_N == 0"})," as an Opt In, or with ",(0,n.jsx)(t.code,{children:"top_N \u2208 [50, 100]"})," as a Top N chain."]}),"\n",(0,n.jsxs)(t.p,{children:["In case of a Top N chain, we restrict the possible values of ",(0,n.jsx)(t.code,{children:"top_N"})," from ",(0,n.jsx)(t.code,{children:"(0, 100]"})," to ",(0,n.jsx)(t.code,{children:"[50, 100]"}),".\nBy having ",(0,n.jsx)(t.code,{children:"top_N >= 50"})," we can guarantee that we cannot have a successful attack, assuming that at most ",(0,n.jsx)(t.code,{children:"1/3"})," of provider validators can be malicious.\nThis is because, a Top N chain with ",(0,n.jsx)(t.code,{children:"N >= 50%"})," would have at least ",(0,n.jsx)(t.code,{children:"1/3"})," honest validators, which is sufficient to stop attacks.\nAdditionally, by having ",(0,n.jsx)(t.code,{children:"N >= 50%"})," (and hence ",(0,n.jsx)(t.code,{children:"N > (VetoThreshold = 33.4%)"}),") we enable the top N validators to ",(0,n.jsx)(t.code,{children:"Veto"})," any ",(0,n.jsx)(t.code,{children:"ConsumerAdditionProposal"})," for consumer chains they do not want to validate."]}),"\n",(0,n.jsxs)(t.p,{children:["If a proposal has the ",(0,n.jsx)(t.code,{children:"top_N"})," argument wrongly set, it should get rejected in [ValidateBasic] (",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/types/proposal.go#L86",children:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/types/proposal.go#L86"}),")."]}),"\n",(0,n.jsxs)(t.p,{children:["In the code, we distinguish whether a chain is ",(0,n.jsx)(t.em,{children:"Top N"})," or ",(0,n.jsx)(t.em,{children:"Opt In"})," by checking whether ",(0,n.jsx)(t.code,{children:"top_N"})," is zero or not."]}),"\n",(0,n.jsxs)(t.p,{children:["In a future version of PSS, we intend to introduce a ",(0,n.jsx)(t.code,{children:"ConsumerModificationProposal"})," so that we can modify the parameters of a consumer chain, e.g, a chain that is ",(0,n.jsx)(t.em,{children:"Opt In"})," to become ",(0,n.jsx)(t.em,{children:"Top N"}),", etc."]}),"\n",(0,n.jsx)(t.h4,{id:"state--query",children:"State & Query"}),"\n",(0,n.jsxs)(t.p,{children:["We augment the provider module\u2019s state to keep track of the ",(0,n.jsx)(t.code,{children:"top_N"})," value for each consumer chain. The key to store this information would be:"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{children:"topNBytePrefix | len(chainID) | chainID\n"})}),"\n",(0,n.jsxs)(t.p,{children:["To create the above key, we can use ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/types/keys.go#L418",children:(0,n.jsx)(t.code,{children:"ChainIdWithLenKey"})}),"."]}),"\n",(0,n.jsxs)(t.p,{children:["Then in the ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/keeper/keeper.go",children:"keeper"})," we introduce methods as follows:"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-golang",children:"func (k Keeper) SetTopN(ctx sdk.Context, chainID string, topN uint32)\nfunc (k Keeper) IsTopN(ctx sdk.Context, chainID string) bool\nfunc (k Keeper) IsOptIn(ctx sdk.Context, chainID string) bool\n\n// returns the N if Top N chain, otherwise an error\nfunc (k Keeper) GetTopN(ctx sdk.Context, chainID string) (uint32, error)\n"})}),"\n",(0,n.jsxs)(t.p,{children:["We also extend the ",(0,n.jsx)(t.code,{children:"interchain-security-pd query provider list-consumer-chains"}),' query to return information on whether a consumer chain is an Opt In or a Top N chain and with what N.\nThis way, block explorers can present informative messages such as "This chain is secured by N% of the provider chain" for consumer chains.']}),"\n",(0,n.jsx)(t.h3,{id:"how-do-validators-opt-in",children:"How do validators opt in?"}),"\n",(0,n.jsxs)(t.p,{children:["A validator can opt in by sending a new type of message that we introduce in ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/proto/interchain_security/ccv/provider/v1/tx.proto#L1",children:"tx.proto"}),"."]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-protobuf",children:"message MsgOptIn {\n // the chain id of the consumer chain to opt in to\n string chainID = 1;\n // the provider address of the validator\n string providerAddr = 2;\n // (optional) the consensus public key to use on the consumer\n optional string consumerKey = 3;\n}\n"})}),"\n",(0,n.jsxs)(t.p,{children:["Note that in a Top N consumer chain, the top ",(0,n.jsx)(t.code,{children:"N%"})," provider validators have to validate the consumer chain.\nNevertheless, validators in the bottom ",(0,n.jsx)(t.code,{children:"(100 - N)%"})," can opt in to validate as well.\nProvider validators that belong or enter the top ",(0,n.jsx)(t.code,{children:"N%"})," validators are ",(0,n.jsx)(t.em,{children:"automatically"})," opted in to validate a Top N consumer chain.\nThis means that if a validator ",(0,n.jsx)(t.code,{children:"V"})," belongs to the top ",(0,n.jsx)(t.code,{children:"N%"})," validators but later falls (e.g., due to undelegations) to the bottom ",(0,n.jsx)(t.code,{children:"(100 - N)%"}),", ",(0,n.jsx)(t.code,{children:"V"})," is still considered opted in and has to validate unless ",(0,n.jsx)(t.code,{children:"V"})," sends a ",(0,n.jsx)(t.code,{children:"MsgOptOut"})," message (see below).\nBy automatically opting in validators when they enter the top ",(0,n.jsx)(t.code,{children:"N%"})," validators and by forcing top ",(0,n.jsx)(t.code,{children:"N%"})," validators to explicitly opt out in case they fall to the ",(0,n.jsx)(t.code,{children:"(100 - N)%"})," bottom validators we simplify the design of PSS."]}),"\n",(0,n.jsxs)(t.p,{children:["Note that a validator can send a ",(0,n.jsx)(t.code,{children:"MsgOptIn"})," message even if the consumer chain is not yet running. To do this we reuse the ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/keeper/key_assignment.go#L644",children:(0,n.jsx)(t.code,{children:"IsConsumerProposedOrRegistered"})}),". If the ",(0,n.jsx)(t.code,{children:"chainID"})," does not exist, the ",(0,n.jsx)(t.code,{children:"MsgOptIn"})," should fail, as well as if the provider address does not exist."]}),"\n",(0,n.jsxs)(t.p,{children:["Optionally, a validator that opts in can provide a ",(0,n.jsx)(t.code,{children:"consumerKey"})," so that it assigns a different consumer key (from the provider) to the consumer chain.\nNaturally, a validator can always change the consumer key on a consumer chain by sending a ",(0,n.jsx)(t.code,{children:"MsgAssignConsumerKey"})," message at a later point in time, as is done in Replicated Security."]}),"\n",(0,n.jsx)(t.h4,{id:"state--query-1",children:"State & Query"}),"\n",(0,n.jsxs)(t.p,{children:["For each validator, we store a pair ",(0,n.jsx)(t.code,{children:"(blockHeight, isOptedIn)"})," that contains the block height the validator opted in and whether the validator is currently opted in or not, under the key:"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{children:"optedInBytePrefix | len(chainID) | chainID | addr\n"})}),"\n",(0,n.jsxs)(t.p,{children:["By using a prefix iterator on ",(0,n.jsx)(t.code,{children:"optedInBytePrefix | len(chainID) | chainID"})," we retrieve all the opted in validators."]}),"\n",(0,n.jsxs)(t.p,{children:["We introduce the following ",(0,n.jsx)(t.code,{children:"Keeper"})," methods."]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-golang",children:"// returns all the validators that have opted in on chain `chainID`\nfunc (k Keeper) GetOptedInValidators(ctx sdk.Context, chainID string) []Validators\n\nfunc (k Keeper) IsValidatorOptedIn(ctx sdk.Context, chainID string, val Validator) bool\n"})}),"\n",(0,n.jsx)(t.p,{children:"We introduce the following two queries:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-bash",children:"interchain-security-pd query provider optedInValidators $chainID\ninterchain-security-pd query provider hasToValidate $providerAddr\n"})}),"\n",(0,n.jsx)(t.p,{children:"One query to retrieve the validators that are opted in and hence the validators that need to validate the consumer chain and one query that given a validator's address returns all the chains this validator has to validate."}),"\n",(0,n.jsx)(t.h4,{id:"when-do-validators-opt-in",children:"When do validators opt in?"}),"\n",(0,n.jsxs)(t.p,{children:["As described earlier, validators can manually opt in by sending a ",(0,n.jsx)(t.code,{children:"MsgOptIn"})," message.\nAdditionally, in a Top N chain, a validator is automatically opted in when it moves from the bottom ",(0,n.jsx)(t.code,{children:"(100 - N)%"})," to the top ",(0,n.jsx)(t.code,{children:"N%"})," validators."]}),"\n",(0,n.jsxs)(t.p,{children:["Lastly, validators can also opt in if they vote ",(0,n.jsx)(t.code,{children:"Yes"})," during the ",(0,n.jsx)(t.code,{children:"ConsumerAdditionProposal"})," that introduces a consumer chain.\nThis simplifies validators operations because they do not have to send an additional message to opt in."]}),"\n",(0,n.jsxs)(t.p,{children:["Because the ",(0,n.jsx)(t.code,{children:"Tally"})," method ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.7/x/gov/keeper/tally.go#L71",children:"deletes the votes"})," after reading them, we cannot check the votes of the validators after the votes have been tallied.\nTo circumvent this, we introduce a hook for ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.7/x/gov/keeper/vote.go#L35",children:(0,n.jsx)(t.code,{children:"AfterProposalVote"})})," and keep track of all the votes cast by a validator.\nIf a validator casts more than one vote, we only consider the latest vote.\nFinally, we only consider a validator has opted in if it casts a 100% ",(0,n.jsx)(t.code,{children:"Yes"})," vote in case of a ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-037-gov-split-vote.md",children:"weighted vote"}),"."]}),"\n",(0,n.jsx)(t.h3,{id:"how-do-validators-opt-out",children:"How do validators opt out?"}),"\n",(0,n.jsx)(t.p,{children:"Validators that have opted in on a chain can opt out by sending the following message:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-protobuf",children:"message MsgOptOut {\n // the chain id of the consumer chain to opt out from\n string chainID = 1;\n // the provider address of the validator\n string providerAddr = 2;\n}\n"})}),"\n",(0,n.jsxs)(t.p,{children:["Validators can only opt out after a consumer chain has started and hence the above message returns an error if the chain with ",(0,n.jsx)(t.code,{children:"chainID"})," is not running.\nAdditionally, a validator that belongs to the top ",(0,n.jsx)(t.code,{children:"N%"})," validators cannot opt out from a Top N chain and hence a ",(0,n.jsx)(t.code,{children:"MsgOptOut"})," would error in such a case."]}),"\n",(0,n.jsx)(t.h4,{id:"state--query-2",children:"State & Query"}),"\n",(0,n.jsx)(t.p,{children:"We also update the state of the opted-in validators when a validator has opted out by removing the opted-out validator."}),"\n",(0,n.jsxs)(t.p,{children:["Note that only opted-in validators can be punished for downtime on a consumer chain.\nFor this, we use historical info of all the validators that have opted in; We can examine the ",(0,n.jsx)(t.code,{children:"blockHeight"})," stored under the key ",(0,n.jsx)(t.code,{children:"optedInBytePrefix | len(chainID) | chainID | addr"})," to see if a validator was opted in.\nThis way we can jail validators for downtime knowing that indeed the validators have opted in at some point in the past.\nOtherwise, we can think of a scenario where a validator ",(0,n.jsx)(t.code,{children:"V"})," is down for a period of time, but before ",(0,n.jsx)(t.code,{children:"V"})," gets punished for downtime, validator ",(0,n.jsx)(t.code,{children:"V"})," opts out, and then we do not know whether ",(0,n.jsx)(t.code,{children:"V"})," should be punished or not."]}),"\n",(0,n.jsx)(t.h3,{id:"when-does-a-consumer-chain-start",children:"When does a consumer chain start?"}),"\n",(0,n.jsxs)(t.p,{children:["A Top N consumer chain always starts at the specified date (",(0,n.jsx)(t.code,{children:"spawn_time"}),") if the ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/proto/interchain_security/ccv/provider/v1/provider.proto#L27",children:(0,n.jsx)(t.code,{children:"ConsumerAdditionProposal"})})," has passed.\nAn Opt In consumer chain only starts if at least one validator has opted in. We check this in ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/keeper/proposal.go#L357",children:"BeginBlockInit"}),":"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-golang",children:'func (k Keeper) BeginBlockInit(ctx sdk.Context) {\n propsToExecute := k.GetConsumerAdditionPropsToExecute(ctx)\n\n for _, prop := range propsToExecute {\n chainID := prop.ChainId\n if !k.IsTopN(ctx, chainID) && len(k.GetOptedInValidators(ctx, chainID)) == 0 {\n // drop the proposal\n ctx.Logger().Info("could not start chain because no validator has opted in")\n continue\n } \n ...\n'})}),"\n",(0,n.jsx)(t.h3,{id:"how-do-we-send-the-partial-validator-sets-to-the-consumer-chains",children:"How do we send the partial validator sets to the consumer chains?"}),"\n",(0,n.jsxs)(t.p,{children:["A consumer chain should only be validated by opted in validators.\nWe introduce logic to do this when we ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/keeper/relay.go#L213",children:"queue"})," the ",(0,n.jsx)(t.code,{children:"VSCPacket"}),"s.\nThe logic behind this, is not as straightforward as it seems because CometBFT does not receive the validator set that has to validate a chain, but rather a delta of ",(0,n.jsx)(t.a,{href:"https://docs.cometbft.com/v0.37/spec/abci/abci++_methods#validatorupdate",children:"validator updates"}),".\nFor example, to remove an opted-out validator from a consumer chain, we have to send a validator update with a ",(0,n.jsx)(t.code,{children:"power"})," of ",(0,n.jsx)(t.code,{children:"0"}),", similarly to what is done in the ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/keeper/key_assignment.go#L525",children:"assignment of consumer keys"}),".\nWe intend to update this ADR at a later stage on how exactly we intend to implement this logic."]}),"\n",(0,n.jsx)(t.h3,{id:"how-do-we-distribute-rewards",children:"How do we distribute rewards?"}),"\n",(0,n.jsxs)(t.p,{children:["Currently, rewards are distributed as follows: The consumer ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/consumer/keeper/distribution.go#L148",children:"periodically sends rewards"})," on the provider ",(0,n.jsx)(t.code,{children:"ConsumerRewardsPool"})," address.\nThe provider then ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/keeper/distribution.go#L77",children:"transfers those rewards to the fee collector address"})," and those transferred rewards are distributed to validators and delegators."]}),"\n",(0,n.jsx)(t.p,{children:"In PSS, we distribute rewards only to validators that actually validate the consumer chain.\nTo do this, we have a pool associated with each consumer chain and consumers IBC transfer the rewards to this pool.\nWe then extract the rewards from each consumer pool and distribute them to the opted in validators."}),"\n",(0,n.jsx)(t.p,{children:"Note that we only distribute rewards to validators that have been opted in for some time (e.g., 10000 blocks) to avoid cases where validators opt in just to receive rewards and then opt out immediately afterward."}),"\n",(0,n.jsx)(t.h3,{id:"misbehaviour",children:"Misbehaviour"}),"\n",(0,n.jsx)(t.h4,{id:"fraud-votes",children:"Fraud votes"}),"\n",(0,n.jsxs)(t.p,{children:["In an Opt In chain, a set of validators might attempt to perform an attack. To deter such potential attacks, PSS allows for the use of fraud votes.\nA ",(0,n.jsx)(t.em,{children:"fraud vote"})," is a governance proposal that enables the slashing of validators that performed an attack.\nDue to their inherent complexity, we intend to introduce fraud votes in a different ADR and at a future iteration of PSS."]}),"\n",(0,n.jsx)(t.h4,{id:"double-signing",children:"Double signing"}),"\n",(0,n.jsx)(t.p,{children:"We do not change the way slashing for double signing and light client attacks functions.\nIf a validator misbehaves on a consumer, then we slash that validator on the provider."}),"\n",(0,n.jsx)(t.h4,{id:"downtime",children:"Downtime"}),"\n",(0,n.jsx)(t.p,{children:"We do not change the way downtime jailing functions.\nIf a validator is down on a consumer chain for an adequate amount of time, we jail this validator on the provider but only if the validator was opted in on this consumer chain in the recent past."}),"\n",(0,n.jsx)(t.h2,{id:"consequences",children:"Consequences"}),"\n",(0,n.jsx)(t.h3,{id:"positive",children:"Positive"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsx)(t.p,{children:"Easier for new consumer chains to consume the provider's chain economic security because proposals are more likely to pass if not everyone is forced to validate."}),"\n"]}),"\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsx)(t.p,{children:"Smaller validators are not forced to validate chains anymore if they do not want to."}),"\n"]}),"\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsx)(t.p,{children:"We can deprecate the soft opt-out implementation."}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(t.h3,{id:"negative",children:"Negative"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["A consumer chain does not receive the same economic security as with Replicated Security (assuming the value of ",(0,n.jsx)(t.code,{children:"SoftOptOutThreshold"})," is ",(0,n.jsx)(t.code,{children:"5%"}),"), unless it is a Top N chain with ",(0,n.jsx)(t.code,{children:"N >= 95%"}),"."]}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"references",children:"References"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:(0,n.jsx)(t.a,{href:"https://forum.cosmos.network/t/pss-permissionless-vs-premissioned-lite-opt-in-consumer-chains/12984",children:"PSS: Permissionless vs premissioned-lite opt-in consumer chains"})}),"\n",(0,n.jsx)(t.li,{children:(0,n.jsx)(t.a,{href:"https://forum.cosmos.network/t/chips-discussion-phase-partial-set-security-updated/11775",children:"CHIPs discussion phase: Partial Set Security (updated)"})}),"\n",(0,n.jsx)(t.li,{children:(0,n.jsx)(t.a,{href:"https://forum.cosmos.network/t/pss-exclusive-vs-inclusive-top-n/13058",children:"PSS: Exclusive vs Inclusive Top-N"})}),"\n",(0,n.jsx)(t.li,{children:(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/pull/1518",children:"Initial PSS ADR and notes #1518"})}),"\n",(0,n.jsx)(t.li,{children:(0,n.jsx)(t.a,{href:"https://informal.systems/blog/replicated-vs-mesh-security",children:"Replicated vs. Mesh Security"})}),"\n"]})]})}function l(e={}){const{wrapper:t}={...(0,i.a)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(h,{...e})}):h(e)}},1151:(e,t,o)=>{o.d(t,{Z:()=>r,a:()=>a});var n=o(7294);const i={},s=n.createContext(i);function a(e){const t=n.useContext(s);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),n.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/6b8df643.b0ee3105.js b/assets/js/6b8df643.b0ee3105.js new file mode 100644 index 0000000000..c88893bf23 --- /dev/null +++ b/assets/js/6b8df643.b0ee3105.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4335],{8355:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>l,frontMatter:()=>o,metadata:()=>a,toc:()=>h});var s=t(5893),i=t(1151);const o={sidebar_position:15,title:"Epochs"},r="ADR 014: Epochs",a={id:"adrs/adr-014-epochs",title:"Epochs",description:"Changelog",source:"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-014-epochs.md",sourceDirName:"adrs",slug:"/adrs/adr-014-epochs",permalink:"/interchain-security/v4.2.0/adrs/adr-014-epochs",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:15,frontMatter:{sidebar_position:15,title:"Epochs"},sidebar:"tutorialSidebar",previous:{title:"Slashing on the provider for consumer equivocation",permalink:"/interchain-security/v4.2.0/adrs/adr-013-equivocation-slashing"},next:{title:"Partial Set Security",permalink:"/interchain-security/v4.2.0/adrs/adr-015-partial-set-security"}},c={},h=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function d(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,i.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"adr-014-epochs",children:"ADR 014: Epochs"}),"\n",(0,s.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"2024-01-05: Proposed, first draft of ADR."}),"\n",(0,s.jsx)(n.li,{children:"2024-02-29: Updated so that it describes the implementation where we store the whole consumer validator set."}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,s.jsx)(n.p,{children:"Proposed"}),"\n",(0,s.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,s.jsxs)(n.p,{children:["In every block that the provider valset changes, a ",(0,s.jsx)(n.code,{children:"VSCPacket"})," must be sent to every consumer and a corresponding ",(0,s.jsx)(n.code,{children:"VSCMaturedPacket"})," sent back.\nGiven that the validator powers may change very often on the provider chain (e.g., the Cosmos Hub), this approach results in a large workload for the relayers.\nAlthough the validator powers may change very often, these changes are usually small and have an insignificant impact on the chain's security.\nIn other words, the valset on the consumers can be slightly outdated without affecting security.\nAs a matter of fact, this already happens due to relaying delays."]}),"\n",(0,s.jsxs)(n.p,{children:["As a solution, this ADR introduces the concept of ",(0,s.jsx)(n.em,{children:"epochs"}),".\nAn epoch consists of multiple blocks.\nThe provider sends ",(0,s.jsx)(n.code,{children:"VSCPacket"}),"s once per epoch.\nA ",(0,s.jsx)(n.code,{children:"VSCPacket"})," contains all the validator updates that are needed by a consumer chain."]}),"\n",(0,s.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,s.jsx)(n.p,{children:"The implementation of epochs requires the following changes:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"For each consumer chain, we store the consumer validator set that is currently (i.e., in this epoch) validating the\nconsumer chain. For each validator in the set we store i) its voting power, and ii) the public key that it is\nusing on the consumer chain during the current (i.e., ongoing) epoch.\nThe initial consumer validator set for a chain is set during the creation of the consumer genesis."}),"\n",(0,s.jsxs)(n.li,{children:["We introduce the ",(0,s.jsx)(n.code,{children:"BlocksPerEpoch"})," param that sets the number of blocks in an epoch. By default, ",(0,s.jsx)(n.code,{children:"BlocksPerEpoch"})," is\nset to be 600 which corresponds to 1 hour, assuming 6 seconds per block. This param can be changed through\na ",(0,s.jsx)(n.em,{children:"governance proposal"}),". In the provider ",(0,s.jsx)(n.code,{children:"EndBlock"})," we check ",(0,s.jsx)(n.code,{children:"BlockHeight() % BlocksPerEpoch() == 0"}),"\nto decide when an epoch has ended."]}),"\n",(0,s.jsxs)(n.li,{children:["At the end of every epoch, if there were validator set changes on the provider, then for every consumer chain, we\nconstruct a ",(0,s.jsx)(n.code,{children:"VSCPacket"})," with all the validator updates and add it to the list of ",(0,s.jsx)(n.code,{children:"PendingVSCPackets"}),". We compute the\nvalidator updates needed by a consumer chain by comparing the stored list of consumer validators with the current\nbonded validators on the provider, with something similar to this:"]}),"\n"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-go",children:"// get the valset that has been validating the consumer chain during this epoch \ncurrentValidators := GetConsumerValSet(consumerChain)\n// generate the validator updates needed to be sent through a `VSCPacket` by comparing the current validators \n// in the epoch with the latest bonded validators\nvalUpdates := DiffValidators(currentValidators, stakingmodule.GetBondedValidators())\n// update the current validators set for the upcoming epoch to be the latest bonded validators instead\nSetConsumerValSet(stakingmodule.GetBondedValidators())\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Note that a validator can change its consumer public key for a specific consumer chain an arbitrary amount of times during\na block and during an epoch. Then, when we generate the validator updates in ",(0,s.jsx)(n.code,{children:"DiffValidators"}),", we have to check whether\nthe current consumer public key (retrieved by calling ",(0,s.jsx)(n.code,{children:"GetValidatorConsumerPubKey"}),") is different from the consumer public\nkey the validator was using in the current epoch."]}),"\n",(0,s.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,s.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Reduce the cost of relaying."}),"\n",(0,s.jsx)(n.li,{children:"Reduce the amount of IBC packets needed for ICS."}),"\n",(0,s.jsxs)(n.li,{children:["Simplifies ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-001-key-assignment.md",children:"key-assignment code"})," because\nwe only need to check if the ",(0,s.jsx)(n.code,{children:"consumer_public_key"})," has been modified since the last epoch to generate an update."]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Increase the delay in the propagation of validator set changes (but for reasonable epoch lengths on the order of ~hours or less, this is unlikely to be significant)."}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,s.jsx)(n.p,{children:"N/A"}),"\n",(0,s.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/1087",children:"EPIC"})}),"\n"]})]})}function l(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>a,a:()=>r});var s=t(7294);const i={},o=s.createContext(i);function r(e){const n=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/6cc1db80.b94c8d42.js b/assets/js/6cc1db80.b94c8d42.js new file mode 100644 index 0000000000..ce3ea8ae44 --- /dev/null +++ b/assets/js/6cc1db80.b94c8d42.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8714],{6187:(n,e,t)=>{t.r(e),t.d(e,{assets:()=>a,contentTitle:()=>s,default:()=>l,frontMatter:()=>o,metadata:()=>c,toc:()=>u});var i=t(5893),r=t(1151);const o={sidebar_position:5},s="Joining Neutron",c={id:"validators/joining-neutron",title:"Joining Neutron",description:"Neutron is the first consumer chain to implement ICS.",source:"@site/versioned_docs/version-v5.0.0/validators/joining-neutron.md",sourceDirName:"validators",slug:"/validators/joining-neutron",permalink:"/interchain-security/v5.0.0/validators/joining-neutron",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Validator Instructions for Changeover Procedure",permalink:"/interchain-security/v5.0.0/validators/changeover-procedure"},next:{title:"Joining Stride",permalink:"/interchain-security/v5.0.0/validators/joining-stride"}},a={},u=[{value:"Resources",id:"resources",level:2}];function d(n){const e={a:"a",h1:"h1",h2:"h2",li:"li",p:"p",ul:"ul",...(0,r.a)(),...n.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"joining-neutron",children:"Joining Neutron"}),"\n",(0,i.jsx)(e.p,{children:"Neutron is the first consumer chain to implement ICS."}),"\n",(0,i.jsxs)(e.p,{children:["You can find instructions on joining the mainnet ",(0,i.jsx)(e.a,{href:"https://docs.neutron.org/neutron/consumer-chain-launch",children:"here"}),"."]}),"\n",(0,i.jsxs)(e.p,{children:["To join Neutron chain on the interchain security testnet check ",(0,i.jsx)(e.a,{href:"https://github.com/cosmos/testnets/tree/master/interchain-security/pion-1",children:"here"})]}),"\n",(0,i.jsx)(e.h2,{id:"resources",children:"Resources"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:"https://docs.neutron.org",children:"Neutron docs"})}),"\n"]})]})}function l(n={}){const{wrapper:e}={...(0,r.a)(),...n.components};return e?(0,i.jsx)(e,{...n,children:(0,i.jsx)(d,{...n})}):d(n)}},1151:(n,e,t)=>{t.d(e,{Z:()=>c,a:()=>s});var i=t(7294);const r={},o=i.createContext(r);function s(n){const e=i.useContext(o);return i.useMemo((function(){return"function"==typeof n?n(e):{...e,...n}}),[e,n])}function c(n){let e;return e=n.disableParentContext?"function"==typeof n.components?n.components(r):n.components||r:s(n.components),i.createElement(o.Provider,{value:e},n.children)}}}]); \ No newline at end of file diff --git a/assets/js/6df65b06.eb6ae8e7.js b/assets/js/6df65b06.eb6ae8e7.js new file mode 100644 index 0000000000..12fb167bc9 --- /dev/null +++ b/assets/js/6df65b06.eb6ae8e7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4366],{4878:(s,e,a)=>{a.r(e),a.d(e,{assets:()=>h,contentTitle:()=>l,default:()=>d,frontMatter:()=>t,metadata:()=>r,toc:()=>c});var i=a(5893),n=a(1151);const t={sidebar_position:3,title:"Jail Throttling"},l="ADR 002: Jail Throttling",r={id:"adrs/adr-002-throttle",title:"Jail Throttling",description:"Changelog",source:"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-002-throttle.md",sourceDirName:"adrs",slug:"/adrs/adr-002-throttle",permalink:"/interchain-security/v4.2.0/adrs/adr-002-throttle",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Jail Throttling"},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/v4.2.0/adrs/adr-001-key-assignment"},next:{title:"Equivocation governance proposal",permalink:"/interchain-security/v4.2.0/adrs/adr-003-equivocation-gov-proposal"}},h={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Required State",id:"required-state",level:3},{value:"Params",id:"params",level:3},{value:"Protocol Overview",id:"protocol-overview",level:3},{value:"OnRecvSlashPacket",id:"onrecvslashpacket",level:4},{value:"OnRecvVSCMaturedPacket",id:"onrecvvscmaturedpacket",level:4},{value:"Endblocker",id:"endblocker",level:4},{value:"Slash Meter Replenishment",id:"slash-meter-replenishment",level:5},{value:"Handle Leading VSCMaturedPackets",id:"handle-leading-vscmaturedpackets",level:5},{value:"Handle Throttle Queues",id:"handle-throttle-queues",level:5},{value:"System Properties",id:"system-properties",level:3},{value:"Main Throttling Property",id:"main-throttling-property",level:3},{value:"How Unjailing Affects the Main Throttling Property",id:"how-unjailing-affects-the-main-throttling-property",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function m(s){const e={a:"a",annotation:"annotation",blockquote:"blockquote",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",li:"li",math:"math",mfrac:"mfrac",mi:"mi",mn:"mn",mo:"mo",mrow:"mrow",msub:"msub",ol:"ol",p:"p",pre:"pre",semantics:"semantics",span:"span",strong:"strong",ul:"ul",...(0,n.a)(),...s.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"adr-002-jail-throttling",children:"ADR 002: Jail Throttling"}),"\n",(0,i.jsx)(e.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:"2023-01-26: Initial Draft"}),"\n",(0,i.jsx)(e.li,{children:"2023-02-07: Property refined, ADR ready to review/merge"}),"\n",(0,i.jsx)(e.li,{children:"2023-11-22: Refactor for better understanding"}),"\n"]}),"\n",(0,i.jsx)(e.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(e.p,{children:"Accepted"}),"\n",(0,i.jsx)(e.h2,{id:"context",children:"Context"}),"\n",(0,i.jsx)(e.p,{children:"The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols.\nIn practice, this assumption may not hold.\nA malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider."}),"\n",(0,i.jsx)(e.p,{children:"Before the throttling feature was implemented, the following attack was possible.\nAttacker(s) would create provider validators just below the provider's active set.\nUsing a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once.\nControl of the provider would then pass over to the attackers' validators.\nThis enables the attacker(s) to halt the provider.\nOr even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC."}),"\n",(0,i.jsx)(e.h2,{id:"decision",children:"Decision"}),"\n",(0,i.jsx)(e.p,{children:"The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack,\ni.e., this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time."}),"\n",(0,i.jsx)(e.h3,{id:"required-state",children:"Required State"}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:"Slash meter:"})," There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time.\nThis meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params."]}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:"Global entry queue:"}),' There exists a single queue which stores "global slash entries".\nThese entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering.\nThis queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.']}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:"Per-chain data queue:"}),' For each established consumer, there exists a queue which stores "throttled packet data",\ni.e.,pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering.\nOrder is enforced by IBC sequence number.\nThese "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.']}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.em,{children:"Note:"})," The reason for a multiple-queue design is the ",(0,i.jsx)(e.em,{children:"VSC Maturity and Slashing Order"})," property (see ",(0,i.jsx)(e.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing",children:"spec"}),").\nThere are other ways to ensure such a property (like a queue of linked lists, etc.), but the proposed approach seemed to be the most understandable and easiest to implement with a KV store."]}),"\n",(0,i.jsx)(e.h3,{id:"params",children:"Params"}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:"SlashMeterReplenishPeriod"})," -- the period after which the slash meter is replenished."]}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," -- the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs. This param also serves as a maximum fraction of total voting power that the slash meter can hold."]}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:"MaxThrottledPackets"})," -- the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value.\nThis param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness."]}),"\n",(0,i.jsx)(e.h3,{id:"protocol-overview",children:"Protocol Overview"}),"\n",(0,i.jsx)(e.h4,{id:"onrecvslashpacket",children:"OnRecvSlashPacket"}),"\n",(0,i.jsx)(e.p,{children:"Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:"}),"\n",(0,i.jsxs)(e.ol,{children:["\n",(0,i.jsx)(e.li,{children:"A global slash entry is queued."}),"\n",(0,i.jsx)(e.li,{children:"The data of such a packet is added to the per-chain queue."}),"\n"]}),"\n",(0,i.jsx)(e.h4,{id:"onrecvvscmaturedpacket",children:"OnRecvVSCMaturedPacket"}),"\n",(0,i.jsx)(e.p,{children:"Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue."}),"\n",(0,i.jsx)(e.h4,{id:"endblocker",children:"Endblocker"}),"\n",(0,i.jsxs)(e.p,{children:["In the ",(0,i.jsx)(e.code,{children:"EndBlock"})," of the provider CCV module, there are three actions performed:"]}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:"replenish the slash meter;"}),"\n",(0,i.jsxs)(e.li,{children:["handle the leading ",(0,i.jsx)(e.code,{children:"VSCMaturedPackets"}),";"]}),"\n",(0,i.jsx)(e.li,{children:"and handle the throttle queues."}),"\n"]}),"\n",(0,i.jsx)(e.h5,{id:"slash-meter-replenishment",children:"Slash Meter Replenishment"}),"\n",(0,i.jsxs)(e.p,{children:["Once the slash meter becomes not full, it'll be replenished after ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishPeriod"})," by incrementing the meter with its allowance for the replenishment block, where ",(0,i.jsx)(e.code,{children:"allowance"})," = ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," * ",(0,i.jsx)(e.code,{children:"currentTotalVotingPower"}),".\nThe slash meter will never exceed its current allowance (function of the total voting power for the block) in value."]}),"\n",(0,i.jsx)(e.p,{children:"Note a few things:"}),"\n",(0,i.jsxs)(e.ol,{children:["\n",(0,i.jsx)(e.li,{children:"The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power.\nIn such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods."}),"\n",(0,i.jsx)(e.li,{children:"Total voting power of a chain changes over time, especially as validators are jailed.\nAs validators are jailed, total voting power decreases, and so does the jailing allowance.\nSee below for more detailed throttling property discussion."}),"\n",(0,i.jsxs)(e.li,{children:["The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1.\nIf the ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," is set too low, integer rounding will put this minimum value into effect.\nThat is, if ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," * ",(0,i.jsx)(e.code,{children:"currentTotalVotingPower"})," < 1, then the effective allowance would be 1.\nThis min value of allowance ensures that there's some packets handled over time, even if that is a very long time.\nIt's a crude solution to an edge case caused by too small of a replenishment fraction."]}),"\n"]}),"\n",(0,i.jsxs)(e.p,{children:["The behavior described above is achieved by executing ",(0,i.jsx)(e.code,{children:"CheckForSlashMeterReplenishment()"})," every ",(0,i.jsx)(e.code,{children:"EndBlock"}),", BEFORE ",(0,i.jsx)(e.code,{children:"HandleThrottleQueues()"})," is executed."]}),"\n",(0,i.jsx)(e.h5,{id:"handle-leading-vscmaturedpackets",children:"Handle Leading VSCMaturedPackets"}),"\n",(0,i.jsxs)(e.p,{children:["In every block, it is possible that ",(0,i.jsx)(e.code,{children:"VSCMaturedPacket"}),' data was queued before any slash packet data.\nSince this "leading" VSCMatured packet data does not have to be throttled (see ',(0,i.jsx)(e.em,{children:"VSC Maturity and Slashing Order"}),"), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes."]}),"\n",(0,i.jsx)(e.h5,{id:"handle-throttle-queues",children:"Handle Throttle Queues"}),"\n",(0,i.jsxs)(e.p,{children:["In every ",(0,i.jsx)(e.code,{children:"EndBlock"}),", the following logic is executed to handle data from the throttle queues."]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-typescript",children:"meter := getSlashMeter()\n\n// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist \nwhile meter.IsPositiveOrZero() && entriesExist() {\n // Get next entry in queue\n entry := getNextGlobalSlashEntry()\n // Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet\n valPower := entry.getValPower()\n meter = meter - valPower\n // Using the per-chain queue, handle the single slash packet using its queued data,\n // then handle all trailing VSCMatured packets for this consumer\n handleSlashPacketAndTrailingVSCMaturedPackets(entry)\n // Delete entry in global queue, delete handled data\n entry.Delete()\n deleteThrottledSlashPacketData()\n deleteTrailingVSCMaturedPacketData()\n}\n"})}),"\n",(0,i.jsx)(e.h3,{id:"system-properties",children:"System Properties"}),"\n",(0,i.jsxs)(e.p,{children:["All CCV system properties should be maintained by implementing this feature, see ",(0,i.jsx)(e.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing",children:"CCV spec - Consumer Initiated Slashing"}),"."]}),"\n",(0,i.jsxs)(e.p,{children:["One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than ",(0,i.jsx)(e.code,{children:"MaxThrottledPackets"}),", then the provider binary will panic, and the provider chain will halt.\nTherefore this param should be set carefully. See ",(0,i.jsx)(e.code,{children:"SetThrottledPacketDataSize"}),".\nThis behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators."]}),"\n",(0,i.jsx)(e.h3,{id:"main-throttling-property",children:"Main Throttling Property"}),"\n",(0,i.jsx)(e.p,{children:"Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions."}),"\n",(0,i.jsx)(e.p,{children:"First, we introduce the following definitions:"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:'A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.'}),"\n",(0,i.jsx)(e.li,{children:'The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.'}),"\n",(0,i.jsxs)(e.li,{children:["There is a list of honest validators such that if they are jailed, ",(0,i.jsx)(e.code,{children:"X"}),"% of the initial validator set will be jailed."]}),"\n"]}),"\n",(0,i.jsx)(e.p,{children:"For the Throttling Property to hold, the following assumptions must be true:"}),"\n",(0,i.jsxs)(e.ol,{children:["\n",(0,i.jsx)(e.li,{children:"We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack."}),"\n",(0,i.jsxs)(e.li,{children:["No validator has more than ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," of total voting power on the provider."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," is large enough that ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," * ",(0,i.jsx)(e.code,{children:"currentTotalVotingPower"})," > 1,\ni.e., the replenish fraction is set high enough that we can ignore the effects of rounding."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:"SlashMeterReplenishPeriod"})," is sufficiently longer than the time it takes to produce a block."]}),"\n"]}),"\n",(0,i.jsx)(e.p,{children:(0,i.jsx)(e.em,{children:"Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined."})}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:"Throttling Property"}),": The time it takes to jail/tombstone ",(0,i.jsx)(e.code,{children:"X"}),"% of the initial validator set will be greater than or equal to\n",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"S"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"M"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"R"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"p"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"n"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"P"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"o"}),(0,i.jsx)(e.mi,{children:"d"})]}),(0,i.jsx)(e.mo,{children:"\u22c5"}),(0,i.jsxs)(e.mfrac,{children:[(0,i.jsx)(e.mi,{children:"X"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"S"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"M"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"R"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"p"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"n"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"F"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"c"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"o"}),(0,i.jsx)(e.mi,{children:"n"})]})]}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mn,{children:"2"}),(0,i.jsx)(e.mo,{children:"\u22c5"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"S"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"M"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"R"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"p"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"n"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"P"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"o"}),(0,i.jsx)(e.mi,{children:"d"})]})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\mathit{SlashMeterReplenishPeriod} \\cdot \\frac{X}{\\mathit{SlashMeterReplenishFraction}} - 2 \\cdot \\mathit{SlashMeterReplenishPeriod}"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,i.jsx)(e.span,{className:"mord",children:(0,i.jsx)(e.span,{className:"mord mathit",children:"SlashMeterReplenishPeriod"})}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u22c5"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"1.3534em",verticalAlign:"-0.4811em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,i.jsx)(e.span,{className:"mfrac",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsxs)(e.span,{className:"vlist",style:{height:"0.8723em"},children:[(0,i.jsxs)(e.span,{style:{top:"-2.655em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"SlashMeterReplenishFraction"})})})})]}),(0,i.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,i.jsxs)(e.span,{style:{top:"-3.394em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.07847em"},children:"X"})})})]})]}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.4811em"},children:(0,i.jsx)(e.span,{})})})]})}),(0,i.jsx)(e.span,{className:"mclose nulldelimiter"})]}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6444em"}}),(0,i.jsx)(e.span,{className:"mord",children:"2"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u22c5"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,i.jsx)(e.span,{className:"mord",children:(0,i.jsx)(e.span,{className:"mord mathit",children:"SlashMeterReplenishPeriod"})})]})]})]}),"."]}),"\n",(0,i.jsxs)(e.blockquote,{children:["\n",(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:"Intuition"})}),"\n",(0,i.jsx)(e.p,{children:"Let's use the following notation:"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:[(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"C"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"})]})})]}),": Number of replenishment cycles"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"P"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"P"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"P"})]})})]}),": ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"S"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"M"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"R"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"p"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"n"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"P"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"o"}),(0,i.jsx)(e.mi,{children:"d"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\mathit{SlashMeterReplenishPeriod}"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,i.jsx)(e.span,{className:"mord",children:(0,i.jsx)(e.span,{className:"mord mathit",children:"SlashMeterReplenishPeriod"})})]})})]})]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"F"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"F"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"})]})})]}),": ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"S"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"M"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"R"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"p"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"n"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"F"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"c"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"o"}),(0,i.jsx)(e.mi,{children:"n"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\mathit{SlashMeterReplenishFraction}"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,i.jsx)(e.span,{className:"mord",children:(0,i.jsx)(e.span,{className:"mord mathit",children:"SlashMeterReplenishFraction"})})]})})]})]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsxs)(e.msub,{children:[(0,i.jsx)(e.mi,{children:"V"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"m"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"x"})]})]})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"V_{\\mathit{max}}"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.22222em"},children:"V"}),(0,i.jsx)(e.span,{className:"msupsub",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.1514em"},children:(0,i.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.2222em",marginRight:"0.05em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"max"})})})})]})}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,i.jsx)(e.span,{})})})]})})]})]})})]}),": Max power of a validator as a fraction of total voting power"]}),"\n"]}),"\n",(0,i.jsxs)(e.p,{children:["In ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"C"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"})]})})]})," number of replenishment cycles, the fraction of total voting power that can be removed, ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"a"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"a"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.4306em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",children:"a"})]})})]}),", is ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mo,{children:"\u2264"}),(0,i.jsx)(e.mi,{children:"F"}),(0,i.jsx)(e.mo,{children:"\u22c5"}),(0,i.jsx)(e.mi,{children:"C"}),(0,i.jsx)(e.mo,{children:"+"}),(0,i.jsxs)(e.msub,{children:[(0,i.jsx)(e.mi,{children:"V"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"m"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"x"})]})]})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"a \\leq F \\cdot C + V_{\\mathit{max}}"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.7719em",verticalAlign:"-0.136em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",children:"a"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,i.jsx)(e.span,{className:"mrel",children:"\u2264"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u22c5"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.7667em",verticalAlign:"-0.0833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"+"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.22222em"},children:"V"}),(0,i.jsx)(e.span,{className:"msupsub",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.1514em"},children:(0,i.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.2222em",marginRight:"0.05em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"max"})})})})]})}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,i.jsx)(e.span,{})})})]})})]})]})]})]})," (where ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsxs)(e.msub,{children:[(0,i.jsx)(e.mi,{children:"V"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"m"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"x"})]})]})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"V_{\\mathit{max}}"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.22222em"},children:"V"}),(0,i.jsx)(e.span,{className:"msupsub",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.1514em"},children:(0,i.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.2222em",marginRight:"0.05em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"max"})})})})]})}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,i.jsx)(e.span,{})})})]})})]})]})})]})," is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value)."]}),"\n",(0,i.jsxs)(e.p,{children:["So, we need at least ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"C"}),(0,i.jsx)(e.mo,{children:"\u2265"}),(0,i.jsxs)(e.mfrac,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsxs)(e.msub,{children:[(0,i.jsx)(e.mi,{children:"V"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"m"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"x"})]})]})]}),(0,i.jsx)(e.mi,{children:"F"})]})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C \\geq \\frac{a - V_{\\mathit{max}}}{F}"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8193em",verticalAlign:"-0.136em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,i.jsx)(e.span,{className:"mrel",children:"\u2265"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"1.2334em",verticalAlign:"-0.345em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,i.jsx)(e.span,{className:"mfrac",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsxs)(e.span,{className:"vlist",style:{height:"0.8884em"},children:[(0,i.jsxs)(e.span,{style:{top:"-2.655em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"})})})]}),(0,i.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,i.jsxs)(e.span,{style:{top:"-3.4101em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mord mathnormal mtight",children:"a"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u2212"}),(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.22222em"},children:"V"}),(0,i.jsx)(e.span,{className:"msupsub",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.1645em"},children:(0,i.jsxs)(e.span,{style:{top:"-2.357em",marginLeft:"-0.2222em",marginRight:"0.0714em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"2.5em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size3 size1 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"max"})})})})]})}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.143em"},children:(0,i.jsx)(e.span,{})})})]})})]})]})})]})]}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.345em"},children:(0,i.jsx)(e.span,{})})})]})}),(0,i.jsx)(e.span,{className:"mclose nulldelimiter"})]})]})]})]})," cycles to remove ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"a"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"a"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.4306em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",children:"a"})]})})]})," fraction of the total voting power."]}),"\n",(0,i.jsxs)(e.p,{children:["Since we defined the start of the attack to be the moment when the first slash request arrives, then ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"F"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"F"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"})]})})]})," fraction of the initial validator set can be jailed immediately. For the remaining ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"X"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mi,{children:"F"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"X - F"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.7667em",verticalAlign:"-0.0833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07847em"},children:"X"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"})]})]})]})," fraction of the initial validator set to be jailed, it takes at least ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"C"}),(0,i.jsx)(e.mo,{children:"\u2265"}),(0,i.jsxs)(e.mfrac,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mo,{stretchy:"false",children:"("}),(0,i.jsx)(e.mi,{children:"X"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mi,{children:"F"}),(0,i.jsx)(e.mo,{stretchy:"false",children:")"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsxs)(e.msub,{children:[(0,i.jsx)(e.mi,{children:"V"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"m"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"x"})]})]})]}),(0,i.jsx)(e.mi,{children:"F"})]})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C \\geq \\frac{(X - F) - V_{\\mathit{max}}}{F}"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8193em",verticalAlign:"-0.136em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,i.jsx)(e.span,{className:"mrel",children:"\u2265"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"1.355em",verticalAlign:"-0.345em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,i.jsx)(e.span,{className:"mfrac",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsxs)(e.span,{className:"vlist",style:{height:"1.01em"},children:[(0,i.jsxs)(e.span,{style:{top:"-2.655em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"})})})]}),(0,i.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,i.jsxs)(e.span,{style:{top:"-3.485em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mopen mtight",children:"("}),(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.07847em"},children:"X"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"}),(0,i.jsx)(e.span,{className:"mclose mtight",children:")"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u2212"}),(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.22222em"},children:"V"}),(0,i.jsx)(e.span,{className:"msupsub",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.1645em"},children:(0,i.jsxs)(e.span,{style:{top:"-2.357em",marginLeft:"-0.2222em",marginRight:"0.0714em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"2.5em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size3 size1 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"max"})})})})]})}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.143em"},children:(0,i.jsx)(e.span,{})})})]})})]})]})})]})]}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.345em"},children:(0,i.jsx)(e.span,{})})})]})}),(0,i.jsx)(e.span,{className:"mclose nulldelimiter"})]})]})]})]})," cycles. Using the assumption that ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsxs)(e.msub,{children:[(0,i.jsx)(e.mi,{children:"V"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"m"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"x"})]})]}),(0,i.jsx)(e.mo,{children:"\u2264"}),(0,i.jsx)(e.mi,{children:"F"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"V_{\\mathit{max}} \\leq F"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.22222em"},children:"V"}),(0,i.jsx)(e.span,{className:"msupsub",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.1514em"},children:(0,i.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.2222em",marginRight:"0.05em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"max"})})})})]})}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,i.jsx)(e.span,{})})})]})})]}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,i.jsx)(e.span,{className:"mrel",children:"\u2264"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"})]})]})]})," (assumption 2), we get ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"C"}),(0,i.jsx)(e.mo,{children:"\u2265"}),(0,i.jsxs)(e.mfrac,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"X"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mn,{children:"2"}),(0,i.jsx)(e.mi,{children:"F"})]}),(0,i.jsx)(e.mi,{children:"F"})]})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C \\geq \\frac{X - 2F}{F}"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8193em",verticalAlign:"-0.136em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,i.jsx)(e.span,{className:"mrel",children:"\u2265"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"1.2173em",verticalAlign:"-0.345em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,i.jsx)(e.span,{className:"mfrac",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsxs)(e.span,{className:"vlist",style:{height:"0.8723em"},children:[(0,i.jsxs)(e.span,{style:{top:"-2.655em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"})})})]}),(0,i.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,i.jsxs)(e.span,{style:{top:"-3.394em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.07847em"},children:"X"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mord mtight",children:"2"}),(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"})]})})]})]}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.345em"},children:(0,i.jsx)(e.span,{})})})]})}),(0,i.jsx)(e.span,{className:"mclose nulldelimiter"})]})]})]})]})," cycles."]}),"\n",(0,i.jsxs)(e.p,{children:["In order to execute ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"C"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"})]})})]})," cycles, we need ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"C"}),(0,i.jsx)(e.mo,{children:"\u22c5"}),(0,i.jsx)(e.mi,{children:"P"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C \\cdot P"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u22c5"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"P"})]})]})]})," time."]}),"\n",(0,i.jsxs)(e.p,{children:["Thus, jailing the remaining ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"X"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mi,{children:"F"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"X - F"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.7667em",verticalAlign:"-0.0833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07847em"},children:"X"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"})]})]})]})," fraction of the initial validator set corresponds to ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsxs)(e.mfrac,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"P"}),(0,i.jsx)(e.mo,{children:"\u22c5"}),(0,i.jsx)(e.mo,{stretchy:"false",children:"("}),(0,i.jsx)(e.mi,{children:"X"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mn,{children:"2"}),(0,i.jsx)(e.mi,{children:"F"}),(0,i.jsx)(e.mo,{stretchy:"false",children:")"})]}),(0,i.jsx)(e.mi,{children:"F"})]})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\frac{P \\cdot (X - 2F)}{F}"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"1.355em",verticalAlign:"-0.345em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,i.jsx)(e.span,{className:"mfrac",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsxs)(e.span,{className:"vlist",style:{height:"1.01em"},children:[(0,i.jsxs)(e.span,{style:{top:"-2.655em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"})})})]}),(0,i.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,i.jsxs)(e.span,{style:{top:"-3.485em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"P"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u22c5"}),(0,i.jsx)(e.span,{className:"mopen mtight",children:"("}),(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.07847em"},children:"X"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mord mtight",children:"2"}),(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"}),(0,i.jsx)(e.span,{className:"mclose mtight",children:")"})]})})]})]}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.345em"},children:(0,i.jsx)(e.span,{})})})]})}),(0,i.jsx)(e.span,{className:"mclose nulldelimiter"})]})]})})]})," time."]}),"\n",(0,i.jsxs)(e.p,{children:["In other words, the attack must take at least ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsxs)(e.mfrac,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"P"}),(0,i.jsx)(e.mo,{children:"\u22c5"}),(0,i.jsx)(e.mi,{children:"X"})]}),(0,i.jsx)(e.mi,{children:"F"})]}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mn,{children:"2"}),(0,i.jsx)(e.mi,{children:"P"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\frac{P \\cdot X}{F} - 2P"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"1.2173em",verticalAlign:"-0.345em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,i.jsx)(e.span,{className:"mfrac",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsxs)(e.span,{className:"vlist",style:{height:"0.8723em"},children:[(0,i.jsxs)(e.span,{style:{top:"-2.655em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"})})})]}),(0,i.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,i.jsxs)(e.span,{style:{top:"-3.394em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"P"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u22c5"}),(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.07847em"},children:"X"})]})})]})]}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.345em"},children:(0,i.jsx)(e.span,{})})})]})}),(0,i.jsx)(e.span,{className:"mclose nulldelimiter"})]}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord",children:"2"}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"P"})]})]})]})," time (in the units of replenish period ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"P"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"P"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"P"})]})})]}),")."]}),"\n"]}),"\n",(0,i.jsxs)(e.p,{children:["This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests.\nFor example, if ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," is set to ",(0,i.jsx)(e.code,{children:"0.06"}),", then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub.\nNote that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power."]}),"\n",(0,i.jsx)(e.p,{children:"Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings."}),"\n",(0,i.jsx)(e.h3,{id:"how-unjailing-affects-the-main-throttling-property",children:"How Unjailing Affects the Main Throttling Property"}),"\n",(0,i.jsx)(e.p,{children:"Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained."}),"\n",(0,i.jsx)(e.p,{children:"If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider."}),"\n",(0,i.jsx)(e.p,{children:"In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack."}),"\n",(0,i.jsx)(e.h2,{id:"consequences",children:"Consequences"}),"\n",(0,i.jsx)(e.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:"The described attack is slowed down in seemingly all cases."}),"\n",(0,i.jsx)(e.li,{children:"If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded."}),"\n"]}),"\n",(0,i.jsx)(e.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:["Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below.\nHowever, this is sacrificing liveness in a edge case scenario for the sake of security.\nAs an improvement, ",(0,i.jsx)(e.a,{href:"https://github.com/cosmos/interchain-security/issues/713",children:"using retries"})," would fully prevent this attack vector."]}),"\n"]}),"\n",(0,i.jsx)(e.h3,{id:"neutral",children:"Neutral"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:"Additional state is introduced to the provider chain."}),"\n",(0,i.jsx)(e.li,{children:"VSCMatured and slash packet data is not always handled in the same block that it is received."}),"\n"]}),"\n",(0,i.jsx)(e.h2,{id:"references",children:"References"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:"https://github.com/cosmos/interchain-security/issues/404",children:"Original issue inspiring throttling feature"})}),"\n",(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:"https://github.com/cosmos/interchain-security/issues/594",children:"Issue on DOS vector"})}),"\n",(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:"https://github.com/cosmos/interchain-security/issues/685",children:"Consideration of another attack vector"})}),"\n"]})]})}function d(s={}){const{wrapper:e}={...(0,n.a)(),...s.components};return e?(0,i.jsx)(e,{...s,children:(0,i.jsx)(m,{...s})}):m(s)}},1151:(s,e,a)=>{a.d(e,{Z:()=>r,a:()=>l});var i=a(7294);const n={},t=i.createContext(n);function l(s){const e=i.useContext(t);return i.useMemo((function(){return"function"==typeof s?s(e):{...e,...s}}),[e,s])}function r(s){let e;return e=s.disableParentContext?"function"==typeof s.components?s.components(n):s.components||n:l(s.components),i.createElement(t.Provider,{value:e},s.children)}}}]); \ No newline at end of file diff --git a/assets/js/6f71328c.dbe2f06e.js b/assets/js/6f71328c.dbe2f06e.js new file mode 100644 index 0000000000..51617e65df --- /dev/null +++ b/assets/js/6f71328c.dbe2f06e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8560],{9371:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>h,contentTitle:()=>a,default:()=>l,frontMatter:()=>t,metadata:()=>r,toc:()=>d});var i=o(5893),s=o(1151);const t={sidebar_position:14,title:"Slashing on the provider for consumer equivocation"},a="ADR 013: Slashing on the provider for consumer equivocation",r={id:"adrs/adr-013-equivocation-slashing",title:"Slashing on the provider for consumer equivocation",description:"Changelog",source:"@site/docs/adrs/adr-013-equivocation-slashing.md",sourceDirName:"adrs",slug:"/adrs/adr-013-equivocation-slashing",permalink:"/interchain-security/adrs/adr-013-equivocation-slashing",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:14,frontMatter:{sidebar_position:14,title:"Slashing on the provider for consumer equivocation"},sidebar:"tutorialSidebar",previous:{title:"Separate Releasing",permalink:"/interchain-security/adrs/adr-012-separate-releasing"},next:{title:"Epochs",permalink:"/interchain-security/adrs/adr-014-epochs"}},h={},d=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Single-chain slashing",id:"single-chain-slashing",level:3},{value:"Slashing undelegations and redelegations",id:"slashing-undelegations-and-redelegations",level:4},{value:"Slashing delegations",id:"slashing-delegations",level:4},{value:"Old evidence",id:"old-evidence",level:4},{value:"Slashing for equivocation on the consumer",id:"slashing-for-equivocation-on-the-consumer",level:3},{value:"Proposed solution",id:"proposed-solution",level:2},{value:"Implementation",id:"implementation",level:3},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}];function c(e){const n={a:"a",blockquote:"blockquote",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"adr-013-slashing-on-the-provider-for-consumer-equivocation",children:"ADR 013: Slashing on the provider for consumer equivocation"}),"\n",(0,i.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"1st Sept. 2023: Initial draft"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(n.p,{children:"Accepted"}),"\n",(0,i.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,i.jsxs)(n.p,{children:["This ADR presents some approaches on how to slash on the provider chain validators that performed equivocations on consumer chains.\nCurrently, the provider chain can ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/1232",children:"receive and verify evidence of equivocation"}),", but it cannot slash the misbehaving validator."]}),"\n",(0,i.jsx)(n.p,{children:"In the remainder of this section, we explain how slashing is performed on a single chain and show why slashing on the provider for equivocation on the consumer is challenging."}),"\n",(0,i.jsxs)(n.p,{children:["Note that future versions of the Cosmos SDK, CometBFT, and ibc-go could modify the way we slash, etc. Therefore, a future reader of this ADR, should note that when we refer to Cosmos SDK, CometBFT, and ibc-go we specifically refer to their ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/v0.47/intro/overview",children:"v0.47"}),", ",(0,i.jsx)(n.a,{href:"https://docs.cometbft.com/v0.37/",children:"v0.37"})," and ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/ibc-go/blob/v7.3.0",children:"v7.3.0"})," versions respectively."]}),"\n",(0,i.jsx)(n.h3,{id:"single-chain-slashing",children:"Single-chain slashing"}),"\n",(0,i.jsxs)(n.p,{children:["Slashing is implemented across the ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/v0.47/modules/slashing",children:"slashing"}),"\nand ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/v0.47/modules/staking",children:"staking"})," modules.\nThe slashing module's keeper calls the staking module's ",(0,i.jsx)(n.code,{children:"Slash()"})," method, passing among others, the ",(0,i.jsx)(n.code,{children:"infractionHeight"})," (i.e., the height when the equivocation occurred), the validator's ",(0,i.jsx)(n.code,{children:"power"})," at the infraction height, and the ",(0,i.jsx)(n.code,{children:"slashFactor"})," (currently set to ",(0,i.jsx)(n.code,{children:"5%"})," in case of equivocation on the Cosmos Hub)."]}),"\n",(0,i.jsx)(n.h4,{id:"slashing-undelegations-and-redelegations",children:"Slashing undelegations and redelegations"}),"\n",(0,i.jsxs)(n.p,{children:["To slash undelegations, ",(0,i.jsx)(n.code,{children:"Slash"})," goes through all undelegations and checks whether they started before or after the infraction occurred. If an undelegation started before the ",(0,i.jsx)(n.code,{children:"infractionHeight"}),", then it is ",(0,i.jsx)(n.strong,{children:"not"})," slashed, otherwise it is slashed by ",(0,i.jsx)(n.code,{children:"slashFactor"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["The slashing of redelegations happens in a similar way, meaning that ",(0,i.jsx)(n.code,{children:"Slash"})," goes through all redelegations and checks whether the redelegations started before or after the ",(0,i.jsx)(n.code,{children:"infractionHeight"}),"."]}),"\n",(0,i.jsx)(n.h4,{id:"slashing-delegations",children:"Slashing delegations"}),"\n",(0,i.jsxs)(n.p,{children:["Besides undelegations and redelegations, the validator's delegations need to also be slashed.\nThis is performed by deducting the appropriate amount of tokens from the validator. Note that this deduction is computed based on the voting ",(0,i.jsx)(n.code,{children:"power"})," the misbehaving validator had at the height of the equivocation. As a result of the tokens deduction,\nthe ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/v0.47/modules/staking#delegator-shares",children:"tokens per share"}),"\nreduce and hence later on, when delegators undelegate or redelegate, the delegators retrieve back less\ntokens, effectively having their tokens slashed. The rationale behind this slashing mechanism, as mentioned in the ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/v0.47/modules/staking#delegator-shares",children:"Cosmos SDK documentation"})]}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsx)(n.p,{children:"[...] is to simplify the accounting around slashing. Rather than iteratively slashing the tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, effectively reducing the value of each issued delegator share."}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["This approach of slashing delegations does not utilize the\n",(0,i.jsx)(n.code,{children:"infractionHeight"})," in any way and hence the following scenario could occur:"]}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["a validator ",(0,i.jsx)(n.code,{children:"V"})," performs an equivocation at a height ",(0,i.jsx)(n.code,{children:"Hi"})]}),"\n",(0,i.jsxs)(n.li,{children:["a new delegator ",(0,i.jsx)(n.code,{children:"D"})," delegates to ",(0,i.jsx)(n.code,{children:"V"})," after height ",(0,i.jsx)(n.code,{children:"Hi"})]}),"\n",(0,i.jsxs)(n.li,{children:["evidence of the equivocation by validator ",(0,i.jsx)(n.code,{children:"V"})," is received"]}),"\n",(0,i.jsxs)(n.li,{children:["the tokens of delegator ",(0,i.jsx)(n.code,{children:"D"})," are slashed"]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["In the above scenario, delegator ",(0,i.jsx)(n.code,{children:"D"})," is slashed, even though ",(0,i.jsx)(n.code,{children:"D"}),"'s voting power did not contribute to the infraction."]}),"\n",(0,i.jsx)(n.h4,{id:"old-evidence",children:"Old evidence"}),"\n",(0,i.jsxs)(n.p,{children:["In the single-chain case, old evidence (e.g., from 3 years ago) is ignored. This is achieved through\n",(0,i.jsx)(n.a,{href:"https://docs.cometbft.com/v0.37/spec/consensus/evidence",children:"CometBFT"})," that ignores old evidence based on the parameters ",(0,i.jsx)(n.code,{children:"MaxAgeNumBlocks"})," and ",(0,i.jsx)(n.code,{children:"MaxAgeDuration"})," (see ",(0,i.jsx)(n.a,{href:"https://github.com/cometbft/cometbft/blob/v0.37.0/evidence/pool.go#271",children:"here"}),").\nAdditionally, note that when the evidence is sent by CometBFT to the application, the evidence is rechecked in the ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L54",children:"evidence module"})," of Cosmos SDK and if it is old, the evidence is ignored.\nIn Cosmos Hub, the ",(0,i.jsx)(n.code,{children:"MaxAgeNumBlocks"})," is set to 1000000 (i.e., ~70 days if we assume we need ~6 sec per block) and ",(0,i.jsx)(n.code,{children:"MaxAgeDuration"})," is set to 172800000000000 ns (i.e., 2 days). Because of this check, we can easily exclude old evidence."]}),"\n",(0,i.jsx)(n.h3,{id:"slashing-for-equivocation-on-the-consumer",children:"Slashing for equivocation on the consumer"}),"\n",(0,i.jsxs)(n.p,{children:["In the single-chain case, slashing requires both the ",(0,i.jsx)(n.code,{children:"infractionHeight"})," and the voting ",(0,i.jsx)(n.code,{children:"power"}),".\nIn order to slash on the provider for an equivocation on a consumer, we need to have both the provider's ",(0,i.jsx)(n.code,{children:"infractionHeight"})," and voting ",(0,i.jsx)(n.code,{children:"power"}),".\nNote that the ",(0,i.jsx)(n.code,{children:"infractionHeight"})," on the consumer chain must be mapped to a height on the provider chain.\nUnless we have a way to find the corresponding ",(0,i.jsx)(n.code,{children:"infractionHeight"})," and ",(0,i.jsx)(n.code,{children:"power"})," on the provider chain, we cannot slash for equivocation on the consumer in the same way as we would slash in the single-chain case."]}),"\n",(0,i.jsxs)(n.p,{children:["The challenge of figuring out the corresponding ",(0,i.jsx)(n.code,{children:"infractionHeight"})," and ",(0,i.jsx)(n.code,{children:"power"})," values on the provider chain is due to the following trust assumption:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["We trust the consensus layer and validator set of the consumer chains, ",(0,i.jsx)(n.em,{children:"but we do not trust the application layer"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["As a result, we cannot trust anything that stems from the ",(0,i.jsx)(n.em,{children:"application state"})," of a consumer chain."]}),"\n",(0,i.jsxs)(n.p,{children:["Note that when a relayer or a user sends evidence through a ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/1232",children:"MsgSubmitConsumerDoubleVoting"})," message, the provider gets access to ",(0,i.jsx)(n.a,{href:"https://github.com/cometbft/cometbft/blob/v0.37.0/types/evidence.go#L35",children:"DuplicateVoteEvidence"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-protobuf",children:'type DuplicateVoteEvidence struct {\n\tVoteA *Vote `json:"vote_a"`\n\tVoteB *Vote `json:"vote_b"`\n\n\t// abci specific information\n\tTotalVotingPower int64\n\tValidatorPower int64\n\tTimestamp time.Time\n}\n'})}),"\n",(0,i.jsxs)(n.p,{children:['The "abci specific information" fields cannot be trusted because they are not signed. Therefore,\nwe can use neither ',(0,i.jsx)(n.code,{children:"ValidatorPower"})," for slashing on the provider chain, nor the ",(0,i.jsx)(n.code,{children:"Timestamp"})," to check the evidence age. We can get the ",(0,i.jsx)(n.code,{children:"infractionHeight"})," from the votes, but this ",(0,i.jsx)(n.code,{children:"infractionHeight"})," corresponds to the infraction height on the consumer and ",(0,i.jsx)(n.strong,{children:"not"})," on the provider chain.\nSimilarly, when a relayer or a user sends evidence through a ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/826",children:"MsgSubmitConsumerMisbehaviour"})," message, the provider gets access to ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/ibc-go/blob/v7.3.0/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79",children:"Misbehaviour"})," that we cannot use to extract the infraction height, power, or the time on the provider chain."]}),"\n",(0,i.jsx)(n.h2,{id:"proposed-solution",children:"Proposed solution"}),"\n",(0,i.jsx)(n.p,{children:"As a first iteration, we propose the following approach. At the moment the provider receives evidence of equivocation on a consumer:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["slash all the undelegations and redelegations using ",(0,i.jsx)(n.code,{children:"slashFactor"}),";"]}),"\n",(0,i.jsxs)(n.li,{children:["slash all delegations using as voting ",(0,i.jsx)(n.code,{children:"power"})," the sum of the voting power of the misbehaving validator and the power of all the ongoing undelegations and redelegations."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Evidence expiration:"})," Additionally, because we cannot infer the actual time of the evidence (i.e., the timestamp of the evidence cannot be trusted), we do not consider ",(0,i.jsx)(n.em,{children:"evidence expiration"})," and hence old evidence is never ignored (e.g., the provider would act on 3 year-old evidence of equivocation on a consumer).\nAdditionally, we do not need to store equivocation evidence to avoid slashing a validator more than once, because we ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L94",children:"do not slash"})," tombstoned validators and we ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L138",children:"tombstone"})," a validator when slashed."]}),"\n",(0,i.jsxs)(n.p,{children:["We do not act on evidence that was signed by a validator ",(0,i.jsx)(n.a,{href:"https://tutorials.cosmos.network/tutorials/9-path-to-prod/3-keys.html#what-validator-keys",children:"consensus key"})," that is ",(0,i.jsx)(n.em,{children:"pruned"})," when we receive the evidence. We prune a validator's consensus key if the validator has assigned a new consumer key (using ",(0,i.jsx)(n.code,{children:"MsgAssignConsumerKey"}),") and an unbonding period on the consumer chain has elapsed (see ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-001-key-assignment.md",children:"key assignment ADR"}),"). Note that the provider chain is informed that the unbonding period has elapsed on the consumer when the provider receives a ",(0,i.jsx)(n.code,{children:"VSCMaturedPacket"})," and because of this, if the consumer delays the sending of a ",(0,i.jsx)(n.code,{children:"VSCMaturedPacket"}),", we would delay the pruning of the key as well."]}),"\n",(0,i.jsx)(n.h3,{id:"implementation",children:"Implementation"}),"\n",(0,i.jsxs)(n.p,{children:["The following logic needs to be added to the ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/1232",children:"HandleConsumerDoubleVoting"})," and ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/826",children:"HandleConsumerMisbehaviour"})," methods:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-go",children:"undelegationsInTokens := sdk.NewInt(0)\nfor _, v := range k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validatorAddress) {\n for _, entry := range v.Entries {\n if entry.IsMature(now) && !entry.OnHold() {\n // undelegation no longer eligible for slashing, skip it\n continue\n }\n undelegationsInTokens = undelegationsInTokens.Add(entry.InitialBalance)\n }\n}\n\nredelegationsInTokens := sdk.NewInt(0)\nfor _, v := range k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validatorAddress) {\n for _, entry := range v.Entries {\n if entry.IsMature(now) && !entry.OnHold() {\n // redelegation no longer eligible for slashing, skip it\n continue\n }\n redelegationsInTokens = redelegationsInTokens.Add(entry.InitialBalance)\n }\n}\n\ninfractionHeight := 0\nundelegationsAndRedelegationsInPower = sdk.TokensToConsensusPower(undelegationsInTokens.Add(redelegationsInTokens))\ntotalPower := validator's voting power + undelegationsAndRedelegationsInPower\nslashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)\n\nk.stakingKeeper.Slash(ctx, validatorConsAddress, infractionHeight, totalPower, slashFraction, DoubleSign)\n"})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Infraction height:"})," We provide a zero ",(0,i.jsx)(n.code,{children:"infractionHeight"})," to the ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L33",children:"Slash"})," method in order to slash all ongoing undelegations and redelegations (see checks in ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L92",children:"Slash"}),", ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L195",children:"SlashUnbondingDelegation"}),", and ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L249",children:"SlashRedelegation"}),")."]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Power:"})," We pass the sum of the voting power of the misbehaving validator when the evidence was received (i.e., at evidence height) and the power of all the ongoing undelegations and redelegations.\nIf we assume that the ",(0,i.jsx)(n.code,{children:"slashFactor"})," is ",(0,i.jsx)(n.code,{children:"5%"}),", then the voting power we pass is ",(0,i.jsx)(n.code,{children:"power + totalPower(undelegations) + totalPower(redelegations)"}),".\nHence, when the ",(0,i.jsx)(n.code,{children:"Slash"})," method slashes all the undelegations and redelegations it would end up with ",(0,i.jsx)(n.code,{children:"0.05 * power + 0.05 * totalPower(undelegations) + 0.05 * totalPower(redelegations) - 0.05 * totalPower(undelegations) - 0.05 * totalPower(redelegations) = 0.05 * power"})," and hence it would slash ",(0,i.jsx)(n.code,{children:"5%"})," of the validator's power when the evidence is received."]}),"\n",(0,i.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsx)(n.p,{children:"With the proposed approach we can quickly implement slashing functionality on the provider chain for consumer chain equivocations.\nThis approach does not need to change the staking module and therefore does not change in any way how slashing is performed today for a single chain."}),"\n",(0,i.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["We ",(0,i.jsx)(n.em,{children:"definitely"})," slash more when it comes to undelegations and redelegations because we slash for all of them without considering an ",(0,i.jsx)(n.code,{children:"infractionHeight"}),"."]}),"\n",(0,i.jsxs)(n.li,{children:["We ",(0,i.jsx)(n.em,{children:"potentially"})," slash more than what we would have slashed if we knew the voting ",(0,i.jsx)(n.code,{children:"power"})," at the corresponding ",(0,i.jsx)(n.code,{children:"infractionHeight"})," in the provider chain."]}),"\n",(0,i.jsx)(n.li,{children:"We slash on old evidence of equivocation on a consumer."}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md",children:"ADR 005: Cryptographic verification of equivocation evidence"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/732",children:"EPIC tracking cryptographic equivocation feature"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://forum.cosmos.network/t/cryptographic-equivocation-slashing-design/11400",children:"Cosmos Hub Forum discussion on cryptographic equivocation slashing"})}),"\n"]})]})}function l(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},1151:(e,n,o)=>{o.d(n,{Z:()=>r,a:()=>a});var i=o(7294);const s={},t=i.createContext(s);function a(e){const n=i.useContext(t);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),i.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/700b5f22.48455c22.js b/assets/js/700b5f22.48455c22.js new file mode 100644 index 0000000000..785e97a2aa --- /dev/null +++ b/assets/js/700b5f22.48455c22.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5612],{8734:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>c,contentTitle:()=>s,default:()=>l,frontMatter:()=>a,metadata:()=>r,toc:()=>h});var t=n(5893),o=n(1151);const a={sidebar_position:6},s="Partial Set Security",r={id:"validators/partial-set-security-for-validators",title:"Partial Set Security",description:"Partial Set Security allows consumer chains to join as Opt-In or Top N.",source:"@site/docs/validators/partial-set-security-for-validators.md",sourceDirName:"validators",slug:"/validators/partial-set-security-for-validators",permalink:"/interchain-security/validators/partial-set-security-for-validators",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"tutorialSidebar",previous:{title:"Joining Stride",permalink:"/interchain-security/validators/joining-stride"},next:{title:"Frequently Asked Questions",permalink:"/interchain-security/faq"}},c={},h=[{value:"Messages",id:"messages",level:2},{value:"How to opt in to a consumer chain?",id:"how-to-opt-in-to-a-consumer-chain",level:3},{value:"How to opt out from a consumer chain?",id:"how-to-opt-out-from-a-consumer-chain",level:3},{value:"How to set specific per consumer chain commission rate?",id:"how-to-set-specific-per-consumer-chain-commission-rate",level:3},{value:"Queries",id:"queries",level:2},{value:"Which chains does a validator have to validate?",id:"which-chains-does-a-validator-have-to-validate",level:3},{value:"How do you know how much voting power you need to have to be in the top N for a chain?",id:"how-do-you-know-how-much-voting-power-you-need-to-have-to-be-in-the-top-n-for-a-chain",level:3},{value:"How to retrieve all the opted-in validators on a consumer chain?",id:"how-to-retrieve-all-the-opted-in-validators-on-a-consumer-chain",level:3},{value:"How to retrieve all the consumer validators on a consumer chain?",id:"how-to-retrieve-all-the-consumer-validators-on-a-consumer-chain",level:3},{value:"How can we see the commission rate a validator has set on a consumer chain?",id:"how-can-we-see-the-commission-rate-a-validator-has-set-on-a-consumer-chain",level:3}];function d(e){const i={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,o.a)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(i.h1,{id:"partial-set-security",children:"Partial Set Security"}),"\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.a,{href:"/interchain-security/features/partial-set-security",children:"Partial Set Security"})," allows consumer chains to join as Opt-In or Top N.\nHere, we show how a validator can opt in, opt out, or set a custom commission rate on a consumer chain, as well\nas useful queries that a validator can use to figure out which chains it has to validate, etc."]}),"\n",(0,t.jsx)(i.h2,{id:"messages",children:"Messages"}),"\n",(0,t.jsx)(i.h3,{id:"how-to-opt-in-to-a-consumer-chain",children:"How to opt in to a consumer chain?"}),"\n",(0,t.jsx)(i.admonition,{type:"warning",children:(0,t.jsx)(i.p,{children:"A validator is automatically opted in to a Top N chain if the validator belongs to the top N% of the validators on the provider chain."})}),"\n",(0,t.jsx)(i.p,{children:"In a Top N chain, a validator that does not belong to the top N% of the validators on the provider can still choose\nto opt in to a consumer chain. In other words, validators can opt in, in both Opt-In and Top N chains."}),"\n",(0,t.jsx)(i.p,{children:"A validator can opt in to a consumer chain by issuing the following message:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd tx provider opt-in <consumer-chain-id> <optional consumer-pub-key>\n"})}),"\n",(0,t.jsx)(i.p,{children:"where"}),"\n",(0,t.jsxs)(i.ul,{children:["\n",(0,t.jsxs)(i.li,{children:[(0,t.jsx)(i.code,{children:"consumer-chain-id"})," is the string identifier of the consumer chain the validator wants to opt in to;"]}),"\n",(0,t.jsxs)(i.li,{children:[(0,t.jsx)(i.code,{children:"consumer-pub-key"})," corresponds to the public key the validator wants to use on the consumer chain, and it has the\nfollowing format ",(0,t.jsx)(i.code,{children:'{"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}'}),"."]}),"\n"]}),"\n",(0,t.jsxs)(i.p,{children:["A validator can opt in to an existing consumer chain that is already running, or to a ",(0,t.jsx)(i.a,{href:"/interchain-security/features/proposals",children:"proposed"}),"\nconsumer chain that is still being voted on. A validator can use the following command to retrieve the currently existing\nconsumer chains:"]}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd query provider list-consumer-chains\n"})}),"\n",(0,t.jsx)(i.p,{children:"and this command to see the currently proposed consumer chains:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd query provider list-proposed-consumer-chains\n"})}),"\n",(0,t.jsx)(i.admonition,{type:"tip",children:(0,t.jsxs)(i.p,{children:["By setting the ",(0,t.jsx)(i.code,{children:"consumer-pub-key"}),", a validator can both opt in to a chain and assign a\npublic key on a consumer chain. Note that a validator can always ",(0,t.jsx)(i.a,{href:"/interchain-security/features/key-assignment",children:"assign"}),"\na new consumer key at a later stage. The key-assignment ",(0,t.jsx)(i.a,{href:"/interchain-security/features/key-assignment#rules",children:"rules"}),"\nstill apply when setting ",(0,t.jsx)(i.code,{children:"consumer-pub-key"})," when opting in."]})}),"\n",(0,t.jsx)(i.admonition,{type:"info",children:(0,t.jsx)(i.p,{children:"A validator is only eligible for consumer rewards from a consumer chain if the validator is opted into that chain."})}),"\n",(0,t.jsx)(i.h3,{id:"how-to-opt-out-from-a-consumer-chain",children:"How to opt out from a consumer chain?"}),"\n",(0,t.jsx)(i.p,{children:"A validator can opt out from a consumer by issuing the following message:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd tx provider opt-out <consumer-chain-id>\n"})}),"\n",(0,t.jsx)(i.p,{children:"where"}),"\n",(0,t.jsxs)(i.ul,{children:["\n",(0,t.jsxs)(i.li,{children:[(0,t.jsx)(i.code,{children:"consumer-chain-id"})," is the string identifier of the consumer chain."]}),"\n"]}),"\n",(0,t.jsx)(i.admonition,{type:"warning",children:(0,t.jsx)(i.p,{children:"A validator cannot opt out from a Top N chain if it belongs to the top N% validators of the provider."})}),"\n",(0,t.jsx)(i.admonition,{type:"warning",children:(0,t.jsxs)(i.p,{children:["If a validator moves from the Top N to outside of the top N% of the validators on the provider, it will ",(0,t.jsx)(i.strong,{children:"not"}),"\nbe automatically opted-out. The validator has to manually opt out."]})}),"\n",(0,t.jsx)(i.admonition,{type:"warning",children:(0,t.jsxs)(i.p,{children:["A validator can stop its node on a consumer chain ",(0,t.jsx)(i.strong,{children:"only"})," after opting out and confirming through the ",(0,t.jsx)(i.code,{children:"has-to-validate"}),"\nquery (see ",(0,t.jsx)(i.a,{href:"/interchain-security/validators/partial-set-security-for-validators#which-chains-does-a-validator-have-to-validate",children:"below"}),") that it does\nnot have to validate the consumer chain any longer."]})}),"\n",(0,t.jsx)(i.admonition,{type:"warning",children:(0,t.jsx)(i.p,{children:"If all validators opt out from an Opt-In chain, the chain will halt with a consensus failure upon receiving the VSCPacket with an empty validator set."})}),"\n",(0,t.jsx)(i.h3,{id:"how-to-set-specific-per-consumer-chain-commission-rate",children:"How to set specific per consumer chain commission rate?"}),"\n",(0,t.jsx)(i.p,{children:"A validator can choose to set a different commission rate on each of the consumer chains.\nThis can be done with the following command:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd tx provider set-consumer-commission-rate <consumer-chain-id> <commission-rate>\n"})}),"\n",(0,t.jsx)(i.p,{children:"where"}),"\n",(0,t.jsxs)(i.ul,{children:["\n",(0,t.jsxs)(i.li,{children:[(0,t.jsx)(i.code,{children:"consumer-chain-id"})," is the string identifier of the consumer chain;"]}),"\n",(0,t.jsxs)(i.li,{children:[(0,t.jsx)(i.code,{children:"comission-rate"})," decimal in ",(0,t.jsx)(i.code,{children:"[minRate, 1]"})," where ",(0,t.jsx)(i.code,{children:"minRate"})," corresponds to the minimum commission rate set on the\nprovider chain (see ",(0,t.jsx)(i.code,{children:"min_commission_rate"})," in ",(0,t.jsx)(i.code,{children:"interchain-security-pd query staking params"}),")."]}),"\n"]}),"\n",(0,t.jsx)(i.p,{children:"If a validator does not set a commission rate on a consumer chain, the commission rate defaults to their commission rate on the provider chain."}),"\n",(0,t.jsx)(i.admonition,{type:"tip",children:(0,t.jsx)(i.p,{children:"Validators can set their commission rate even for consumer chains that they are not currently opted in on, and the commission rate will be applied when they opt in. This is particularly useful for Top N chains, where validators might be opted in automatically,\nso validators can set the commission rate in advance."})}),"\n",(0,t.jsx)(i.admonition,{type:"tip",children:(0,t.jsxs)(i.p,{children:["If a validator opts out and then back in, this will ",(0,t.jsx)(i.em,{children:"not"})," reset their commission rate back to the default. Instead, their\nset commission rate still applies."]})}),"\n",(0,t.jsx)(i.h2,{id:"queries",children:"Queries"}),"\n",(0,t.jsx)(i.p,{children:"Partial Set Security introduces a number of queries to assist validators determine which consumer chains they have to\nvalidate, their commission rate per chain, etc."}),"\n",(0,t.jsx)(i.h3,{id:"which-chains-does-a-validator-have-to-validate",children:"Which chains does a validator have to validate?"}),"\n",(0,t.jsx)(i.p,{children:"Naturally, a validator is aware of the Opt-In chains it has to validate because in order to validate an Opt-In chain,\na validator has to manually opt in to the chain. This is not the case for Top N chains where a validator might be required\nto validate such a chain without explicitly opting in if it belongs to the top N% of the validators on the provider."}),"\n",(0,t.jsx)(i.p,{children:"We introduce the following query:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd query provider has-to-validate <provider-validator-address>\n"})}),"\n",(0,t.jsxs)(i.p,{children:["that can be used by validator with ",(0,t.jsx)(i.code,{children:"provider-validator-address"})," address to retrieve the list of chains that it has to validate."]}),"\n",(0,t.jsx)(i.admonition,{type:"tip",children:(0,t.jsxs)(i.p,{children:["As a validator, the list of chains returned by ",(0,t.jsx)(i.code,{children:"has-to-validate"})," is the list of chains you ",(0,t.jsx)(i.strong,{children:"should"})," be validating to avoid\ngetting jailed for downtime."]})}),"\n",(0,t.jsx)(i.h3,{id:"how-do-you-know-how-much-voting-power-you-need-to-have-to-be-in-the-top-n-for-a-chain",children:"How do you know how much voting power you need to have to be in the top N for a chain?"}),"\n",(0,t.jsxs)(i.p,{children:["This can be seen as part of the ",(0,t.jsx)(i.code,{children:"list-consumer-chains"})," query:"]}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd query provider list-consumer-chains\n"})}),"\n",(0,t.jsxs)(i.p,{children:["where the ",(0,t.jsx)(i.code,{children:"min_power_in_top_N"})," field shows the minimum voting power required to be\nautomatically opted in to the chain."]}),"\n",(0,t.jsx)(i.admonition,{type:"tip",children:(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.code,{children:"list-consumer-chains"})," shows the minimal voting power ",(0,t.jsx)(i.em,{children:"right now"}),", but\nthe automatic opt-in happens only when epochs end on the provider.\nIn consequence, a validators power might be large enough to be automatically opted in\nduring an epoch, but if their power is sufficiently decreased before the epoch ends,\nthey will not be opted in automatically."]})}),"\n",(0,t.jsx)(i.h3,{id:"how-to-retrieve-all-the-opted-in-validators-on-a-consumer-chain",children:"How to retrieve all the opted-in validators on a consumer chain?"}),"\n",(0,t.jsx)(i.p,{children:"With the following query:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd query provider consumer-opted-in-validators <consumer-chain-id>\n"})}),"\n",(0,t.jsxs)(i.p,{children:["we can see all the opted-in validators on ",(0,t.jsx)(i.code,{children:"consumer-chain-id"})," that were manually or automatically opted in."]}),"\n",(0,t.jsx)(i.h3,{id:"how-to-retrieve-all-the-consumer-validators-on-a-consumer-chain",children:"How to retrieve all the consumer validators on a consumer chain?"}),"\n",(0,t.jsx)(i.p,{children:"With the following query:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd query provider consumer-validators <consumer-chain-id>\n"})}),"\n",(0,t.jsxs)(i.p,{children:["we can see all the ",(0,t.jsx)(i.em,{children:"consumer validators"})," (i.e., validator set) of ",(0,t.jsx)(i.code,{children:"consumer-chain-id"}),". The consumer validators are the\nones that are currently (or in the future, see warning) validating the consumer chain. A ",(0,t.jsx)(i.em,{children:"consumer validator"})," is an opted-in\nvalidator but not vice versa. For example, an opted-in validator ",(0,t.jsx)(i.code,{children:"V"})," might not be a consumer validator because ",(0,t.jsx)(i.code,{children:"V"})," is\ndenylisted or because ",(0,t.jsx)(i.code,{children:"V"})," is removed due to a validator-set cap."]}),"\n",(0,t.jsx)(i.admonition,{type:"warning",children:(0,t.jsxs)(i.p,{children:["The returned consumer validators from this query do not necessarily correspond to the validator set that is\nvalidating the consumer chain at this exact moment. This is because the ",(0,t.jsx)(i.code,{children:"VSCPacket"})," sent to a consumer chain might be\ndelayed and hence this query might return the validator set that the consumer chain would have at some future\npoint in time."]})}),"\n",(0,t.jsx)(i.h3,{id:"how-can-we-see-the-commission-rate-a-validator-has-set-on-a-consumer-chain",children:"How can we see the commission rate a validator has set on a consumer chain?"}),"\n",(0,t.jsx)(i.p,{children:"Using the following query:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd query provider validator-consumer-commission-rate <consumer-chain-id> <provider-validator-address>\n"})}),"\n",(0,t.jsxs)(i.p,{children:["we retrieve the commission rate set by validator with ",(0,t.jsx)(i.code,{children:"provider-validator-address"})," address on ",(0,t.jsx)(i.code,{children:"consumer-chain-id"}),"."]})]})}function l(e={}){const{wrapper:i}={...(0,o.a)(),...e.components};return i?(0,t.jsx)(i,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},1151:(e,i,n)=>{n.d(i,{Z:()=>r,a:()=>s});var t=n(7294);const o={},a=t.createContext(o);function s(e){const i=t.useContext(a);return t.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function r(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),t.createElement(a.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/70938a03.0a87b3b7.js b/assets/js/70938a03.0a87b3b7.js new file mode 100644 index 0000000000..f41a3a17f4 --- /dev/null +++ b/assets/js/70938a03.0a87b3b7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5457],{5610:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>a,metadata:()=>r,toc:()=>d});var t=i(5893),s=i(1151);const a={sidebar_position:5},o="Changeover Procedure",r={id:"consumer-development/changeover-procedure",title:"Changeover Procedure",description:"Chains that were not initially launched as consumers of Interchain Security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.",source:"@site/docs/consumer-development/changeover-procedure.md",sourceDirName:"consumer-development",slug:"/consumer-development/changeover-procedure",permalink:"/interchain-security/consumer-development/changeover-procedure",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Offboarding Checklist",permalink:"/interchain-security/consumer-development/offboarding"},next:{title:"Consumer Genesis Transformation",permalink:"/interchain-security/consumer-development/consumer-genesis-transformation"}},c={},d=[{value:"Overview",id:"overview",level:2},{value:"1. ConsumerAddition proposal submitted to the <code>provider</code> chain",id:"1-consumeraddition-proposal-submitted-to-the-provider-chain",level:3},{value:"2. upgrade proposal on standalone chain",id:"2-upgrade-proposal-on-standalone-chain",level:3},{value:"3. spawn time is reached",id:"3-spawn-time-is-reached",level:3},{value:"4. standalone chain upgrade",id:"4-standalone-chain-upgrade",level:3},{value:"Notes",id:"notes",level:4},{value:"Onboarding Checklist",id:"onboarding-checklist",level:2},{value:"1. Complete testing & integration",id:"1-complete-testing--integration",level:2},{value:"2. Create an Onboarding Repository",id:"2-create-an-onboarding-repository",level:2},{value:"3. Submit a ConsumerChainAddition Governance Proposal to the provider",id:"3-submit-a-consumerchainaddition-governance-proposal-to-the-provider",level:2},{value:"3. Submit an Upgrade Proposal & Prepare for Changeover",id:"3-submit-an-upgrade-proposal--prepare-for-changeover",level:2},{value:"4. Upgrade time \ud83d\ude80",id:"4-upgrade-time-",level:2}];function h(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",input:"input",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.a)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"changeover-procedure",children:"Changeover Procedure"}),"\n",(0,t.jsxs)(n.p,{children:["Chains that were ",(0,t.jsx)(n.strong,{children:"not"})," initially launched as consumers of Interchain Security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the ",(0,t.jsx)(n.strong,{children:"changeover procedure"})," and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain."]}),"\n",(0,t.jsx)(n.p,{children:"The relevant protocol specifications are available below:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md#channel-initialization-existing-chains",children:"ICS-28 with existing chains"}),"."]}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"/interchain-security/adrs/adr-010-standalone-changeover",children:"ADR in ICS repo"})}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"overview",children:"Overview"}),"\n",(0,t.jsx)(n.p,{children:"Standalone to consumer changeover procedure can roughly be separated into 4 parts:"}),"\n",(0,t.jsxs)(n.h3,{id:"1-consumeraddition-proposal-submitted-to-the-provider-chain",children:["1. ConsumerAddition proposal submitted to the ",(0,t.jsx)(n.code,{children:"provider"})," chain"]}),"\n",(0,t.jsx)(n.p,{children:'The proposal is equivalent to the "normal" ConsumerAddition proposal submitted by new consumer chains.'}),"\n",(0,t.jsx)(n.p,{children:"However, here are the most important notes and differences between a new consumer chain and a standalone chain performing a changeover:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"chain_id"})," must be equal to the standalone chain id"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"initial_height"})," field has additional rules to abide by:"]}),"\n"]}),"\n",(0,t.jsxs)(n.admonition,{type:"caution",children:[(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:'{\n...\n "initial_height" : {\n // must correspond to current revision number of standalone chain\n // e.g. stride-1 => "revision_number": 1\n "revision_number": 1,\n\n // must correspond to a height that is at least 1 block after the upgrade\n // that will add the `consumer` module to the standalone chain\n // e.g. "upgrade_height": 100 => "revision_height": 101\n "revision_height": 1,\n },\n...\n}\n'})}),(0,t.jsx)(n.p,{children:"RevisionNumber: 0, RevisionHeight: 111"})]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"genesis_hash"})," can be safely ignored because the chain is already running. A hash of the standalone chain's initial genesis may be used"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"binary_hash"})," may not be available ahead of time. All chains performing the changeover go through rigorous testing - if bugs are caught and fixed the hash listed in the proposal may not be the most recent one."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"spawn_time"})," listed in the proposal MUST be before the ",(0,t.jsx)(n.code,{children:"upgrade_height"})," listed in the upgrade proposal on the standalone chain."]}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.admonition,{type:"caution",children:(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"spawn_time"})," must occur before the ",(0,t.jsx)(n.code,{children:"upgrade_height"})," on the standalone chain is reached because the ",(0,t.jsx)(n.code,{children:"provider"})," chain must generate the ",(0,t.jsx)(n.code,{children:"ConsumerGenesis"})," that contains the ",(0,t.jsx)(n.strong,{children:"validator set"})," that will be used after the changeover."]})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"unbonding_period"})," must correspond to the value used on the standalone chain. Otherwise, the clients used for the ccv protocol may be incorrectly initialized."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"distribution_transmission_channel"})," ",(0,t.jsx)(n.strong,{children:"should be set"}),"."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.admonition,{type:"note",children:[(0,t.jsxs)(n.p,{children:["Populating ",(0,t.jsx)(n.code,{children:"distribution_transmission_channel"})," will enable the standalone chain to reuse one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ",(0,t.jsx)(n.code,{children:"ibc denom"})," that may already be in use."]}),(0,t.jsx)(n.p,{children:"If the parameter is not set, a new channel will be created."})]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"ccv_timeout_period"})," has no important notes"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"transfer_timeout_period"})," has no important notes"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"consumer_redistribution_fraction"})," has no important notes"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"blocks_per_distribution_transmission"})," has no important notes"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"historical_entries"})," has no important notes"]}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"2-upgrade-proposal-on-standalone-chain",children:"2. upgrade proposal on standalone chain"}),"\n",(0,t.jsxs)(n.p,{children:["The standalone chain creates an upgrade proposal to include the ",(0,t.jsx)(n.code,{children:"interchain-security/x/ccv/consumer"})," module."]}),"\n",(0,t.jsx)(n.admonition,{type:"caution",children:(0,t.jsxs)(n.p,{children:["The upgrade height in the proposal should correspond to a height that is after the ",(0,t.jsx)(n.code,{children:"spawn_time"})," in the consumer addition proposal submitted to the ",(0,t.jsx)(n.code,{children:"provider"})," chain."]})}),"\n",(0,t.jsx)(n.p,{children:"Otherwise, the upgrade is indistinguishable from a regular on-chain upgrade proposal."}),"\n",(0,t.jsx)(n.h3,{id:"3-spawn-time-is-reached",children:"3. spawn time is reached"}),"\n",(0,t.jsxs)(n.p,{children:["When the ",(0,t.jsx)(n.code,{children:"spawn_time"})," is reached on the ",(0,t.jsx)(n.code,{children:"provider"})," it will generate a ",(0,t.jsx)(n.code,{children:"ConsumerGenesis"})," that contains the validator set that will supersede the ",(0,t.jsx)(n.code,{children:"standalone"})," validator set."]}),"\n",(0,t.jsxs)(n.p,{children:["This ",(0,t.jsx)(n.code,{children:"ConsumerGenesis"})," must be available on the standalone chain during the on-chain upgrade."]}),"\n",(0,t.jsx)(n.h3,{id:"4-standalone-chain-upgrade",children:"4. standalone chain upgrade"}),"\n",(0,t.jsxs)(n.p,{children:["Performing the on-chain upgrade on the standalone chain will add the ",(0,t.jsx)(n.code,{children:"ccv/consumer"})," module and allow the chain to become a ",(0,t.jsx)(n.code,{children:"consumer"})," of Interchain Security."]}),"\n",(0,t.jsxs)(n.admonition,{type:"caution",children:[(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"ConsumerGenesis"})," must be exported to a file and placed in the correct folder on the standalone chain before the upgrade."]}),(0,t.jsx)(n.p,{children:"The file must be placed at the exact specified location, otherwise the upgrade will not be executed correctly."}),(0,t.jsxs)(n.p,{children:["Usually the file is placed in ",(0,t.jsx)(n.code,{children:"$NODE_HOME/config"}),", but the file name and the exact directory is dictated by the upgrade code on the ",(0,t.jsx)(n.code,{children:"standalone"})," chain."]}),(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["please check exact instructions provided by the ",(0,t.jsx)(n.code,{children:"standalone"})," chain team"]}),"\n"]})]}),"\n",(0,t.jsxs)(n.p,{children:["After the ",(0,t.jsx)(n.code,{children:"genesis.json"})," file has been made available, the process is equivalent to a normal on-chain upgrade. The standalone validator set will sign the next couple of blocks before transferring control to ",(0,t.jsx)(n.code,{children:"provider"})," validator set."]}),"\n",(0,t.jsxs)(n.p,{children:["The standalone validator set can still be slashed for any infractions if evidence is submitted within the ",(0,t.jsx)(n.code,{children:"unboding_period"}),"."]}),"\n",(0,t.jsx)(n.h4,{id:"notes",children:"Notes"}),"\n",(0,t.jsx)(n.p,{children:"The changeover procedure may be updated in the future to create a seamless way of providing the validator set information to the standalone chain."}),"\n",(0,t.jsx)(n.h2,{id:"onboarding-checklist",children:"Onboarding Checklist"}),"\n",(0,t.jsxs)(n.p,{children:["This onboarding checklist is slightly different from the one under ",(0,t.jsx)(n.a,{href:"/interchain-security/consumer-development/onboarding",children:"Onboarding"})]}),"\n",(0,t.jsxs)(n.p,{children:["Additionally, you can check the ",(0,t.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/CONSUMER_LAUNCH_GUIDE.md",children:"testnet repo"})," for a comprehensive guide on preparing and launching consumer chains."]}),"\n",(0,t.jsx)(n.h2,{id:"1-complete-testing--integration",children:"1. Complete testing & integration"}),"\n",(0,t.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","test integration with gaia"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","test your protocol with supported relayer versions (minimum hermes 1.4.1)"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","test the changeover procedure"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","reach out to the ICS team if you are facing issues"]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"2-create-an-onboarding-repository",children:"2. Create an Onboarding Repository"}),"\n",(0,t.jsx)(n.p,{children:"To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain."}),"\n",(0,t.jsx)(n.p,{children:"This should include (at minimum):"}),"\n",(0,t.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see ",(0,t.jsx)(n.a,{href:"/interchain-security/consumer-development/consumer-genesis-transformation",children:"Transform Consumer Genesis"}),")"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","information about relevant seed/peer nodes you are running"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","relayer information (compatible versions)"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","copy of your governance proposal (as JSON)"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","a script showing how to start your chain and connect to peers (optional)"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable"]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["Example of such a repository can be found ",(0,t.jsx)(n.a,{href:"https://github.com/hyphacoop/ics-testnets/tree/main/game-of-chains-2022/sputnik",children:"here"}),"."]}),"\n",(0,t.jsx)(n.h2,{id:"3-submit-a-consumerchainaddition-governance-proposal-to-the-provider",children:"3. Submit a ConsumerChainAddition Governance Proposal to the provider"}),"\n",(0,t.jsxs)(n.p,{children:["Before you submit a ",(0,t.jsx)(n.code,{children:"ConsumerChainAddition"})," proposal, please provide a ",(0,t.jsx)(n.code,{children:"spawn_time"})," that is ",(0,t.jsx)(n.strong,{children:"before"})," the ",(0,t.jsx)(n.code,{children:"upgrade_height"})," of the upgrade that will introduce the ",(0,t.jsx)(n.code,{children:"ccv module"})," to your chain."]}),"\n",(0,t.jsx)(n.admonition,{type:"danger",children:(0,t.jsxs)(n.p,{children:["If the ",(0,t.jsx)(n.code,{children:"spawn_time"})," happens after your ",(0,t.jsx)(n.code,{children:"upgrade_height"})," the provider will not be able to communicate the new validator set to be used after the changeover."]})}),"\n",(0,t.jsxs)(n.p,{children:["Additionally, reach out to the community via the ",(0,t.jsx)(n.a,{href:"https://forum.cosmos.network/",children:"forum"})," to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers."]}),"\n",(0,t.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","determine your chain's spawn time"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","determine consumer chain parameters to be put in the proposal"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","take note to include a link to your onboarding repository"]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["Example of a consumer chain addition proposal (compare with the ",(0,t.jsx)(n.a,{href:"/interchain-security/consumer-development/onboarding#3-submit-a-governance-proposal",children:"ConsumerAdditionProposal"})," in the ICS Provider Proposals section for chains that ",(0,t.jsx)(n.em,{children:"launch"})," as consumers):"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:'// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain or add a standalone chain.\n// If it passes, then a subset (i.e., depends on `top_N` and on the power shaping parameters) of validators on the provider chain are expected\n// to validate the consumer chain at spawn time. It is recommended that spawn time occurs after the proposal end time and that it is \n// scheduled to happen before the standalone chain upgrade that sill introduce the ccv module.\n{\n // Title of the proposal\n "title": "Changeover Standalone chain",\n // Description of the proposal\n // format the text as a .md file and include the file in your onboarding repository\n "description": ".md description of your chain and all other relevant information",\n // Proposed chain-id of the new consumer chain.\n // Must be unique from all other consumer chain ids of the executing provider chain.\n "chain_id": "standalone-1",\n // Initial height of new consumer chain.\n "initial_height" : {\n // must correspond to current revision number of standalone chain\n // e.g. standalone-1 => "revision_number": 1\n "revision_number": 1,\n\n // must correspond to a height that is at least 1 block after the upgrade\n // that will add the `consumer` module to the standalone chain\n // e.g. "upgrade_height": 100 => "revision_height": 101\n "revision_number": 1,\n },\n // Hash of the consumer chain genesis state without the consumer CCV module genesis params.\n // => not relevant for changeover procedure\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n // Hash of the consumer chain binary that should be run by validators on standalone chain upgrade\n // => not relevant for changeover procedure as it may become stale\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n // Unbonding period for the consumer chain.\n // It should should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n // IBC transfer packets will timeout after this interval elapses.\n "transfer_timeout_period": 1800000000000,\n // The fraction of tokens allocated to the consumer redistribution address during distribution events.\n // The fraction is a string representing a decimal number. For example "0.75" would represent 75%.\n // The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.\n "consumer_redistribution_fraction": "0.75",\n // BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.\n // eg. send rewards to the provider every 1000 blocks\n "blocks_per_distribution_transmission": 1000,\n // The number of historical info entries to persist in store.\n // This param is a part of the cosmos sdk staking module. In the case of\n // a ccv enabled consumer chain, the ccv module acts as the staking module.\n "historical_entries": 10000,\n // The ID of a token transfer channel used for the Reward Distribution\n\t// sub-protocol. If DistributionTransmissionChannel == "", a new transfer\n\t// channel is created on top of the same connection as the CCV channel.\n\t// Note that transfer_channel_id is the ID of the channel end on the consumer chain.\n // it is most relevant for chains performing a standalone to consumer changeover\n // in order to maintain the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123" // NOTE: use existing transfer channel if available\n // Corresponds to the percentage of validators that have to validate the chain under the Top N case.\n // For example, 53 corresponds to a Top 53% chain, meaning that the top 53% provider validators by voting power\n // have to validate the proposed consumer chain. top_N can either be 0 or any value in [50, 100].\n // A chain can join with top_N == 0 as an Opt In chain, or with top_N \u2208 [50, 100] as a Top N chain.\n "top_N": 95,\n // Corresponds to the maximum power (percentage-wise) a validator can have on the consumer chain. For instance, if\n // `validators_power_cap` is set to 32, it means that no validator can have more than 32% of the voting power on the\n // consumer chain. Note that this might not be feasible. For example, think of a consumer chain with only\n // 5 validators and with `validators_power_cap` set to 10%. In such a scenario, at least one validator would need\n // to have more than 20% of the total voting power. Therefore, `validators_power_cap` operates on a best-effort basis.\n "validators_power_cap": 0,\n // Corresponds to the maximum number of validators that can validate a consumer chain.\n // Only applicable to Opt In chains. Setting `validator_set_cap` on a Top N chain is a no-op.\n "validator_set_cap": 0,\n // Corresponds to a list of provider consensus addresses of validators that are the ONLY ones that can validate\n // the consumer chain.\n "allowlist": [],\n // Corresponds to a list of provider consensus addresses of validators that CANNOT validate the consumer chain.\n "denylist": []\n}\n'})}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsxs)(n.p,{children:["As seen in the ",(0,t.jsx)(n.code,{children:"ConsumerAdditionProposal"})," example above, the changeover procedure can be used together with ",(0,t.jsx)(n.a,{href:"/interchain-security/adrs/adr-015-partial-set-security",children:"Partial Set Security"}),".\nThis means, that a standalone chain can choose to only be validated by some of the validators of the provider chain by setting ",(0,t.jsx)(n.code,{children:"top_N"})," appropriately, or by\nadditionally setting a validators-power cap, validator-set cap, etc. by using the ",(0,t.jsx)(n.a,{href:"/interchain-security/features/power-shaping",children:"power-shaping parameters"}),"."]})}),"\n",(0,t.jsx)(n.h2,{id:"3-submit-an-upgrade-proposal--prepare-for-changeover",children:"3. Submit an Upgrade Proposal & Prepare for Changeover"}),"\n",(0,t.jsxs)(n.p,{children:["This proposal should add the ccv ",(0,t.jsx)(n.code,{children:"consumer"})," module to your chain."]}),"\n",(0,t.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","proposal ",(0,t.jsx)(n.code,{children:"upgrade_height"})," must happen after ",(0,t.jsx)(n.code,{children:"spawn_time"})," in the ",(0,t.jsx)(n.code,{children:"ConsumerAdditionProposal"})]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","advise validators about the exact procedure for your chain and point them to your onboarding repository"]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"4-upgrade-time-",children:"4. Upgrade time \ud83d\ude80"}),"\n",(0,t.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","after ",(0,t.jsx)(n.code,{children:"spawn_time"}),", request ",(0,t.jsx)(n.code,{children:"ConsumerGenesis"})," from the ",(0,t.jsx)(n.code,{children:"provider"})," and place it in ",(0,t.jsx)(n.code,{children:"<CURRENT_USER_HOME_DIR>/.sovereign/config/genesis.json"})]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","upgrade the binary to the one listed in your ",(0,t.jsx)(n.code,{children:"UpgradeProposal"})]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:['The chain starts after at least 66.67% of standalone voting power comes online. The consumer chain is considered interchain secured once the "old" validator set signs a couple of blocks and transfers control to the ',(0,t.jsx)(n.code,{children:"provider"})," validator set."]}),"\n",(0,t.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","provide a repo with onboarding instructions for validators (it should already be listed in the proposal)"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","genesis.json after ",(0,t.jsx)(n.code,{children:"spawn_time"})," obtained from ",(0,t.jsx)(n.code,{children:"provider"})," (MUST contain the initial validator set)"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)"]}),"\n"]})]})}function l(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(h,{...e})}):h(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>r,a:()=>o});var t=i(7294);const s={},a=t.createContext(s);function o(e){const n=t.useContext(a);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),t.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/72e9af3b.840537aa.js b/assets/js/72e9af3b.840537aa.js new file mode 100644 index 0000000000..167031113e --- /dev/null +++ b/assets/js/72e9af3b.840537aa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[903],{8161:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>s,metadata:()=>r,toc:()=>d});var n=o(5893),i=o(1151);const s={sidebar_position:10,title:"Soft Opt-Out"},a=void 0,r={id:"adrs/adr-009-soft-opt-out",title:"Soft Opt-Out",description:"ADR 009: Soft Opt-Out",source:"@site/versioned_docs/version-v5.0.0/adrs/adr-009-soft-opt-out.md",sourceDirName:"adrs",slug:"/adrs/adr-009-soft-opt-out",permalink:"/interchain-security/v5.0.0/adrs/adr-009-soft-opt-out",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:10,frontMatter:{sidebar_position:10,title:"Soft Opt-Out"},sidebar:"tutorialSidebar",previous:{title:"Throttle with retries",permalink:"/interchain-security/v5.0.0/adrs/adr-008-throttle-retries"},next:{title:"Standalone to Consumer Changeover",permalink:"/interchain-security/v5.0.0/adrs/adr-010-standalone-changeover"}},l={},d=[{value:"ADR 009: Soft Opt-Out",id:"adr-009-soft-opt-out",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function c(e){const t={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,i.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h2,{id:"adr-009-soft-opt-out",children:"ADR 009: Soft Opt-Out"}),"\n",(0,n.jsx)(t.h2,{id:"changelog",children:"Changelog"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"6/13/23: Initial draft of ADR. Feature already implemented and in production."}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"status",children:"Status"}),"\n",(0,n.jsx)(t.p,{children:"Accepted"}),"\n",(0,n.jsx)(t.h2,{id:"context",children:"Context"}),"\n",(0,n.jsxs)(t.p,{children:["Some small validators may not have the resources needed to validate all consumer chains. Therefore a need exists to allow the bottom ",(0,n.jsx)(t.code,{children:"x%"})," of validators to opt-out of validating a consumer chain. Meaning downtime infractions for these validators are dropped without ever reaching the provider."]}),"\n",(0,n.jsx)(t.p,{children:"This document specifies a modification to the ccv protocol which allows the bottom x% of the validator set by power to opt out of validating consumer chains without being jailed or otherwise punished for it. The feature is implemented with entirely consumer-side code."}),"\n",(0,n.jsx)(t.h2,{id:"decision",children:"Decision"}),"\n",(0,n.jsxs)(t.p,{children:["A consumer param exists, known as ",(0,n.jsx)(t.code,{children:"SoftOptOutThreshold"}),", which is a string decimal in the range of [0, 0.2], that determines the portion of validators which are allowed to opt out of validating that specific consumer."]}),"\n",(0,n.jsxs)(t.p,{children:["In every consumer beginblocker, a function is ran which determines the so called ",(0,n.jsx)(t.em,{children:"smallest non opt-out voting power"}),". Validators with voting power greater than or equal to this value must validate the consumer chain, while validators below this value may opt out of validating the consumer chain."]}),"\n",(0,n.jsxs)(t.p,{children:["The smallest non opt-out voting power is recomputed every beginblocker in ",(0,n.jsx)(t.code,{children:"UpdateSmallestNonOptOutPower()"}),". In a nutshell, the method obtains the total voting power of the consumer, iterates through the full valset (ordered power ascending) keeping track of a power sum, and when ",(0,n.jsx)(t.code,{children:"powerSum / totalPower > SoftOptOutThreshold"}),", the ",(0,n.jsx)(t.code,{children:"SmallestNonOptOutPower"})," is found and persisted."]}),"\n",(0,n.jsxs)(t.p,{children:["Then, whenever the ",(0,n.jsx)(t.code,{children:"Slash()"})," interface is executed on the consumer, if the voting power of the relevant validator being slashed is less than ",(0,n.jsx)(t.code,{children:"SmallestNonOptOutPower"})," for that block, the slash request is dropped and never sent to the provider."]}),"\n",(0,n.jsx)(t.h2,{id:"consequences",children:"Consequences"}),"\n",(0,n.jsx)(t.h3,{id:"positive",children:"Positive"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"Small validators can opt out of validating specific consumers without being punished for it."}),"\n"]}),"\n",(0,n.jsx)(t.h3,{id:"negative",children:"Negative"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["The bottom ",(0,n.jsx)(t.code,{children:"x%"})," is still part of the total voting power of the consumer chain. This means that if the soft opt-out threshold is set to ",(0,n.jsx)(t.code,{children:"10%"})," for example, and every validator in the bottom ",(0,n.jsx)(t.code,{children:"10%"})," opts out from validating the consumer, then a ",(0,n.jsx)(t.code,{children:"24%"})," downtime of the remaining voting power would halt the chain. This may be especially problematic during consumer upgrades."]}),"\n",(0,n.jsxs)(t.li,{children:["In nominal scenarios, consumers with soft opt out enabled will be constructing slash packets for small vals, which may be dropped. This is wasted computation, but necessary to keep implementation simple. Note that the sdk's ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/d3f09c222243bb3da3464969f0366330dcb977a8/x/slashing/keeper/infractions.go#L75",children:"full downtime logic"})," is always executed on the consumer, which can be computationally expensive and slow down certain blocks."]}),"\n",(0,n.jsx)(t.li,{children:"In a consumer chain, when a validator that has opted out becomes the proposer, there will naturally be no proposal made and validators would need to move to the next consensus round for the same height to reach a decision. As a result, we would need more time to finalize blocks on a consumer chain."}),"\n"]}),"\n",(0,n.jsx)(t.h3,{id:"neutral",children:"Neutral"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"Validators in the bottom of the valset who don't have to validate, may receive large delegation(s) which suddenly boost the validator to the subset that has to validate. This may catch the validator off guard."}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"references",children:"References"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["Original issue with some napkin math ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/issues/784",children:"#784"})]}),"\n"]})]})}function h(e={}){const{wrapper:t}={...(0,i.a)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(c,{...e})}):c(e)}},1151:(e,t,o)=>{o.d(t,{Z:()=>r,a:()=>a});var n=o(7294);const i={},s=n.createContext(i);function a(e){const t=n.useContext(s);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),n.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/7380b9fa.932b3293.js b/assets/js/7380b9fa.932b3293.js new file mode 100644 index 0000000000..d78624d70a --- /dev/null +++ b/assets/js/7380b9fa.932b3293.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1877],{6263:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>t,metadata:()=>r,toc:()=>d});var o=i(5893),s=i(1151);const t={sidebar_position:4,title:"Equivocation governance proposal"},a="ADR 003: Equivocation governance proposal",r={id:"adrs/adr-003-equivocation-gov-proposal",title:"Equivocation governance proposal",description:"Changelog",source:"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-003-equivocation-gov-proposal.md",sourceDirName:"adrs",slug:"/adrs/adr-003-equivocation-gov-proposal",permalink:"/interchain-security/v4.2.0/adrs/adr-003-equivocation-gov-proposal",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Equivocation governance proposal"},sidebar:"tutorialSidebar",previous:{title:"Jail Throttling",permalink:"/interchain-security/v4.2.0/adrs/adr-002-throttle"},next:{title:"Cryptographic verification of equivocation evidence",permalink:"/interchain-security/v4.2.0/adrs/adr-005-cryptographic-equivocation-verification"}},c={},d=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function l(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"adr-003-equivocation-governance-proposal",children:"ADR 003: Equivocation governance proposal"}),"\n",(0,o.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"2023-02-06: Initial draft"}),"\n",(0,o.jsx)(n.li,{children:"2023-11-30: Change status to deprecated"}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,o.jsx)(n.p,{children:"Deprecated"}),"\n",(0,o.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.strong,{children:"Note:"})," ADR deprecated as the equivocation proposal was removed by the\ncryptographic verification of equivocation feature\n(see ",(0,o.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-005-cryptographic-equivocation-verification",children:"ADR-005"})," and\n",(0,o.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-013-equivocation-slashing",children:"ADR-013"}),")."]}),"\n",(0,o.jsx)(n.p,{children:"We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain."}),"\n",(0,o.jsx)(n.p,{children:"For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence."}),"\n",(0,o.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,o.jsx)(n.p,{children:"To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain."}),"\n",(0,o.jsxs)(n.p,{children:["A new kind of governance proposal is added to the ",(0,o.jsx)(n.code,{children:"provider"})," module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain."]}),"\n",(0,o.jsxs)(n.p,{children:["If such proposal passes, the proposal handler delegates to the ",(0,o.jsx)(n.code,{children:"evidence"})," module to process the equivocation. This module ensures the evidence isn\u2019t too old, or else ignores it (see ",(0,o.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/21021b837882d1d40f1d79bcbc4fad2e79a3fefe/x/evidence/keeper/infraction.go#L54-L62",children:"code"}),"). ",(0,o.jsx)(n.em,{children:"Too old"})," is determined by 2 consensus params :"]}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"evidence.max_age_duration"})," number of nanoseconds before an evidence is considered too old"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"evidence.max_age_numblocks"})," number of blocks before an evidence is considered too old."]}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:"On the hub, those parameters are equals to"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-json",children:'// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682\n(...)\n"evidence": {\n\t"max_age_num_blocks": "1000000",\n\t"max_age_duration": "172800000000000",\n (...)\n},\n(...)\n'})}),"\n",(0,o.jsxs)(n.p,{children:["A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the ",(0,o.jsx)(n.code,{children:"evidence"})," module when the proposal passes and is handled by the hub."]}),"\n",(0,o.jsxs)(n.p,{children:["For ",(0,o.jsx)(n.code,{children:"max_age_num_blocks=1M"}),", the parameter is big enough if we consider the hub produces 12k blocks per day (",(0,o.jsx)(n.code,{children:"blocks_per_year/365 = 436,0000/365"}),"). The evidence can be up to 83 days old (",(0,o.jsx)(n.code,{children:"1,000,000/12,000"}),") and not be ignored."]}),"\n",(0,o.jsxs)(n.p,{children:["For ",(0,o.jsx)(n.code,{children:"max_age_duration=172,800,000,000,000"}),", the parameter is too low, because the value is in nanoseconds so it\u2019s 2 days. Fortunately the condition that checks those 2 parameters uses a ",(0,o.jsx)(n.strong,{children:"AND"}),", so if ",(0,o.jsx)(n.code,{children:"max_age_num_blocks"})," condition passes, the evidence won\u2019t be ignored."]}),"\n",(0,o.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,o.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Remove the possibility from a malicious consumer chain to \u201cattack\u201d the provider chain by slashing/jailing validators."}),"\n",(0,o.jsx)(n.li,{children:"Provide a more acceptable implementation for the validator community."}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Punishment action of double-signing isn\u2019t \u201cautomated\u201d, a governance proposal is required which takes more time."}),"\n",(0,o.jsx)(n.li,{children:"You need to pay 250ATOM to submit an equivocation evidence."}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,o.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:["PR that ignores non downtime slash packet : ",(0,o.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/692",children:"https://github.com/cosmos/interchain-security/pull/692"})]}),"\n",(0,o.jsxs)(n.li,{children:["PR that adds the governance slash proposal: ",(0,o.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/703",children:"https://github.com/cosmos/interchain-security/pull/703"})]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>r,a:()=>a});var o=i(7294);const s={},t=o.createContext(s);function a(e){const n=o.useContext(t);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),o.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/758625d4.17c5d74a.js b/assets/js/758625d4.17c5d74a.js new file mode 100644 index 0000000000..de663e7cc9 --- /dev/null +++ b/assets/js/758625d4.17c5d74a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[321],{5477:(e,r,n)=>{n.r(r),n.d(r,{assets:()=>o,contentTitle:()=>t,default:()=>h,frontMatter:()=>s,metadata:()=>d,toc:()=>c});var a=n(5893),i=n(1151);const s={sidebar_position:3},t="Consumer chain validator rewards",d={id:"validators/withdraw_rewards",title:"Consumer chain validator rewards",description:"A validator can only receive rewards from a consumer chain if the validator has been validating the consumer chain",source:"@site/docs/validators/withdraw_rewards.md",sourceDirName:"validators",slug:"/validators/withdraw_rewards",permalink:"/interchain-security/validators/withdraw_rewards",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Joining Interchain Security testnet",permalink:"/interchain-security/validators/joining-testnet"},next:{title:"Validator Instructions for Changeover Procedure",permalink:"/interchain-security/validators/changeover-procedure"}},o={},c=[{value:"Withdrawing rewards",id:"withdrawing-rewards",level:2},{value:"Querying validator rewards",id:"querying-validator-rewards",level:2},{value:"Withdrawing rewards and commission",id:"withdrawing-rewards-and-commission",level:2},{value:"1. Withdraw rewards",id:"1-withdraw-rewards",level:3},{value:"2. Confirm withdrawal",id:"2-confirm-withdrawal",level:3}];function l(e){const r={admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,i.a)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(r.h1,{id:"consumer-chain-validator-rewards",children:"Consumer chain validator rewards"}),"\n",(0,a.jsx)(r.admonition,{type:"warning",children:(0,a.jsxs)(r.p,{children:["A validator can only receive rewards from a consumer chain if the validator has been validating the consumer chain\nfor some time. Specifically, the validator has to be a consumer validator of the consumer chain for at least\n",(0,a.jsx)(r.code,{children:"NumberOfEpochsToStartReceivingRewards * BlocksPerEpoch"})," blocks (run ",(0,a.jsx)(r.code,{children:"interchain-security-pd query provider params"})," for\nthe actual values of the ",(0,a.jsx)(r.code,{children:"NumberOfEpochsToStartReceivingRewards"})," and ",(0,a.jsx)(r.code,{children:"BlocksPerEpoch"})," params)."]})}),"\n",(0,a.jsx)(r.h2,{id:"withdrawing-rewards",children:"Withdrawing rewards"}),"\n",(0,a.jsx)(r.p,{children:"Here are example steps for withdrawing rewards from consumer chains in the provider chain"}),"\n",(0,a.jsxs)(r.admonition,{type:"info",children:[(0,a.jsxs)(r.p,{children:["The examples used are from ",(0,a.jsx)(r.code,{children:"rs-testnet"}),", the Interchain Security persistent testnet."]}),(0,a.jsxs)(r.p,{children:["Validator operator address: ",(0,a.jsx)(r.code,{children:"cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6"}),"\nSelf-delegation address: ",(0,a.jsx)(r.code,{children:"cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf"})]})]}),"\n",(0,a.jsx)(r.p,{children:"Prior to withdrawing rewards, query balances for self-delegation address:"}),"\n",(0,a.jsx)(r.pre,{children:(0,a.jsx)(r.code,{className:"language-bash",children:'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "1000000000000"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n'})}),"\n",(0,a.jsx)(r.h2,{id:"querying-validator-rewards",children:"Querying validator rewards"}),"\n",(0,a.jsx)(r.p,{children:"Query rewards for the validator address:"}),"\n",(0,a.jsx)(r.pre,{children:(0,a.jsx)(r.code,{className:"language-bash",children:'gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6\n\nrewards:\n- amount: "158.069895000000000000"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "841842390516.072526500000000000"\n denom: uatom\n'})}),"\n",(0,a.jsxs)(r.p,{children:["The ",(0,a.jsx)(r.code,{children:"ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD"})," denom represents rewards from a consumer chain."]}),"\n",(0,a.jsx)(r.h2,{id:"withdrawing-rewards-and-commission",children:"Withdrawing rewards and commission"}),"\n",(0,a.jsx)(r.h3,{id:"1-withdraw-rewards",children:"1. Withdraw rewards"}),"\n",(0,a.jsx)(r.pre,{children:(0,a.jsx)(r.code,{className:"language-bash",children:"gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y\n\ntxhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A\n"})}),"\n",(0,a.jsx)(r.h3,{id:"2-confirm-withdrawal",children:"2. Confirm withdrawal"}),"\n",(0,a.jsx)(r.p,{children:"After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:"}),"\n",(0,a.jsx)(r.pre,{children:(0,a.jsx)(r.code,{className:"language-bash",children:'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "216"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "2233766225342"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n'})})]})}function h(e={}){const{wrapper:r}={...(0,i.a)(),...e.components};return r?(0,a.jsx)(r,{...e,children:(0,a.jsx)(l,{...e})}):l(e)}},1151:(e,r,n)=>{n.d(r,{Z:()=>d,a:()=>t});var a=n(7294);const i={},s=a.createContext(i);function t(e){const r=a.useContext(s);return a.useMemo((function(){return"function"==typeof e?e(r):{...r,...e}}),[r,e])}function d(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:t(e.components),a.createElement(s.Provider,{value:r},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/75f9ba63.bf714c2a.js b/assets/js/75f9ba63.bf714c2a.js new file mode 100644 index 0000000000..4d3ac11e70 --- /dev/null +++ b/assets/js/75f9ba63.bf714c2a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5296],{2372:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>c,contentTitle:()=>s,default:()=>l,frontMatter:()=>a,metadata:()=>r,toc:()=>h});var o=n(5893),t=n(1151);const a={sidebar_position:6},s="Partial Set Security",r={id:"validators/partial-set-security-for-validators",title:"Partial Set Security",description:"Partial Set Security allows consumer chains to join as Opt-In or Top N.",source:"@site/versioned_docs/version-v4.2.0-docs/validators/partial-set-security-for-validators.md",sourceDirName:"validators",slug:"/validators/partial-set-security-for-validators",permalink:"/interchain-security/v4.2.0/validators/partial-set-security-for-validators",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"tutorialSidebar",previous:{title:"Joining Stride",permalink:"/interchain-security/v4.2.0/validators/joining-stride"},next:{title:"Frequently Asked Questions",permalink:"/interchain-security/v4.2.0/faq"}},c={},h=[{value:"Messages",id:"messages",level:2},{value:"How to opt in to a consumer chain?",id:"how-to-opt-in-to-a-consumer-chain",level:3},{value:"How to opt out from a consumer chain?",id:"how-to-opt-out-from-a-consumer-chain",level:3},{value:"How to set specific per consumer chain commission rate?",id:"how-to-set-specific-per-consumer-chain-commission-rate",level:3},{value:"Queries",id:"queries",level:2},{value:"Which chains does a validator have to validate?",id:"which-chains-does-a-validator-have-to-validate",level:3},{value:"How do you know how much voting power you need to have to be in the top N for a chain?",id:"how-do-you-know-how-much-voting-power-you-need-to-have-to-be-in-the-top-n-for-a-chain",level:3},{value:"How to retrieve all the opted-in validators on a consumer chain?",id:"how-to-retrieve-all-the-opted-in-validators-on-a-consumer-chain",level:3},{value:"How to retrieve all the consumer validators on a consumer chain?",id:"how-to-retrieve-all-the-consumer-validators-on-a-consumer-chain",level:3},{value:"How can we see the commission rate a validator has set on a consumer chain?",id:"how-can-we-see-the-commission-rate-a-validator-has-set-on-a-consumer-chain",level:3}];function d(e){const i={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(i.h1,{id:"partial-set-security",children:"Partial Set Security"}),"\n",(0,o.jsxs)(i.p,{children:[(0,o.jsx)(i.a,{href:"/interchain-security/v4.2.0/features/partial-set-security",children:"Partial Set Security"})," allows consumer chains to join as Opt-In or Top N.\nHere, we show how a validator can opt in, opt out, or set a custom commission rate on a consumer chain, as well\nas useful queries that a validator can use to figure out which chains it has to validate, etc."]}),"\n",(0,o.jsx)(i.h2,{id:"messages",children:"Messages"}),"\n",(0,o.jsx)(i.h3,{id:"how-to-opt-in-to-a-consumer-chain",children:"How to opt in to a consumer chain?"}),"\n",(0,o.jsx)(i.admonition,{type:"warning",children:(0,o.jsx)(i.p,{children:"A validator is automatically opted in to a Top N chain if the validator belongs to the top N% of the validators on the provider chain."})}),"\n",(0,o.jsx)(i.p,{children:"In a Top N chain, a validator that does not belong to the top N% of the validators on the provider can still choose\nto opt in to a consumer chain. In other words, validators can opt in, in both Opt-In and Top N chains."}),"\n",(0,o.jsx)(i.p,{children:"A validator can opt in to a consumer chain by issuing the following message:"}),"\n",(0,o.jsx)(i.pre,{children:(0,o.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd tx provider opt-in <consumer-chain-id> <optional consumer-pub-key>\n"})}),"\n",(0,o.jsx)(i.p,{children:"where"}),"\n",(0,o.jsxs)(i.ul,{children:["\n",(0,o.jsxs)(i.li,{children:[(0,o.jsx)(i.code,{children:"consumer-chain-id"})," is the string identifier of the consumer chain the validator wants to opt in to;"]}),"\n",(0,o.jsxs)(i.li,{children:[(0,o.jsx)(i.code,{children:"consumer-pub-key"})," corresponds to the public key the validator wants to use on the consumer chain, and it has the\nfollowing format ",(0,o.jsx)(i.code,{children:'{"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}'}),"."]}),"\n"]}),"\n",(0,o.jsxs)(i.p,{children:["A validator can opt in to an existing consumer chain that is already running, or to a ",(0,o.jsx)(i.a,{href:"/interchain-security/v4.2.0/features/proposals",children:"proposed"}),"\nconsumer chain that is still being voted on. A validator can use the following command to retrieve the currently existing\nconsumer chains:"]}),"\n",(0,o.jsx)(i.pre,{children:(0,o.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd query provider list-consumer-chains\n"})}),"\n",(0,o.jsx)(i.p,{children:"and this command to see the currently proposed consumer chains:"}),"\n",(0,o.jsx)(i.pre,{children:(0,o.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd query provider list-proposed-consumer-chains\n"})}),"\n",(0,o.jsx)(i.admonition,{type:"tip",children:(0,o.jsxs)(i.p,{children:["By setting the ",(0,o.jsx)(i.code,{children:"consumer-pub-key"}),", a validator can both opt in to a chain and assign a\npublic key on a consumer chain. Note that a validator can always ",(0,o.jsx)(i.a,{href:"/interchain-security/v4.2.0/features/key-assignment",children:"assign"}),"\na new consumer key at a later stage. The key-assignment ",(0,o.jsx)(i.a,{href:"/interchain-security/v4.2.0/features/key-assignment#rules",children:"rules"}),"\nstill apply when setting ",(0,o.jsx)(i.code,{children:"consumer-pub-key"})," when opting in."]})}),"\n",(0,o.jsx)(i.admonition,{type:"info",children:(0,o.jsx)(i.p,{children:"A validator is only eligible for consumer rewards from a consumer chain if the validator is opted into that chain."})}),"\n",(0,o.jsx)(i.h3,{id:"how-to-opt-out-from-a-consumer-chain",children:"How to opt out from a consumer chain?"}),"\n",(0,o.jsx)(i.p,{children:"A validator can opt out from a consumer by issuing the following message:"}),"\n",(0,o.jsx)(i.pre,{children:(0,o.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd tx provider opt-out <consumer-chain-id>\n"})}),"\n",(0,o.jsx)(i.p,{children:"where"}),"\n",(0,o.jsxs)(i.ul,{children:["\n",(0,o.jsxs)(i.li,{children:[(0,o.jsx)(i.code,{children:"consumer-chain-id"})," is the string identifier of the consumer chain."]}),"\n"]}),"\n",(0,o.jsx)(i.admonition,{type:"warning",children:(0,o.jsx)(i.p,{children:"A validator cannot opt out from a Top N chain if it belongs to the top N% validators of the provider."})}),"\n",(0,o.jsx)(i.admonition,{type:"warning",children:(0,o.jsxs)(i.p,{children:["If a validator moves from the Top N to outside of the top N% of the validators on the provider, it will ",(0,o.jsx)(i.strong,{children:"not"}),"\nbe automatically opted-out. The validator has to manually opt out."]})}),"\n",(0,o.jsx)(i.admonition,{type:"warning",children:(0,o.jsxs)(i.p,{children:["A validator can stop its node on a consumer chain ",(0,o.jsx)(i.strong,{children:"only"})," after opting out and confirming through the ",(0,o.jsx)(i.code,{children:"has-to-validate"}),"\nquery (see ",(0,o.jsx)(i.a,{href:"/interchain-security/v4.2.0/validators/partial-set-security-for-validators#which-chains-does-a-validator-have-to-validate",children:"below"}),") that it does\nnot have to validate the consumer chain any longer."]})}),"\n",(0,o.jsx)(i.admonition,{type:"warning",children:(0,o.jsx)(i.p,{children:"If all validators opt out from an Opt-In chain, the chain will halt with a consensus failure upon receiving the VSCPacket with an empty validator set."})}),"\n",(0,o.jsx)(i.h3,{id:"how-to-set-specific-per-consumer-chain-commission-rate",children:"How to set specific per consumer chain commission rate?"}),"\n",(0,o.jsx)(i.p,{children:"A validator can choose to set a different commission rate on each of the consumer chains.\nThis can be done with the following command:"}),"\n",(0,o.jsx)(i.pre,{children:(0,o.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd tx provider set-consumer-commission-rate <consumer-chain-id> <commission-rate>\n"})}),"\n",(0,o.jsx)(i.p,{children:"where"}),"\n",(0,o.jsxs)(i.ul,{children:["\n",(0,o.jsxs)(i.li,{children:[(0,o.jsx)(i.code,{children:"consumer-chain-id"})," is the string identifier of the consumer chain;"]}),"\n",(0,o.jsxs)(i.li,{children:[(0,o.jsx)(i.code,{children:"comission-rate"})," decimal in ",(0,o.jsx)(i.code,{children:"[minRate, 1]"})," where ",(0,o.jsx)(i.code,{children:"minRate"})," corresponds to the minimum commission rate set on the\nprovider chain (see ",(0,o.jsx)(i.code,{children:"min_commission_rate"})," in ",(0,o.jsx)(i.code,{children:"interchain-security-pd query staking params"}),")."]}),"\n"]}),"\n",(0,o.jsx)(i.p,{children:"If a validator does not set a commission rate on a consumer chain, the commission rate defaults to their commission rate on the provider chain."}),"\n",(0,o.jsx)(i.admonition,{type:"tip",children:(0,o.jsx)(i.p,{children:"Validators can set their commission rate even for consumer chains that they are not currently opted in on, and the commission rate will be applied when they opt in. This is particularly useful for Top N chains, where validators might be opted in automatically,\nso validators can set the commission rate in advance."})}),"\n",(0,o.jsx)(i.admonition,{type:"tip",children:(0,o.jsxs)(i.p,{children:["If a validator opts out and then back in, this will ",(0,o.jsx)(i.em,{children:"not"})," reset their commission rate back to the default. Instead, their\nset commission rate still applies."]})}),"\n",(0,o.jsx)(i.h2,{id:"queries",children:"Queries"}),"\n",(0,o.jsx)(i.p,{children:"Partial Set Security introduces a number of queries to assist validators determine which consumer chains they have to\nvalidate, their commission rate per chain, etc."}),"\n",(0,o.jsx)(i.h3,{id:"which-chains-does-a-validator-have-to-validate",children:"Which chains does a validator have to validate?"}),"\n",(0,o.jsx)(i.p,{children:"Naturally, a validator is aware of the Opt-In chains it has to validate because in order to validate an Opt-In chain,\na validator has to manually opt in to the chain. This is not the case for Top N chains where a validator might be required\nto validate such a chain without explicitly opting in if it belongs to the top N% of the validators on the provider."}),"\n",(0,o.jsx)(i.p,{children:"We introduce the following query:"}),"\n",(0,o.jsx)(i.pre,{children:(0,o.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd query provider has-to-validate <provider-validator-address>\n"})}),"\n",(0,o.jsxs)(i.p,{children:["that can be used by validator with ",(0,o.jsx)(i.code,{children:"provider-validator-address"})," address to retrieve the list of chains that it has to validate."]}),"\n",(0,o.jsx)(i.admonition,{type:"tip",children:(0,o.jsxs)(i.p,{children:["As a validator, the list of chains returned by ",(0,o.jsx)(i.code,{children:"has-to-validate"})," is the list of chains you ",(0,o.jsx)(i.strong,{children:"should"})," be validating to avoid\ngetting jailed for downtime."]})}),"\n",(0,o.jsx)(i.h3,{id:"how-do-you-know-how-much-voting-power-you-need-to-have-to-be-in-the-top-n-for-a-chain",children:"How do you know how much voting power you need to have to be in the top N for a chain?"}),"\n",(0,o.jsxs)(i.p,{children:["This can be seen as part of the ",(0,o.jsx)(i.code,{children:"list-consumer-chains"})," query:"]}),"\n",(0,o.jsx)(i.pre,{children:(0,o.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd query provider list-consumer-chains\n"})}),"\n",(0,o.jsxs)(i.p,{children:["where the ",(0,o.jsx)(i.code,{children:"min_power_in_top_N"})," field shows the minimum voting power required to be\nautomatically opted in to the chain."]}),"\n",(0,o.jsx)(i.admonition,{type:"tip",children:(0,o.jsxs)(i.p,{children:[(0,o.jsx)(i.code,{children:"list-consumer-chains"})," shows the minimal voting power ",(0,o.jsx)(i.em,{children:"right now"}),", but\nthe automatic opt-in happens only when epochs end on the provider.\nIn consequence, a validators power might be large enough to be automatically opted in\nduring an epoch, but if their power is sufficiently decreased before the epoch ends,\nthey will not be opted in automatically."]})}),"\n",(0,o.jsx)(i.h3,{id:"how-to-retrieve-all-the-opted-in-validators-on-a-consumer-chain",children:"How to retrieve all the opted-in validators on a consumer chain?"}),"\n",(0,o.jsx)(i.p,{children:"With the following query:"}),"\n",(0,o.jsx)(i.pre,{children:(0,o.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd query provider consumer-opted-in-validators <consumer-chain-id>\n"})}),"\n",(0,o.jsxs)(i.p,{children:["we can see all the opted-in validators on ",(0,o.jsx)(i.code,{children:"consumer-chain-id"})," that were manually or automatically opted in."]}),"\n",(0,o.jsx)(i.h3,{id:"how-to-retrieve-all-the-consumer-validators-on-a-consumer-chain",children:"How to retrieve all the consumer validators on a consumer chain?"}),"\n",(0,o.jsx)(i.p,{children:"With the following query:"}),"\n",(0,o.jsx)(i.pre,{children:(0,o.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd query provider consumer-validators <consumer-chain-id>\n"})}),"\n",(0,o.jsxs)(i.p,{children:["we can see all the ",(0,o.jsx)(i.em,{children:"consumer validators"})," (i.e., validator set) of ",(0,o.jsx)(i.code,{children:"consumer-chain-id"}),". The consumer validators are the\nones that are currently (or in the future, see warning) validating the consumer chain. A ",(0,o.jsx)(i.em,{children:"consumer validator"})," is an opted-in\nvalidator but not vice versa. For example, an opted-in validator ",(0,o.jsx)(i.code,{children:"V"})," might not be a consumer validator because ",(0,o.jsx)(i.code,{children:"V"})," is\ndenylisted or because ",(0,o.jsx)(i.code,{children:"V"})," is removed due to a validator-set cap."]}),"\n",(0,o.jsx)(i.admonition,{type:"warning",children:(0,o.jsxs)(i.p,{children:["The returned consumer validators from this query do not necessarily correspond to the validator set that is\nvalidating the consumer chain at this exact moment. This is because the ",(0,o.jsx)(i.code,{children:"VSCPacket"})," sent to a consumer chain might be\ndelayed and hence this query might return the validator set that the consumer chain would have at some future\npoint in time."]})}),"\n",(0,o.jsx)(i.h3,{id:"how-can-we-see-the-commission-rate-a-validator-has-set-on-a-consumer-chain",children:"How can we see the commission rate a validator has set on a consumer chain?"}),"\n",(0,o.jsx)(i.p,{children:"Using the following query:"}),"\n",(0,o.jsx)(i.pre,{children:(0,o.jsx)(i.code,{className:"language-bash",children:"interchain-security-pd query provider validator-consumer-commission-rate <consumer-chain-id> <provider-validator-address>\n"})}),"\n",(0,o.jsxs)(i.p,{children:["we retrieve the commission rate set by validator with ",(0,o.jsx)(i.code,{children:"provider-validator-address"})," address on ",(0,o.jsx)(i.code,{children:"consumer-chain-id"}),"."]})]})}function l(e={}){const{wrapper:i}={...(0,t.a)(),...e.components};return i?(0,o.jsx)(i,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},1151:(e,i,n)=>{n.d(i,{Z:()=>r,a:()=>s});var o=n(7294);const t={},a=o.createContext(t);function s(e){const i=o.useContext(a);return o.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function r(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:s(e.components),o.createElement(a.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/7616f23a.837a872f.js b/assets/js/7616f23a.837a872f.js new file mode 100644 index 0000000000..32be2a2d4e --- /dev/null +++ b/assets/js/7616f23a.837a872f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2247],{1422:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>d,frontMatter:()=>r,metadata:()=>s,toc:()=>h});var o=i(5893),t=i(1151);const r={sidebar_position:1},a="Overview",s={id:"introduction/overview",title:"Overview",description:"Interchain Security is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.",source:"@site/docs/introduction/overview.md",sourceDirName:"introduction",slug:"/introduction/overview",permalink:"/interchain-security/introduction/overview",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Docs",permalink:"/interchain-security/"},next:{title:"Terminology",permalink:"/interchain-security/introduction/terminology"}},c={},h=[{value:"Why Interchain Security?",id:"why-interchain-security",level:2},{value:"Core protocol",id:"core-protocol",level:2},{value:"Downtime Slashing",id:"downtime-slashing",level:3},{value:"Tokenomics and Rewards",id:"tokenomics-and-rewards",level:3}];function l(e){const n={a:"a",admonition:"admonition",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,t.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"overview",children:"Overview"}),"\n",(0,o.jsxs)(n.admonition,{type:"info",children:[(0,o.jsx)(n.p,{children:"Interchain Security is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another."}),(0,o.jsx)("br",{}),(0,o.jsx)(n.p,{children:'Interchain Security allows anyone to launch a "consumer" blockchain using a subset, or even the entire, validator set from the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit security and decentralization from the provider.'})]}),"\n",(0,o.jsx)(n.h2,{id:"why-interchain-security",children:"Why Interchain Security?"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"The right amount of security for each application. Consumer chains can choose to inherit the whole validator set from the provider, or they can launch as an opt in chain where only a subset of the provider validators validate the consumer chain. This allows for a wide range of security tradeoffs."}),"\n",(0,o.jsx)(n.li,{children:"Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum."}),"\n",(0,o.jsx)(n.li,{children:"Projects keep majority of gas fees. Depending on configuration, these fees either go to the project\u2019s community DAO, or can be used in the protocol in other ways."}),"\n",(0,o.jsx)(n.li,{children:"No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. Validators from the provider chain validate on the consumer chain with their stake on the provider chain, earning additional rewards. For the consumer chain, this comes with the benefit of exposing their chain to the wider audience of the provider chain."}),"\n",(0,o.jsx)(n.li,{children:"Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set."}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"core-protocol",children:"Core protocol"}),"\n",(0,o.jsx)(n.admonition,{type:"info",children:(0,o.jsxs)(n.p,{children:["Protocol specification is available as ",(0,o.jsx)(n.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md",children:"ICS-028"})," in the IBC repository."]})}),"\n",(0,o.jsx)(n.p,{children:"Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer."}),"\n",(0,o.jsx)(n.p,{children:"To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider."}),"\n",(0,o.jsx)(n.h3,{id:"downtime-slashing",children:"Downtime Slashing"}),"\n",(0,o.jsx)(n.p,{children:"If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period."}),"\n",(0,o.jsx)(n.h3,{id:"tokenomics-and-rewards",children:"Tokenomics and Rewards"}),"\n",(0,o.jsx)(n.p,{children:"Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance."})]})}function d(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>s,a:()=>a});var o=i(7294);const t={},r=o.createContext(t);function a(e){const n=o.useContext(r);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function s(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:a(e.components),o.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/775e2592.0e85c471.js b/assets/js/775e2592.0e85c471.js new file mode 100644 index 0000000000..f3bd13a045 --- /dev/null +++ b/assets/js/775e2592.0e85c471.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7375],{6180:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>o,toc:()=>c});var i=n(5893),s=n(1151);const r={sidebar_position:7,title:"Throttle with retries"},a=void 0,o={id:"adrs/adr-008-throttle-retries",title:"Throttle with retries",description:"ADR 008: Throttle with retries",source:"@site/docs/adrs/adr-008-throttle-retries.md",sourceDirName:"adrs",slug:"/adrs/adr-008-throttle-retries",permalink:"/interchain-security/adrs/adr-008-throttle-retries",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:7,frontMatter:{sidebar_position:7,title:"Throttle with retries"},sidebar:"tutorialSidebar",previous:{title:"Cryptographic verification of equivocation evidence",permalink:"/interchain-security/adrs/adr-005-cryptographic-equivocation-verification"},next:{title:"Soft Opt-Out",permalink:"/interchain-security/adrs/adr-009-soft-opt-out"}},d={},c=[{value:"ADR 008: Throttle with retries",id:"adr-008-throttle-with-retries",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consumer changes",id:"consumer-changes",level:3},{value:"Consumer pending packets storage optimization",id:"consumer-pending-packets-storage-optimization",level:4},{value:"Provider changes",id:"provider-changes",level:3},{value:"Handling <code>VSCMaturedPackets</code> immediately",id:"handling-vscmaturedpackets-immediately",level:4},{value:"Why the provider can handle VSCMatured packets immediately",id:"why-the-provider-can-handle-vscmatured-packets-immediately",level:4},{value:"Splitting of PRs and Upgrade Order",id:"splitting-of-prs-and-upgrade-order",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function l(e){const t={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h2,{id:"adr-008-throttle-with-retries",children:"ADR 008: Throttle with retries"}),"\n",(0,i.jsx)(t.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"6/9/23: Initial draft"}),"\n",(0,i.jsx)(t.li,{children:"6/22/23: added note on consumer pending packets storage optimization"}),"\n",(0,i.jsx)(t.li,{children:"7/14/23: Added note on upgrade order"}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(t.p,{children:"Accepted"}),"\n",(0,i.jsx)(t.h2,{id:"context",children:"Context"}),"\n",(0,i.jsxs)(t.p,{children:["For context on why the throttling mechanism exists, see ",(0,i.jsx)(t.a,{href:"/interchain-security/adrs/adr-002-throttle",children:"ADR 002"}),"."]}),"\n",(0,i.jsxs)(t.p,{children:["Note the terms slash throttling and jail throttling are synonymous, since in Interchain Security a ",(0,i.jsx)(t.code,{children:"SlashPacket"})," simply jails a validator for downtime infractions."]}),"\n",(0,i.jsxs)(t.p,{children:["Currently the throttling mechanism is designed so that provider logic (slash meter, etc.) dictates how many ",(0,i.jsx)(t.code,{children:"SlashPackets"})," can be handled over time.\nThrottled ",(0,i.jsx)(t.code,{children:"SlashPackets"})," are persisted on the provider, leading to multiple possible issues. Namely:"]}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:["If ",(0,i.jsx)(t.code,{children:"SlashPackets"})," or ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," are actually throttled/queued on the provider, state can grow and potentially lead to a DoS attack.\nWe have short term solutions around this, but overall they come with their own weaknesses.\nSee ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/issues/594",children:"#594"}),"."]}),"\n",(0,i.jsxs)(t.li,{children:["If a jailing attack described in ",(0,i.jsx)(t.a,{href:"/interchain-security/adrs/adr-002-throttle",children:"ADR 002"})," were actually to be carried out with the current throttling design, we'd likely have to halt the provider, and perform an emergency upgrade and/or migration to clear the queues of ",(0,i.jsx)(t.code,{children:"SlashPackets"})," that were deemed to be malicious.\nAlternatively, validators would just have to ",(0,i.jsx)(t.em,{children:"tough it out"})," and wait for the queues to clear, during which all/most validators would be jailed.\nRight after being jailed, validators would have to unjail themselves promptly to ensure safety.\nThe coordination required to maintain safety in such a scenario is not ideal."]}),"\n"]}),"\n",(0,i.jsx)(t.p,{children:"As a solution, we can improve the throttling mechanism to instead queue/persist relevant data on each consumer, and have consumers retry slash requests as needed."}),"\n",(0,i.jsx)(t.h2,{id:"decision",children:"Decision"}),"\n",(0,i.jsx)(t.h3,{id:"consumer-changes",children:"Consumer changes"}),"\n",(0,i.jsxs)(t.p,{children:["Note the consumer already queues up both ",(0,i.jsx)(t.code,{children:"SlashPackets"})," and ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," via ",(0,i.jsx)(t.code,{children:"AppendPendingPacket"}),".\nThose packets are dequeued in every ",(0,i.jsx)(t.code,{children:"EndBlock"})," in ",(0,i.jsx)(t.code,{children:"SendPackets"})," and sent to the provider."]}),"\n",(0,i.jsxs)(t.p,{children:["Instead, we will now introduce the following logic on ",(0,i.jsx)(t.code,{children:"EndBlock"}),":"]}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:["Slash packets will always be sent to the provider once they're at the head of the queue.\nHowever, once sent, the consumer will not send any subsequent ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," from the queue until the provider responds with an acknowledgement that the sent ",(0,i.jsx)(t.code,{children:"SlashPacket"})," has been handled, i.e., validator was jailed.\nThat is, ",(0,i.jsx)(t.code,{children:"SlashPackets"})," block the sending of subsequent ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," in the consumer queue."]}),"\n",(0,i.jsxs)(t.li,{children:["If two ",(0,i.jsx)(t.code,{children:"SlashPackets"})," are at the head of the queue, the consumer will send the first ",(0,i.jsx)(t.code,{children:"SlashPacket"}),", and then wait for a success acknowledgement from the provider before sending the second ",(0,i.jsx)(t.code,{children:"SlashPacket"}),".\nThis seems like it'd simplify implementation."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," at the head of the queue (i.e., NOT following a ",(0,i.jsx)(t.code,{children:"SlashPacket"}),") can be sent immediately, and do not block any other packets in the queue, since the provider always handles them immediately."]}),"\n"]}),"\n",(0,i.jsxs)(t.p,{children:["To prevent the provider from having to keep track of what ",(0,i.jsx)(t.code,{children:"SlashPackets"})," have been rejected, the consumer will have to retry the sending of ",(0,i.jsx)(t.code,{children:"SlashPackets"})," over some period of time.\nThis can be achieved with an on-chain consumer param, i.e., ",(0,i.jsx)(t.code,{children:"RetryDelayPeriod"}),".\nTo reduce the amount of redundant re-sends, we recommend setting ",(0,i.jsx)(t.code,{children:"RetryDelayPeriod ~ SlashMeterReplenishmentPeriod"}),", i.e., waiting for the provider slash meter to be replenished before resending the rejected ",(0,i.jsx)(t.code,{children:"SlashPacket"}),"."]}),"\n",(0,i.jsx)(t.p,{children:"Note to prevent weird edge case behavior, a retry would not be attempted until either a success or failure acknowledgement has been received from the provider."}),"\n",(0,i.jsxs)(t.p,{children:["With the behavior described, we maintain very similar behavior to the previous throttling mechanism regarding the timing that ",(0,i.jsx)(t.code,{children:"SlashPackets"})," and ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," are handled on the provider.\nObviously the queueing and blocking logic is moved, and the two chains would have to send more messages between one another (only in the case the throttling mechanism is triggered)."]}),"\n",(0,i.jsxs)(t.p,{children:["In the normal case, when no or a few ",(0,i.jsx)(t.code,{children:"SlashPackets"})," are being sent, the ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," will not be delayed, and hence unbonding will not be delayed."]}),"\n",(0,i.jsxs)(t.p,{children:["For the implementation of this design, see ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/fec3eccad59416cbdb6844e279f59e3f81242888/x/ccv/consumer/keeper/throttle_retry.go",children:"throttle_retry.go"}),"."]}),"\n",(0,i.jsx)(t.h4,{id:"consumer-pending-packets-storage-optimization",children:"Consumer pending packets storage optimization"}),"\n",(0,i.jsx)(t.p,{children:"In addition to the mentioned consumer changes, an optimization will need to be made to the consumer's pending packets storage to properly implement the feature from this ADR."}),"\n",(0,i.jsxs)(t.p,{children:['The consumer ccv module previously queued "pending packets" to be sent in each ',(0,i.jsx)(t.code,{children:"EndBlock"})," in ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/3bc4e7135066d848aac60b0787364c07157fd36d/x/ccv/consumer/keeper/relay.go#L178",children:"SendPackets"}),".\nThese packets are queued in state with a protobuf list of ",(0,i.jsx)(t.code,{children:"ConsumerPacketData"}),".\nFor a single append operation, the entire list is deserialized, then a packet is appended to that list, and the list is serialized again.\nSee older version of ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/05c2dae7c6372b1252b9e97215d07c6aa7618f33/x/ccv/consumer/keeper/keeper.go#L606",children:"AppendPendingPacket"}),".\nThat is, a single append operation has O(N) complexity, where N is the size of the list."]}),"\n",(0,i.jsxs)(t.p,{children:["This poor append performance isn't a problem when the pending packets list is small.\nBut with this ADR being implemented, the pending packets list could potentially grow to the order of thousands of entries when ",(0,i.jsx)(t.code,{children:"SlashPackets"})," need to be resent."]}),"\n",(0,i.jsx)(t.p,{children:"We can improve the append time for this queue by converting it from a protobuf-esq list, to a queue implemented with sdk-esq code.\nThe idea is to persist a uint64 index that will be incremented each time you queue up a packet.\nYou can think of this as storing the tail of the queue.\nThen, packet data will be keyed by that index, making the data naturally ordered byte-wise for sdk's iterator.\nThe index will also be stored in the packet data value bytes, so that the index can later be used to delete certain packets from the queue."}),"\n",(0,i.jsx)(t.p,{children:"Two things are achieved with this approach:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"More efficient packet append/enqueue times"}),"\n",(0,i.jsx)(t.li,{children:"The ability to delete select packets from the queue (previously all packets were deleted at once)"}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"provider-changes",children:"Provider changes"}),"\n",(0,i.jsxs)(t.p,{children:["The main change needed for the provider is the removal of queuing logic for ",(0,i.jsx)(t.code,{children:"SlashPackets"})," and ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," upon being received."]}),"\n",(0,i.jsxs)(t.p,{children:["Instead, the provider will consult the slash meter to determine if a ",(0,i.jsx)(t.code,{children:"SlashPacket"})," can be handled immediately.\nIf not, the provider will return an acknowledgement message to the consumer communicating that the ",(0,i.jsx)(t.code,{children:"SlashPacket"})," could not be handled, and needs to be sent again in the future (retried)."]}),"\n",(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," will always be handled immediately upon being received by the provider."]}),"\n",(0,i.jsxs)(t.p,{children:["Note ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing",children:"spec"}),". Specifically the section on ",(0,i.jsx)(t.em,{children:"VSC Maturity and Slashing Order"}),". Previously the onus was on the provider to maintain this property via queuing packets and handling them FIFO."]}),"\n",(0,i.jsxs)(t.p,{children:["Now this property will be maintained by the consumer sending packets in the correct order, and blocking the sending of ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," as needed. Then, the ordered IBC channel will ensure that ",(0,i.jsx)(t.code,{children:"SlashPackets"})," and ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," are received in the correct order on the provider."]}),"\n",(0,i.jsxs)(t.p,{children:["The provider's main responsibility regarding throttling will now be to determine if a received ",(0,i.jsx)(t.code,{children:"SlashPacket"})," can be handled via slash meter etc., and appropriately acknowledge to the sending consumer."]}),"\n",(0,i.jsxs)(t.h4,{id:"handling-vscmaturedpackets-immediately",children:["Handling ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," immediately"]}),"\n",(0,i.jsx)(t.h4,{id:"why-the-provider-can-handle-vscmatured-packets-immediately",children:"Why the provider can handle VSCMatured packets immediately"}),"\n",(0,i.jsxs)(t.p,{children:["A ",(0,i.jsx)(t.code,{children:"VSCMaturedPacket"})," communicates to the provider that sufficient time passed on the consumer since the corresponding ",(0,i.jsx)(t.code,{children:"VSCPacket"})," has been applied (on the consumer) such that infractions committed on the consumer could have been submitted."]}),"\n",(0,i.jsxs)(t.p,{children:["If the consumer is following the queuing/blocking protocol described, then no bad behavior occurs and the ",(0,i.jsx)(t.em,{children:"VSC Maturity and Slashing Order"})," property is maintained."]}),"\n",(0,i.jsxs)(t.p,{children:["If a consumer sends ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," too leniently -- the consumer is malicious and sends duplicate ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"}),", or sends the packets sooner than the CCV protocol specifies -- then the provider needs to handle ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," immediately to prevent DOS, state bloat, or other issues.\nThe only possible negative outcome is that the malicious consumer may not be able to jail a validator who should have been jailed.\nThe malicious behavior only creates a negative outcome for the consumer chain that is being malicious."]}),"\n",(0,i.jsxs)(t.p,{children:["If a consumer blocks the sending of ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"}),", then unbonding operations on the provider will be delayed, but only until the VSC timeout period has elapsed.\nAt that time, the consumer is removed.\nAgain the malicious behavior only creates a negative outcome for the consumer chain that is being malicious."]}),"\n",(0,i.jsx)(t.h3,{id:"splitting-of-prs-and-upgrade-order",children:"Splitting of PRs and Upgrade Order"}),"\n",(0,i.jsxs)(t.p,{children:["This feature will implement consumer changes in ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/pull/1024",children:"#1024"}),"."]}),"\n",(0,i.jsxs)(t.p,{children:["\u2757",(0,i.jsx)(t.em,{children:(0,i.jsx)(t.strong,{children:"These changes should be deployed to production for all consumers before the provider changes are deployed to production."})})]}),"\n",(0,i.jsxs)(t.p,{children:["In other words, the consumer changes in ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/pull/1024",children:"#1024"}),' are compatible with the current ("v1") provider implementation of throttling that\'s running on the Cosmos Hub as of July 2023.']}),"\n",(0,i.jsxs)(t.p,{children:["Once all consumers have deployed the changes in #1024, the provider changes from ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/pull/1321",children:"#1321"})," can be deployed to production, fully enabling v2 throttling."]}),"\n",(0,i.jsx)(t.h2,{id:"consequences",children:"Consequences"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"Consumers will now have to manage their own queues, and retry logic."}),"\n",(0,i.jsx)(t.li,{children:"Consumers still aren't trustless, but the provider is now less susceptible to mismanaged or malicious consumers."}),"\n",(0,i.jsx)(t.li,{children:'Recovering from the "jailing attack" is more elegant.'}),"\n",(0,i.jsxs)(t.li,{children:["Some issues like ",(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/issues/1001",children:"#1001"})," will now be handled implicitly by the improved throttling mechanism."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.code,{children:"SlashPackets"})," and ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," can be handled immediately once received by the provider if the slash meter allows."]}),"\n",(0,i.jsxs)(t.li,{children:["In general, we reduce the amount of computation that happens in the provider ",(0,i.jsx)(t.code,{children:"EndBlock"}),"."]}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:['We no longer have to reason about a "global queue" and a "chain specific queue", and keeping those all in-sync.\nNow ',(0,i.jsx)(t.code,{children:"SlashPackets"})," and ",(0,i.jsx)(t.code,{children:"VSCMaturedPackets"})," queuing is handled on each consumer individually."]}),"\n",(0,i.jsx)(t.li,{children:"Due to the above, the throttling protocol becomes less complex overall."}),"\n",(0,i.jsx)(t.li,{children:"We no longer have to worry about throttle related DoS attack on the provider, since no queuing exists on the provider."}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"Increased number of IBC packets being relayed anytime throttling logic is triggered."}),"\n",(0,i.jsx)(t.li,{children:"Consumer complexity increases, since consumers now have manage queuing themselves, and implement packet retry logic."}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"neutral",children:"Neutral"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"Core throttling logic on the provider remains unchanged, i.e., slash meter, replenishment cycles, etc."}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"references",children:"References"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/issues/713",children:"EPIC"})," tracking the changes proposed by this ADR"]}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"/interchain-security/adrs/adr-002-throttle",children:"ADR 002: Jail Throttling"})}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/issues/594",children:"#594"})}),"\n"]})]})}function h(e={}){const{wrapper:t}={...(0,s.a)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},1151:(e,t,n)=>{n.d(t,{Z:()=>o,a:()=>a});var i=n(7294);const s={},r=i.createContext(s);function a(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/7aa430a8.3f0c815c.js b/assets/js/7aa430a8.3f0c815c.js new file mode 100644 index 0000000000..bcb37d0081 --- /dev/null +++ b/assets/js/7aa430a8.3f0c815c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7506],{6525:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>t,metadata:()=>r,toc:()=>c});var o=i(5893),s=i(1151);const t={sidebar_position:2,title:"ADR Template"},a="ADR 007: Pause validator unbonding during equivocation proposal",r={id:"adrs/adr-007-pause-unbonding-on-eqv-prop",title:"ADR Template",description:"Changelog",source:"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-007-pause-unbonding-on-eqv-prop.md",sourceDirName:"adrs",slug:"/adrs/adr-007-pause-unbonding-on-eqv-prop",permalink:"/interchain-security/v4.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"ADR Template"},sidebar:"tutorialSidebar",previous:{title:"ADR Template",permalink:"/interchain-security/v4.2.0/adrs/adr-004-denom-dos-fixes"},next:{title:"ADR Template",permalink:"/interchain-security/v4.2.0/adrs/adr-template"}},d={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"How",id:"how",level:3},{value:"When pause",id:"when-pause",level:3},{value:"When unpause",id:"when-unpause",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function l(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"adr-007-pause-validator-unbonding-during-equivocation-proposal",children:"ADR 007: Pause validator unbonding during equivocation proposal"}),"\n",(0,o.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"2023-05-16: Initial Draft"}),"\n",(0,o.jsx)(n.li,{children:"2023-11-30: Change the status to rejected"}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,o.jsx)(n.p,{children:"Rejected"}),"\n",(0,o.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.strong,{children:"Note:"})," ADR rejected as the equivocation proposal was removed by the\ncryptographic verification of equivocation feature\n(see ",(0,o.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-005-cryptographic-equivocation-verification",children:"ADR-005"})," and\n",(0,o.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-013-equivocation-slashing",children:"ADR-013"}),")."]}),"\n",(0,o.jsx)(n.p,{children:"Currently, if an equivocation slashing proposal is created after more than one\nweek has passed since the equivocation, it is possible that the validator in\nquestion could unbond and get away without being slashed, since the unbonding\nperiod is 3 weeks, and the voting period is 2 weeks. For this reason, it might\nbe good to pause unbondings for validators named in an equivocation slashing\nproposal until the proposal's voting period is over."}),"\n",(0,o.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,o.jsx)(n.h3,{id:"how",children:"How"}),"\n",(0,o.jsxs)(n.p,{children:["Pausing the unbonding period is already possible thanks to the changes in the\n",(0,o.jsx)(n.code,{children:"staking"})," module of the cosmos-sdk:"]}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"stakingKeeper.PutUnbondingOnHold"})," pauses an unbonding period"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"stakingKeeper.UnbondingCanComplete"})," unpauses an unbonding period"]}),"\n"]}),"\n",(0,o.jsxs)(n.p,{children:["These methods use a reference counter under the hood, that gets incremented\nevery time ",(0,o.jsx)(n.code,{children:"PutUnbondingOnHold"})," is called, and decreased when\n",(0,o.jsx)(n.code,{children:"UnbondingCanComplete"})," is called instead. A specific unbonding is considered\nfully unpaused when its underlying reference counter reaches 0. Therefore, as\nlong as we safeguard consistency - i.e. we make sure we eventually decrement\nthe reference counter for each time we have incremented it - we can safely use\nthis existing mechanism without conflicts with the ",(0,o.jsx)(n.em,{children:"Completion of Unbonding\nOperations"})," system."]}),"\n",(0,o.jsx)(n.h3,{id:"when-pause",children:"When pause"}),"\n",(0,o.jsxs)(n.p,{children:["The unbonding period (if there is any unbonding) should be paused once an\nequivocation proposal enters the voting period. For that, the ",(0,o.jsx)(n.code,{children:"gov"})," module's\nhook ",(0,o.jsx)(n.code,{children:"AfterProposalDeposit"})," can be used."]}),"\n",(0,o.jsx)(n.p,{children:"If the hook is triggered with a an equivocation proposal in voting period, then\nfor each equivocation of the proposal, the unbonding operations of the related\nvalidator that were initiated after the equivocation block time must be paused"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"i.e. the underlying reference counter has to be increased."}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:"Note that even after the voting period has started, a proposal can receive\nadditional deposits. The hook is triggered however at arrival of a deposit, so\na check to verify that the proposal is not already in voting period is\nrequired."}),"\n",(0,o.jsx)(n.h3,{id:"when-unpause",children:"When unpause"}),"\n",(0,o.jsxs)(n.p,{children:["We can use a ",(0,o.jsx)(n.code,{children:"gov"})," module's hook also here and it is\n",(0,o.jsx)(n.code,{children:"AfterProposalVotingPeriodEnded"}),"."]}),"\n",(0,o.jsx)(n.p,{children:"If the hook is triggered with an equivocation proposal, then for each\nassociated equivocation, the unbonding operations of the related validator that\nwere initiated between the equivocation block time and the start of the\nproposal voting period must be unpaused - i.e. decrease the underlying\nreference counter - regardless of the proposal outcome."}),"\n",(0,o.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,o.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Validators subject to an equivocation proposal cannot finish unbonding\ntheir tokens before the end of the voting period."}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"A malicious consumer chain could forge slash packets enabling submission of\nan equivocation proposal on the provider chain, resulting in the freezing of\nvalidator's unbondings for an undeterminated amount of time."}),"\n",(0,o.jsx)(n.li,{children:"Misbehavior on a consumer chain can potentially go unpunished, if no one\nsubmits an equivocation proposal in time, or if the proposal doesn't pass."}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"This feature can't be used for social slashing, because an equivocation\nproposal is only accepted if there's a slash log for the related\nvalidator(s), meaning the consumer chain has reported the equivocation to\nthe provider chain."}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/747",children:"https://github.com/cosmos/interchain-security/issues/747"})}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/791",children:"https://github.com/cosmos/interchain-security/pull/791"})}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>r,a:()=>a});var o=i(7294);const s={},t=o.createContext(s);function a(e){const n=o.useContext(t);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),o.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/829e00bf.265639bf.js b/assets/js/829e00bf.265639bf.js new file mode 100644 index 0000000000..6e9f6cdc3b --- /dev/null +++ b/assets/js/829e00bf.265639bf.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8718],{1118:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>h,frontMatter:()=>t,metadata:()=>d,toc:()=>l});var i=s(5893),o=s(1151);const t={sidebar_position:2,title:"ADR Template"},r="ADR 004: Denom DOS fixes",d={id:"adrs/adr-004-denom-dos-fixes",title:"ADR Template",description:"Changelog",source:"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-004-denom-dos-fixes.md",sourceDirName:"adrs",slug:"/adrs/adr-004-denom-dos-fixes",permalink:"/interchain-security/v4.2.0/adrs/adr-004-denom-dos-fixes",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"ADR Template"},sidebar:"tutorialSidebar",previous:{title:"ADRs",permalink:"/interchain-security/v4.2.0/adrs/intro"},next:{title:"ADR Template",permalink:"/interchain-security/v4.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop"}},a={},l=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Provider",id:"provider",level:3},{value:"Consumer",id:"consumer",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3}];function c(e){const n={h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,o.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"adr-004-denom-dos-fixes",children:"ADR 004: Denom DOS fixes"}),"\n",(0,i.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"5/9/2023: ADR created"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(n.p,{children:"Accepted"}),"\n",(0,i.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,i.jsx)(n.p,{children:"The provider and consumer modules are vulnerable to similar issues involving an attacker sending millions of denoms to certain addresses and causing the chain to halt. This ADR outlines both fixes since they are similar. Both fixes involve processing only denoms that are on a whitelist to avoid iterating over millions of junk denoms but have different requirements and are implemented in different ways."}),"\n",(0,i.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,i.jsx)(n.h3,{id:"provider",children:"Provider"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Put the distribution module's FeePoolAddress back on the blocklist so that it cannot receive funds from users."}),"\n",(0,i.jsx)(n.li,{children:"Create a new address called ConsumerRewardPool and unblock it, allowing funds to be sent to it."}),"\n",(0,i.jsx)(n.li,{children:"Create a set of strings in the store for allowed ConsumerRewardDenoms."}),"\n",(0,i.jsx)(n.li,{children:"Create an endpoint called RegisterConsumerRewardDenom which deducts a fee from the sender's account, sends it to the community pool and adds a string to the ConsumerRewardDenoms set."}),"\n",(0,i.jsx)(n.li,{children:"Create a parameter called ConsumerRewardDenomRegistrationFee which determines the fee which is charged to register a consumer reward denom in the step above."}),"\n",(0,i.jsxs)(n.li,{children:["Create a function called TransferRewardsToFeeCollector which gets the entire ConsumerRewardDenoms set from the store, iterates over it, and for each entry:","\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Gets the balance of this denom for the ConsumerRewardPool account"}),"\n",(0,i.jsx)(n.li,{children:"Sends the entire balance out to the FeePoolAddress using SendCoinsFromModuleToModule which is not affected by the blocklist."}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.li,{children:"Run TransferRewardsToFeeCollector in the endblock"}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Now, nobody can send millions of junk denoms to the FeePoolAddress because it is on the block list. If they send millions of junk denoms to the ConsumerRewardPool, this does not matter because all balances are not iterated over, only those which are in the ConsumerRewardDenoms set."}),"\n",(0,i.jsx)(n.p,{children:"We also add a new tx: register-consumer-reward-denom, and a new query: registered-consumer-reward-denoms"}),"\n",(0,i.jsx)(n.h3,{id:"consumer",children:"Consumer"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Create a new param RewardDenoms with a list of strings"}),"\n",(0,i.jsx)(n.li,{children:"Create a new param ProviderRewardDenoms with a list of strings"}),"\n",(0,i.jsx)(n.li,{children:"Create a function AllowedRewardDenoms which iterates over ProviderRewardDenoms and converts each denom to its ibc-prefixed denom using the provider chain's ibc channel information, then concatenates the RewardDenoms list and returns the combined list of allowed denoms."}),"\n",(0,i.jsx)(n.li,{children:"In SendRewardsToProvider, instead of iterating over the balances of all denoms in the ToSendToProvider address, iterate over AllowedRewardDenoms"}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Now, if somebody sends millions of junk denoms to ToSendToProvider, they will not be iterated over. Only the RewardDenoms and ProviderRewardDenoms will be iterated over. Since we do not require this feature to be permissionless on the consumer, the registration fee process is not needed."}),"\n",(0,i.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,i.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Denom DOS is no longer possible on either provider or consumer."}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Consumer chain teams must pay a fee to register a denom for distribution on the provider, and add some extra parameters in their genesis file."}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,o.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},1151:(e,n,s)=>{s.d(n,{Z:()=>d,a:()=>r});var i=s(7294);const o={},t=i.createContext(o);function r(e){const n=i.useContext(t);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:r(e.components),i.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/83f6d28d.5a6df8c0.js b/assets/js/83f6d28d.5a6df8c0.js new file mode 100644 index 0000000000..bd7c5ff6bf --- /dev/null +++ b/assets/js/83f6d28d.5a6df8c0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7534],{7915:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>h,frontMatter:()=>s,metadata:()=>a,toc:()=>d});var i=t(5893),r=t(1151);const s={sidebar_position:6},o="Joining Stride",a={id:"validators/joining-stride",title:"Joining Stride",description:"Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.",source:"@site/versioned_docs/version-v5.0.0/validators/joining-stride.md",sourceDirName:"validators",slug:"/validators/joining-stride",permalink:"/interchain-security/v5.0.0/validators/joining-stride",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"tutorialSidebar",previous:{title:"Joining Neutron",permalink:"/interchain-security/v5.0.0/validators/joining-neutron"},next:{title:"Frequently Asked Questions",permalink:"/interchain-security/v5.0.0/faq"}},c={},d=[{value:"Note",id:"note",level:2},{value:"Resources",id:"resources",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",ul:"ul",...(0,r.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"joining-stride",children:"Joining Stride"}),"\n",(0,i.jsxs)(n.p,{children:["Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using ",(0,i.jsx)(n.code,{children:"cosmoshub-4"})," validator set."]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"stride-1"})," network (mainnet) will perform a software upgrade and at height ",(0,i.jsx)(n.code,{children:"4616678"})," that will transition the network to using the Cosmos Hub's (",(0,i.jsx)(n.code,{children:"cosmoshub-4"}),") validator set."]}),"\n",(0,i.jsxs)(n.p,{children:["You can find instructions about the Stride consumer chain launch and joining the mainnet ",(0,i.jsx)(n.a,{href:"https://github.com/Stride-Labs/mainnet/tree/main/ics-instructions",children:"here"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["This ",(0,i.jsx)(n.a,{href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt",children:"Excalidraw graphic"})," explains the timeline of Stride's changeover procedure."]}),"\n",(0,i.jsx)(n.h2,{id:"note",children:"Note"}),"\n",(0,i.jsxs)(n.p,{children:["Stride re-uses an existing ",(0,i.jsx)(n.code,{children:"transfer"})," channel to send consumer rewards to the provider chain, in order to preserve existing transfer IBC denom between ",(0,i.jsx)(n.code,{children:"stride-1"})," and ",(0,i.jsx)(n.code,{children:"cosmoshub-4"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"resources",children:"Resources"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://docs.stride.zone/docs",children:"Stride docs"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt",children:"Changeover procedure timeline"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/Stride-Labs/mainnet/tree/main/ics-instructions",children:"Changeover upgrade docs"})}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,r.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>a,a:()=>o});var i=t(7294);const r={},s=i.createContext(r);function o(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/852eba87.e3d2f27b.js b/assets/js/852eba87.e3d2f27b.js new file mode 100644 index 0000000000..5628579cec --- /dev/null +++ b/assets/js/852eba87.e3d2f27b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2473],{8939:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>c,contentTitle:()=>t,default:()=>h,frontMatter:()=>o,metadata:()=>d,toc:()=>a});var r=n(5893),s=n(1151);const o={sidebar_position:3},t="Interchain Security Parameters",d={id:"introduction/params",title:"Interchain Security Parameters",description:"The parameters necessary for Interchain Security (ICS) are defined in",source:"@site/versioned_docs/version-v4.2.0-docs/introduction/params.md",sourceDirName:"introduction",slug:"/introduction/params",permalink:"/interchain-security/v4.2.0/introduction/params",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Terminology",permalink:"/interchain-security/v4.2.0/introduction/terminology"},next:{title:"Technical Specification",permalink:"/interchain-security/v4.2.0/introduction/technical-specification"}},c={},a=[{value:"Time-Based Parameters",id:"time-based-parameters",level:2},{value:"ProviderUnbondingPeriod",id:"providerunbondingperiod",level:3},{value:"ConsumerUnbondingPeriod",id:"consumerunbondingperiod",level:3},{value:"TrustingPeriodFraction",id:"trustingperiodfraction",level:3},{value:"CCVTimeoutPeriod",id:"ccvtimeoutperiod",level:3},{value:"InitTimeoutPeriod",id:"inittimeoutperiod",level:3},{value:"VscTimeoutPeriod",id:"vsctimeoutperiod",level:3},{value:"BlocksPerDistributionTransmission",id:"blocksperdistributiontransmission",level:3},{value:"TransferPeriodTimeout",id:"transferperiodtimeout",level:3},{value:"Reward Distribution Parameters",id:"reward-distribution-parameters",level:2},{value:"ConsumerRedistributionFraction",id:"consumerredistributionfraction",level:3},{value:"BlocksPerDistributionTransmission",id:"blocksperdistributiontransmission-1",level:3},{value:"TransferTimeoutPeriod",id:"transfertimeoutperiod",level:3},{value:"DistributionTransmissionChannel",id:"distributiontransmissionchannel",level:3},{value:"ProviderFeePoolAddrStr",id:"providerfeepooladdrstr",level:3},{value:"Slash Throttle Parameters",id:"slash-throttle-parameters",level:2},{value:"SlashMeterReplenishPeriod",id:"slashmeterreplenishperiod",level:3},{value:"SlashMeterReplenishFraction",id:"slashmeterreplenishfraction",level:3},{value:"MaxThrottledPackets",id:"maxthrottledpackets",level:3},{value:"RetryDelayPeriod",id:"retrydelayperiod",level:3},{value:"Epoch Parameters",id:"epoch-parameters",level:2},{value:"BlocksPerEpoch",id:"blocksperepoch",level:3}];function l(e){const i={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(i.h1,{id:"interchain-security-parameters",children:"Interchain Security Parameters"}),"\n",(0,r.jsx)(i.p,{children:"The parameters necessary for Interchain Security (ICS) are defined in"}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:["the ",(0,r.jsx)(i.code,{children:"Params"})," structure in ",(0,r.jsx)(i.code,{children:"proto/interchain_security/ccv/provider/v1/provider.proto"})," for the provider;"]}),"\n",(0,r.jsxs)(i.li,{children:["the ",(0,r.jsx)(i.code,{children:"Params"})," structure in ",(0,r.jsx)(i.code,{children:"proto/interchain_security/ccv/consumer/v1/consumer.proto"})," for the consumer."]}),"\n"]}),"\n",(0,r.jsx)(i.h2,{id:"time-based-parameters",children:"Time-Based Parameters"}),"\n",(0,r.jsx)(i.p,{children:"ICS relies on the following time-based parameters."}),"\n",(0,r.jsx)(i.h3,{id:"providerunbondingperiod",children:"ProviderUnbondingPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"ProviderUnbondingPeriod"})," is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance."]}),"\n",(0,r.jsx)(i.h3,{id:"consumerunbondingperiod",children:"ConsumerUnbondingPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"ConsumerUnbondingPeriod"})," is the unbonding period on the consumer chain."]}),"\n",(0,r.jsxs)(i.admonition,{type:"info",children:[(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"ConsumerUnbondingPeriod"})," is set via the ",(0,r.jsx)(i.code,{children:"ConsumerAdditionProposal"})," governance proposal to add a new consumer chain.\nIt is recommended that every consumer chain set and unbonding period shorter than ",(0,r.jsx)(i.code,{children:"ProviderUnbondingPeriod"})]}),(0,r.jsx)("br",{}),(0,r.jsx)(i.p,{children:"Example:"}),(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{children:"ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day\n"})})]}),"\n",(0,r.jsx)(i.p,{children:"Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer."}),"\n",(0,r.jsx)(i.h3,{id:"trustingperiodfraction",children:"TrustingPeriodFraction"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"TrustingPeriodFraction"})," is used to calculate the ",(0,r.jsx)(i.code,{children:"TrustingPeriod"})," of created IBC clients on both provider and consumer chains."]}),"\n",(0,r.jsxs)(i.p,{children:["Setting ",(0,r.jsx)(i.code,{children:"TrustingPeriodFraction"})," to ",(0,r.jsx)(i.code,{children:"0.5"})," would result in the following:"]}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{children:"TrustingPeriodFraction = 0.5\nProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5\nConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5\n"})}),"\n",(0,r.jsxs)(i.p,{children:["Note that a light clients must be updated within the ",(0,r.jsx)(i.code,{children:"TrustingPeriod"})," in order to avoid being frozen."]}),"\n",(0,r.jsxs)(i.p,{children:["For more details, see the ",(0,r.jsx)(i.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/client/ics-007-tendermint-client/README.md",children:"IBC specification of Tendermint clients"}),"."]}),"\n",(0,r.jsx)(i.h3,{id:"ccvtimeoutperiod",children:"CCVTimeoutPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"CCVTimeoutPeriod"})," is the period used to compute the timeout timestamp when sending IBC packets."]}),"\n",(0,r.jsxs)(i.p,{children:["For more details, see the ",(0,r.jsx)(i.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/core/ics-004-channel-and-packet-semantics/README.md#sending-packets",children:"IBC specification of Channel & Packet Semantics"}),"."]}),"\n",(0,r.jsx)(i.admonition,{type:"warning",children:(0,r.jsx)(i.p,{children:"If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed."})}),"\n",(0,r.jsx)(i.p,{children:"CCVTimeoutPeriod may have different values on the provider and consumer chains."}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"CCVTimeoutPeriod"})," on the provider ",(0,r.jsx)(i.strong,{children:"must"})," be larger than ",(0,r.jsx)(i.code,{children:"ConsumerUnbondingPeriod"})]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"CCVTimeoutPeriod"})," on the consumer is initial set via the ",(0,r.jsx)(i.code,{children:"ConsumerAdditionProposal"})]}),"\n"]}),"\n",(0,r.jsx)(i.h3,{id:"inittimeoutperiod",children:"InitTimeoutPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"InitTimeoutPeriod"})," is the maximum allowed duration for CCV channel initialization to execute."]}),"\n",(0,r.jsxs)(i.p,{children:["For any consumer chain, if the CCV channel is not established within ",(0,r.jsx)(i.code,{children:"InitTimeoutPeriod"})," then the consumer chain will be removed and therefore will not be secured by the provider chain."]}),"\n",(0,r.jsxs)(i.p,{children:["The countdown starts when the ",(0,r.jsx)(i.code,{children:"spawn_time"})," specified in the ",(0,r.jsx)(i.code,{children:"ConsumerAdditionProposal"})," is reached."]}),"\n",(0,r.jsx)(i.h3,{id:"vsctimeoutperiod",children:"VscTimeoutPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"VscTimeoutPeriod"})," is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live.\nIf the ",(0,r.jsx)(i.code,{children:"VscTimeoutPeriod"})," is ever reached for a consumer chain that chain will be considered not live and removed from interchain security."]}),"\n",(0,r.jsx)(i.admonition,{type:"tip",children:(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"VscTimeoutPeriod"})," MUST be larger than the ",(0,r.jsx)(i.code,{children:"ConsumerUnbondingPeriod"}),"."]})}),"\n",(0,r.jsx)(i.h3,{id:"blocksperdistributiontransmission",children:"BlocksPerDistributionTransmission"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"BlocksPerDistributionTransmission"})," is the number of blocks between rewards transfers from the consumer to the provider."]}),"\n",(0,r.jsx)(i.h3,{id:"transferperiodtimeout",children:"TransferPeriodTimeout"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"TransferPeriodTimeout"})," is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider."]}),"\n",(0,r.jsxs)(i.p,{children:["If this timeout expires, then the transfer is attempted again after ",(0,r.jsx)(i.code,{children:"BlocksPerDistributionTransmission"})," blocks."]}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"TransferPeriodTimeout"})," on the consumer is initial set via the ",(0,r.jsx)(i.code,{children:"ConsumerAdditionProposal"})," gov proposal to add the consumer"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"TransferPeriodTimeout"})," should be smaller than ",(0,r.jsx)(i.code,{children:"BlocksPerDistributionTransmission x avg_block_time"})]}),"\n"]}),"\n",(0,r.jsx)(i.h2,{id:"reward-distribution-parameters",children:"Reward Distribution Parameters"}),"\n",(0,r.jsx)(i.admonition,{type:"tip",children:(0,r.jsxs)(i.p,{children:["The following chain parameters dictate consumer chain distribution amount and frequency.\nThey are set at consumer genesis and ",(0,r.jsx)(i.code,{children:"BlocksPerDistributionTransmission"}),", ",(0,r.jsx)(i.code,{children:"ConsumerRedistributionFraction"}),"\n",(0,r.jsx)(i.code,{children:"TransferTimeoutPeriod"})," must be provided in every ",(0,r.jsx)(i.code,{children:"ConsumerChainAddition"})," proposal."]})}),"\n",(0,r.jsx)(i.h3,{id:"consumerredistributionfraction",children:"ConsumerRedistributionFraction"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"ConsumerRedistributionFraction"})," is the fraction of tokens allocated to the consumer redistribution address during distribution events. The fraction is a string representing a decimal number. For example ",(0,r.jsx)(i.code,{children:'"0.75"'})," would represent ",(0,r.jsx)(i.code,{children:"75%"}),"."]}),"\n",(0,r.jsxs)(i.admonition,{type:"tip",children:[(0,r.jsx)(i.p,{children:"Example:"}),(0,r.jsxs)(i.p,{children:["With ",(0,r.jsx)(i.code,{children:"ConsumerRedistributionFraction"})," set to ",(0,r.jsx)(i.code,{children:'"0.75"'})," the consumer chain would send ",(0,r.jsx)(i.code,{children:"75%"})," of its block rewards and accumulated fees to the consumer redistribution address, and the remaining ",(0,r.jsx)(i.code,{children:"25%"})," to the provider chain every ",(0,r.jsx)(i.code,{children:"BlocksPerDistributionTransmission"})," blocks."]})]}),"\n",(0,r.jsx)(i.h3,{id:"blocksperdistributiontransmission-1",children:"BlocksPerDistributionTransmission"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"BlocksPerDistributionTransmission"})," is the number of blocks between IBC token transfers from the consumer chain to the provider chain."]}),"\n",(0,r.jsx)(i.h3,{id:"transfertimeoutperiod",children:"TransferTimeoutPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"TransferTimeoutPeriod"})," is the timeout period for consumer chain reward distribution IBC packets."]}),"\n",(0,r.jsx)(i.h3,{id:"distributiontransmissionchannel",children:"DistributionTransmissionChannel"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"DistributionTransmissionChannel"})," is the provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."]}),"\n",(0,r.jsx)(i.h3,{id:"providerfeepooladdrstr",children:"ProviderFeePoolAddrStr"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"ProviderFeePoolAddrStr"})," is the provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."]}),"\n",(0,r.jsx)(i.h2,{id:"slash-throttle-parameters",children:"Slash Throttle Parameters"}),"\n",(0,r.jsx)(i.h3,{id:"slashmeterreplenishperiod",children:"SlashMeterReplenishPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"SlashMeterReplenishPeriod"})," exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed."]}),"\n",(0,r.jsxs)(i.p,{children:["The meter is replenished to an amount equal to the slash meter allowance for that block, or ",(0,r.jsx)(i.code,{children:"SlashMeterReplenishFraction * CurrentTotalVotingPower"}),"."]}),"\n",(0,r.jsx)(i.h3,{id:"slashmeterreplenishfraction",children:"SlashMeterReplenishFraction"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"SlashMeterReplenishFraction"})," exists on the provider as the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs."]}),"\n",(0,r.jsxs)(i.p,{children:["This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a ",(0,r.jsx)(i.code,{children:"sdk.Dec"})," when used."]}),"\n",(0,r.jsx)(i.h3,{id:"maxthrottledpackets",children:"MaxThrottledPackets"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"MaxThrottledPackets"})," exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value."]}),"\n",(0,r.jsx)(i.p,{children:"This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness."}),"\n",(0,r.jsx)(i.admonition,{type:"info",children:(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"MaxThrottledPackets"})," was deprecated in ICS versions >= v3.2.0 due to the implementation of ",(0,r.jsx)(i.a,{href:"/interchain-security/v4.2.0/adrs/adr-008-throttle-retries",children:"ADR-008"}),"."]})}),"\n",(0,r.jsx)(i.h3,{id:"retrydelayperiod",children:"RetryDelayPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"RetryDelayPeriod"})," exists on the consumer for ",(0,r.jsx)(i.strong,{children:"ICS versions >= v3.2.0"})," (introduced by the implementation of ",(0,r.jsx)(i.a,{href:"/interchain-security/v4.2.0/adrs/adr-008-throttle-retries",children:"ADR-008"}),") and is the period at which the consumer retries to send a ",(0,r.jsx)(i.code,{children:"SlashPacket"})," that was rejected by the provider."]}),"\n",(0,r.jsx)(i.h2,{id:"epoch-parameters",children:"Epoch Parameters"}),"\n",(0,r.jsx)(i.h3,{id:"blocksperepoch",children:"BlocksPerEpoch"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"BlocksPerEpoch"})," exists on the provider for ",(0,r.jsx)(i.strong,{children:"ICS versions >= 3.3.0"})," (introduced by the implementation of ",(0,r.jsx)(i.a,{href:"/interchain-security/v4.2.0/adrs/adr-014-epochs",children:"ADR-014"}),")\nand corresponds to the number of blocks that constitute an epoch. This param is set to 600 by default. Assuming we need 6 seconds to\ncommit a block, the duration of an epoch corresponds to 1 hour. This means that a ",(0,r.jsx)(i.code,{children:"VSCPacket"})," would be sent to a consumer\nchain once at the end of every epoch, so once every 600 blocks. This parameter can be adjusted via a governance proposal,\nhowever careful consideration is needed so that ",(0,r.jsx)(i.code,{children:"BlocksPerEpoch"})," is not too large. A large ",(0,r.jsx)(i.code,{children:"BlocksPerEpoch"})," could lead to a delay\nof ",(0,r.jsx)(i.code,{children:"VSCPacket"}),"s and hence potentially lead to ",(0,r.jsx)(i.a,{href:"https://informal.systems/blog/learning-to-live-with-unbonding-pausing",children:"unbonding pausing"}),".\nFor setting ",(0,r.jsx)(i.code,{children:"BlocksPerEpoch"}),", we also need to consider potential slow chain upgrades that could delay the sending of a\n",(0,r.jsx)(i.code,{children:"VSCPacket"}),", as well as potential increases in the time it takes to commit a block (e.g., from 6 seconds to 30 seconds)."]})]})}function h(e={}){const{wrapper:i}={...(0,s.a)(),...e.components};return i?(0,r.jsx)(i,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},1151:(e,i,n)=>{n.d(i,{Z:()=>d,a:()=>t});var r=n(7294);const s={},o=r.createContext(s);function t(e){const i=r.useContext(o);return r.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function d(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:t(e.components),r.createElement(o.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/867425db.d47ee539.js b/assets/js/867425db.d47ee539.js new file mode 100644 index 0000000000..28a160ecb8 --- /dev/null +++ b/assets/js/867425db.d47ee539.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8477],{5024:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>h,contentTitle:()=>s,default:()=>l,frontMatter:()=>o,metadata:()=>r,toc:()=>c});var t=i(5893),a=i(1151);const o={sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},s=void 0,r={id:"frequently-asked-questions",title:"Frequently Asked Questions",description:"What is a consumer chain?",source:"@site/versioned_docs/version-v4.2.0-docs/frequently-asked-questions.md",sourceDirName:".",slug:"/faq",permalink:"/interchain-security/v4.2.0/faq",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:5,frontMatter:{sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},sidebar:"tutorialSidebar",previous:{title:"Partial Set Security",permalink:"/interchain-security/v4.2.0/validators/partial-set-security-for-validators"},next:{title:"ADRs",permalink:"/interchain-security/v4.2.0/adrs/intro"}},h={},c=[{value:"What is a consumer chain?",id:"what-is-a-consumer-chain",level:2},{value:"What happens to consumer if provider is down?",id:"what-happens-to-consumer-if-provider-is-down",level:2},{value:"What happens to provider if consumer is down?",id:"what-happens-to-provider-if-consumer-is-down",level:2},{value:"Can I run the provider and consumer chains on the same machine?",id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine",level:2},{value:"Can the consumer chain have its own token?",id:"can-the-consumer-chain-have-its-own-token",level:2},{value:"How are Tx fees paid on consumer?",id:"how-are-tx-fees-paid-on-consumer",level:2},{value:"Are there any restrictions the consumer chains need to abide by?",id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by",level:2},{value:"What's in it for the validators and stakers?",id:"whats-in-it-for-the-validators-and-stakers",level:2},{value:"Can the consumer chain have its own governance?",id:"can-the-consumer-chain-have-its-own-governance",level:2},{value:"Can validators opt out of validating a consumer chain?",id:"can-validators-opt-out-of-validating-a-consumer-chain",level:2},{value:"How does Slashing work?",id:"how-does-slashing-work",level:2},{value:"Can Consumer Chains perform Software Upgrades?",id:"can-consumer-chains-perform-software-upgrades",level:2},{value:"How can I connect to the testnets?",id:"how-can-i-connect-to-the-testnets",level:2},{value:"How do I start using ICS?",id:"how-do-i-start-using-ics",level:2},{value:"Which relayers are supported?",id:"which-relayers-are-supported",level:2},{value:"How does key delegation work in ICS?",id:"how-does-key-delegation-work-in-ics",level:2},{value:"How does Partial Set Security work?",id:"how-does-partial-set-security-work",level:2},{value:"How does a validator know which consumers chains it has to validate?",id:"how-does-a-validator-know-which-consumers-chains-it-has-to-validate",level:2},{value:"How many chains can a validator opt in to?",id:"how-many-chains-can-a-validator-opt-in-to",level:2},{value:"Can validators assign a consensus keys while a consumer-addition proposal is in voting period?",id:"can-validators-assign-a-consensus-keys-while-a-consumer-addition-proposal-is-in-voting-period",level:2},{value:"Can validators assign a consensus key during the voting period for a consumer-addition proposal if they are not in the top N?",id:"can-validators-assign-a-consensus-key-during-the-voting-period-for-a-consumer-addition-proposal-if-they-are-not-in-the-top-n",level:2},{value:"Can validators opt in to an Opt-in or Top N chain after its consumer-addition proposal voting period is over but before the spawn time?",id:"can-validators-opt-in-to-an-opt-in-or-top-n-chain-after-its-consumer-addition-proposal-voting-period-is-over-but-before-the-spawn-time",level:2},{value:"Can validators opt in to an Opt-in chain after the spawn time if nobody else opted in?",id:"can-validators-opt-in-to-an-opt-in-chain-after-the-spawn-time-if-nobody-else-opted-in",level:2},{value:"Can all validators opt out of an Opt-in chain?",id:"can-all-validators-opt-out-of-an-opt-in-chain",level:2},{value:"Can validators set a commission rate for chains they have not opted in to?",id:"can-validators-set-a-commission-rate-for-chains-they-have-not-opted-in-to",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h2:"h2",li:"li",p:"p",strong:"strong",ul:"ul",...(0,a.a)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h2,{id:"what-is-a-consumer-chain",children:"What is a consumer chain?"}),"\n",(0,t.jsx)(n.p,{children:"Consumer chain is a blockchain operated by (a subset of) the validators of the provider chain. The ICS protocol ensures that the consumer chain gets information about which validators should run it (informs consumer chain about the current state of the validator set and the opted in validators for this consumer chain on the provider)."}),"\n",(0,t.jsx)(n.p,{children:"Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements."}),"\n",(0,t.jsx)(n.h2,{id:"what-happens-to-consumer-if-provider-is-down",children:"What happens to consumer if provider is down?"}),"\n",(0,t.jsx)(n.p,{children:"In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set."}),"\n",(0,t.jsx)(n.p,{children:"The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness."}),"\n",(0,t.jsxs)(n.p,{children:["However, if the ",(0,t.jsx)(n.code,{children:"trusting_period"})," (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain.\nThis means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about."]}),"\n",(0,t.jsx)(n.p,{children:'Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point.\nAt the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.'}),"\n",(0,t.jsx)(n.h2,{id:"what-happens-to-provider-if-consumer-is-down",children:"What happens to provider if consumer is down?"}),"\n",(0,t.jsx)(n.p,{children:"Consumer chains do not impact the provider chain.\nThe ICS protocol is concerned only with validator set management, and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events)."}),"\n",(0,t.jsx)(n.h2,{id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine",children:"Can I run the provider and consumer chains on the same machine?"}),"\n",(0,t.jsx)(n.p,{children:"Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation."}),"\n",(0,t.jsx)(n.h2,{id:"can-the-consumer-chain-have-its-own-token",children:"Can the consumer chain have its own token?"}),"\n",(0,t.jsx)(n.p,{children:"As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees."}),"\n",(0,t.jsx)(n.h2,{id:"how-are-tx-fees-paid-on-consumer",children:"How are Tx fees paid on consumer?"}),"\n",(0,t.jsx)(n.p,{children:"The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations."}),"\n",(0,t.jsx)(n.h2,{id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by",children:"Are there any restrictions the consumer chains need to abide by?"}),"\n",(0,t.jsx)(n.p,{children:"No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way.\nThe only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain."}),"\n",(0,t.jsx)(n.h2,{id:"whats-in-it-for-the-validators-and-stakers",children:"What's in it for the validators and stakers?"}),"\n",(0,t.jsxs)(n.p,{children:["The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by ",(0,t.jsx)(n.code,{children:"ConsumerRedistributionFraction"}),". The rewards are distributed (sent to the provider) every ",(0,t.jsx)(n.code,{children:"BlocksPerDistributionTransmission"}),"."]}),"\n",(0,t.jsx)(n.admonition,{type:"note",children:(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"ConsumerRedistributionFraction"})," and ",(0,t.jsx)(n.code,{children:"BlocksPerDistributionTransmission"})," are parameters defined in the ",(0,t.jsx)(n.code,{children:"ConsumerAdditionProposal"})," used to create the consumer chain. These parameters can be changed via consumer chain governance."]})}),"\n",(0,t.jsx)(n.h2,{id:"can-the-consumer-chain-have-its-own-governance",children:"Can the consumer chain have its own governance?"}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Yes."})}),"\n",(0,t.jsx)(n.p,{children:'In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.'}),"\n",(0,t.jsx)(n.p,{children:"Validators can also be representatives but representatives are not required to run validator nodes."}),"\n",(0,t.jsx)(n.p,{children:"This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance."}),"\n",(0,t.jsx)(n.h2,{id:"can-validators-opt-out-of-validating-a-consumer-chain",children:"Can validators opt out of validating a consumer chain?"}),"\n",(0,t.jsx)(n.p,{children:"A validator can always opt out from an Opt-In consumer chain.\nA validator can only opt out from a Top N chain if the validator does not belong to the top N% validators."}),"\n",(0,t.jsx)(n.h2,{id:"how-does-slashing-work",children:"How does Slashing work?"}),"\n",(0,t.jsxs)(n.p,{children:["Validators that perform an equivocation or a light-client attack on a consumer chain are slashed on the provider chain.\nWe achieve this by submitting the proof of the equivocation or the light-client attack to the provider chain (see ",(0,t.jsx)(n.a,{href:"/interchain-security/v4.2.0/features/slashing",children:"slashing"}),")."]}),"\n",(0,t.jsx)(n.h2,{id:"can-consumer-chains-perform-software-upgrades",children:"Can Consumer Chains perform Software Upgrades?"}),"\n",(0,t.jsx)(n.p,{children:"Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM)."}),"\n",(0,t.jsx)(n.p,{children:"Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module."}),"\n",(0,t.jsx)(n.h2,{id:"how-can-i-connect-to-the-testnets",children:"How can I connect to the testnets?"}),"\n",(0,t.jsxs)(n.p,{children:["Check out the ",(0,t.jsx)(n.a,{href:"/interchain-security/v4.2.0/validators/joining-testnet",children:"Joining Replicated Security testnet"})," section."]}),"\n",(0,t.jsx)(n.h2,{id:"how-do-i-start-using-ics",children:"How do I start using ICS?"}),"\n",(0,t.jsxs)(n.p,{children:["To become a consumer chain use this ",(0,t.jsx)(n.a,{href:"/interchain-security/v4.2.0/consumer-development/onboarding",children:"checklist"})," and check the ",(0,t.jsx)(n.a,{href:"/interchain-security/v4.2.0/consumer-development/app-integration",children:"App integration section"})]}),"\n",(0,t.jsx)(n.h2,{id:"which-relayers-are-supported",children:"Which relayers are supported?"}),"\n",(0,t.jsx)(n.p,{children:"Currently supported versions:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Hermes 1.8.0"}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"how-does-key-delegation-work-in-ics",children:"How does key delegation work in ICS?"}),"\n",(0,t.jsxs)(n.p,{children:["You can check the ",(0,t.jsx)(n.a,{href:"/interchain-security/v4.2.0/features/key-assignment",children:"Key Assignment Guide"})," for specific instructions."]}),"\n",(0,t.jsx)(n.h2,{id:"how-does-partial-set-security-work",children:"How does Partial Set Security work?"}),"\n",(0,t.jsx)(n.p,{children:"Partial Set Security allows a provider chain to share only a subset of its validator set with a consumer chain. This subset can be determined by the top N% validators by voting power, or by validators opting in to validate the consumer chain. Partial Set Security allows for flexible tradeoffs between security, decentralization, and the budget a consumer chain spends on rewards to validators."}),"\n",(0,t.jsxs)(n.p,{children:["See the ",(0,t.jsx)(n.a,{href:"/interchain-security/v4.2.0/features/partial-set-security",children:"Partial Set Security"})," section for more information."]}),"\n",(0,t.jsx)(n.h2,{id:"how-does-a-validator-know-which-consumers-chains-it-has-to-validate",children:"How does a validator know which consumers chains it has to validate?"}),"\n",(0,t.jsxs)(n.p,{children:["In order for a validator to keep track of all the chains it has to validate, the validator can use the\n",(0,t.jsxs)(n.a,{href:"/interchain-security/v4.2.0/validators/partial-set-security-for-validators#which-chains-does-a-validator-have-to-validate",children:[(0,t.jsx)(n.code,{children:"has-to-validate"})," query"]}),"."]}),"\n",(0,t.jsx)(n.h2,{id:"how-many-chains-can-a-validator-opt-in-to",children:"How many chains can a validator opt in to?"}),"\n",(0,t.jsxs)(n.p,{children:["There is ",(0,t.jsx)(n.strong,{children:"no"})," limit in the number of consumers chains a validator can choose to opt in to."]}),"\n",(0,t.jsx)(n.h2,{id:"can-validators-assign-a-consensus-keys-while-a-consumer-addition-proposal-is-in-voting-period",children:"Can validators assign a consensus keys while a consumer-addition proposal is in voting period?"}),"\n",(0,t.jsxs)(n.p,{children:["Yes, see the ",(0,t.jsx)(n.a,{href:"/interchain-security/v4.2.0/features/key-assignment",children:"Key Assignment Guide"})," for more information."]}),"\n",(0,t.jsx)(n.h2,{id:"can-validators-assign-a-consensus-key-during-the-voting-period-for-a-consumer-addition-proposal-if-they-are-not-in-the-top-n",children:"Can validators assign a consensus key during the voting period for a consumer-addition proposal if they are not in the top N?"}),"\n",(0,t.jsx)(n.p,{children:"Yes."}),"\n",(0,t.jsx)(n.h2,{id:"can-validators-opt-in-to-an-opt-in-or-top-n-chain-after-its-consumer-addition-proposal-voting-period-is-over-but-before-the-spawn-time",children:"Can validators opt in to an Opt-in or Top N chain after its consumer-addition proposal voting period is over but before the spawn time?"}),"\n",(0,t.jsx)(n.p,{children:"Yes."}),"\n",(0,t.jsx)(n.h2,{id:"can-validators-opt-in-to-an-opt-in-chain-after-the-spawn-time-if-nobody-else-opted-in",children:"Can validators opt in to an Opt-in chain after the spawn time if nobody else opted in?"}),"\n",(0,t.jsx)(n.p,{children:"No, the consumer chain will not be added if nobody opted in by the spawn time. At least one validator, regardless of its voting power, must opt in before the spawn time arrives in order for the chain can start."}),"\n",(0,t.jsx)(n.h2,{id:"can-all-validators-opt-out-of-an-opt-in-chain",children:"Can all validators opt out of an Opt-in chain?"}),"\n",(0,t.jsx)(n.p,{children:"Yes, the consumer chain will halt with an ERR CONSENSUS FAILURE error after the opt-out message for the last validator is received."}),"\n",(0,t.jsx)(n.h2,{id:"can-validators-set-a-commission-rate-for-chains-they-have-not-opted-in-to",children:"Can validators set a commission rate for chains they have not opted in to?"}),"\n",(0,t.jsx)(n.p,{children:"Yes, and this is useful for validators that are not in the top N% of the provider chain, but might move into the top N% in the future.\nBy setting the commission rate ahead of time, they can make sure that they immediately have a commission rate of their choosing as soon as they are in the top N%."})]})}function l(e={}){const{wrapper:n}={...(0,a.a)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>r,a:()=>s});var t=i(7294);const a={},o=t.createContext(a);function s(e){const n=t.useContext(o);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:s(e.components),t.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/8a86a05c.a622c0e8.js b/assets/js/8a86a05c.a622c0e8.js new file mode 100644 index 0000000000..2d0f2fff9b --- /dev/null +++ b/assets/js/8a86a05c.a622c0e8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5938],{8380:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>h,frontMatter:()=>a,metadata:()=>r,toc:()=>l});var t=i(5893),s=i(1151);const a={sidebar_position:3,title:"Onboarding Checklist"},o="Consumer Onboarding Checklist",r={id:"consumer-development/onboarding",title:"Onboarding Checklist",description:"The following checklists will aid in onboarding a new consumer chain to interchain security.",source:"@site/versioned_docs/version-v5.0.0/consumer-development/onboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/onboarding",permalink:"/interchain-security/v5.0.0/consumer-development/onboarding",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Onboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Consumer Chain Governance",permalink:"/interchain-security/v5.0.0/consumer-development/consumer-chain-governance"},next:{title:"Offboarding Checklist",permalink:"/interchain-security/v5.0.0/consumer-development/offboarding"}},c={},l=[{value:"1. Complete testing & integration",id:"1-complete-testing--integration",level:2},{value:"2. Create an Onboarding Repository",id:"2-create-an-onboarding-repository",level:2},{value:"3. Submit a Governance Proposal",id:"3-submit-a-governance-proposal",level:2},{value:"4. Launch",id:"4-launch",level:2}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",input:"input",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.a)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"consumer-onboarding-checklist",children:"Consumer Onboarding Checklist"}),"\n",(0,t.jsx)(n.p,{children:"The following checklists will aid in onboarding a new consumer chain to interchain security."}),"\n",(0,t.jsxs)(n.p,{children:["Additionally, you can check the ",(0,t.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/CONSUMER_LAUNCH_GUIDE.md",children:"testnet repo"})," for a comprehensive guide on preparing and launching consumer chains."]}),"\n",(0,t.jsx)(n.h2,{id:"1-complete-testing--integration",children:"1. Complete testing & integration"}),"\n",(0,t.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","test integration with gaia"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","test your protocol with supported relayer versions (minimum hermes 1.4.1)"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","reach out to the ICS team if you are facing issues"]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"2-create-an-onboarding-repository",children:"2. Create an Onboarding Repository"}),"\n",(0,t.jsx)(n.p,{children:"To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain."}),"\n",(0,t.jsx)(n.p,{children:"This should include (at minimum):"}),"\n",(0,t.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","genesis.json without CCV data (before the proposal passes)"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see ",(0,t.jsx)(n.a,{href:"/interchain-security/v5.0.0/consumer-development/consumer-genesis-transformation",children:"Transform Consumer Genesis"}),")"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","information about relevant seed/peer nodes you are running"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","relayer information (compatible versions)"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","copy of your governance proposal (as JSON)"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","a script showing how to start your chain and connect to peers (optional)"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable"]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["Example of such a repository can be found ",(0,t.jsx)(n.a,{href:"https://github.com/hyphacoop/ics-testnets/tree/main/game-of-chains-2022/sputnik",children:"here"}),"."]}),"\n",(0,t.jsx)(n.h2,{id:"3-submit-a-governance-proposal",children:"3. Submit a Governance Proposal"}),"\n",(0,t.jsxs)(n.p,{children:["Before you submit a ",(0,t.jsx)(n.code,{children:"ConsumerChainAddition"})," proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch.\nIf possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues."]}),"\n",(0,t.jsxs)(n.p,{children:["Additionally, reach out to the community via the ",(0,t.jsx)(n.a,{href:"https://forum.cosmos.network/",children:"forum"})," to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers."]}),"\n",(0,t.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","determine your chain's spawn time"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","determine consumer chain parameters to be put in the proposal"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","take note to include a link to your onboarding repository"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","describe the purpose and benefits of running your chain"]}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"Example of a consumer chain addition proposal."}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:'// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.\n// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.\n// It is recommended that spawn time occurs after the proposal end time.\n{\n // Title of the proposal\n "title": "Add consumer chain",\n // Description of the proposal\n // format the text as a .md file and include the file in your onboarding repository\n "description": ".md description of your chain and all other relevant information",\n // Proposed chain-id of the new consumer chain.\n // Must be unique from all other consumer chain ids of the executing provider chain.\n "chain_id": "newchain-1",\n // Initial height of new consumer chain.\n // For a completely new chain, this will be {0,1}.\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Hash of the consumer chain genesis state without the consumer CCV module genesis params.\n // It is used for off-chain confirmation of genesis.json validity by validators and other parties.\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n // Hash of the consumer chain binary that should be run by validators on chain initialization.\n // It is used for off-chain confirmation of binary validity by validators and other parties.\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n // Unbonding period for the consumer chain.\n // It should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n // IBC transfer packets will timeout after this interval elapses.\n "transfer_timeout_period": 1800000000000,\n // The fraction of tokens allocated to the consumer redistribution address during distribution events.\n // The fraction is a string representing a decimal number. For example "0.75" would represent 75%.\n // The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.\n "consumer_redistribution_fraction": "0.75",\n // BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.\n // eg. send rewards to the provider every 1000 blocks\n "blocks_per_distribution_transmission": 1000,\n // The number of historical info entries to persist in store.\n // This param is a part of the cosmos sdk staking module. In the case of\n // a ccv enabled consumer chain, the ccv module acts as the staking module.\n "historical_entries": 10000,\n // The ID of a token transfer channel used for the Reward Distribution\n\t// sub-protocol. If DistributionTransmissionChannel == "", a new transfer\n\t// channel is created on top of the same connection as the CCV channel.\n\t// Note that transfer_channel_id is the ID of the channel end on the consumer chain.\n // it is most relevant for chains performing a standalone to consumer changeover\n // in order to maintain the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123"\n}\n'})}),"\n",(0,t.jsx)(n.h2,{id:"4-launch",children:"4. Launch"}),"\n",(0,t.jsx)(n.p,{children:"The consumer chain starts after at least 66.67% of all provider's voting power comes online. The consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer"}),"\n",(0,t.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","provide a repo with onboarding instructions for validators (it should already be listed in the proposal)"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","genesis.json with ccv data populated (MUST contain the initial validator set)"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)"]}),"\n",(0,t.jsxs)(n.li,{className:"task-list-item",children:[(0,t.jsx)(n.input,{type:"checkbox",disabled:!0})," ","have a block explorer in place to track chain activity & health"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>r,a:()=>o});var t=i(7294);const s={},a=t.createContext(s);function o(e){const n=t.useContext(a);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),t.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/8d3b6fe8.e2b00793.js b/assets/js/8d3b6fe8.e2b00793.js new file mode 100644 index 0000000000..25e6030a63 --- /dev/null +++ b/assets/js/8d3b6fe8.e2b00793.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1163],{6216:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>m,frontMatter:()=>s,metadata:()=>i,toc:()=>h});var o=t(5893),a=t(1151);const s={sidebar_position:2},r="Consumer Chain Governance",i={id:"consumer-development/consumer-chain-governance",title:"Consumer Chain Governance",description:'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.',source:"@site/versioned_docs/version-v4.2.0-docs/consumer-development/consumer-chain-governance.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-chain-governance",permalink:"/interchain-security/v4.2.0/consumer-development/consumer-chain-governance",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/v4.2.0/consumer-development/app-integration"},next:{title:"Onboarding Checklist",permalink:"/interchain-security/v4.2.0/consumer-development/onboarding"}},c={},h=[{value:"Democracy module",id:"democracy-module",level:2},{value:"CosmWasm",id:"cosmwasm",level:2},{value:"The Whitelist",id:"the-whitelist",level:2}];function l(e){const n={a:"a",h1:"h1",h2:"h2",p:"p",...(0,a.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"consumer-chain-governance",children:"Consumer Chain Governance"}),"\n",(0,o.jsx)(n.p,{children:'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.'}),"\n",(0,o.jsx)(n.h2,{id:"democracy-module",children:"Democracy module"}),"\n",(0,o.jsx)(n.p,{children:"The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy."}),"\n",(0,o.jsx)(n.p,{children:"Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus."}),"\n",(0,o.jsxs)(n.p,{children:["For an example, see the ",(0,o.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy",children:"Democracy Consumer"})]}),"\n",(0,o.jsx)(n.h2,{id:"cosmwasm",children:"CosmWasm"}),"\n",(0,o.jsx)(n.p,{children:"There are several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain."}),"\n",(0,o.jsxs)(n.p,{children:["For an example, see ",(0,o.jsx)(n.a,{href:"https://github.com/neutron-org/neutron/",children:"Neutron"}),"."]}),"\n",(0,o.jsx)(n.h2,{id:"the-whitelist",children:"The Whitelist"}),"\n",(0,o.jsxs)(n.p,{children:["Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see ",(0,o.jsx)(n.a,{href:"https://github.com/neutron-org/neutron/blob/main/app/proposals_allowlisting.go",children:"Neutron's"})," whitelist."]})]})}function m(e={}){const{wrapper:n}={...(0,a.a)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>i,a:()=>r});var o=t(7294);const a={},s=o.createContext(a);function r(e){const n=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:r(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/903c2771.18b9a08b.js b/assets/js/903c2771.18b9a08b.js new file mode 100644 index 0000000000..4db8f2a766 --- /dev/null +++ b/assets/js/903c2771.18b9a08b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6054],{461:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>s,metadata:()=>r,toc:()=>d});var n=o(5893),i=o(1151);const s={sidebar_position:10,title:"Soft Opt-Out"},a=void 0,r={id:"adrs/adr-009-soft-opt-out",title:"Soft Opt-Out",description:"ADR 009: Soft Opt-Out",source:"@site/docs/adrs/adr-009-soft-opt-out.md",sourceDirName:"adrs",slug:"/adrs/adr-009-soft-opt-out",permalink:"/interchain-security/adrs/adr-009-soft-opt-out",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:10,frontMatter:{sidebar_position:10,title:"Soft Opt-Out"},sidebar:"tutorialSidebar",previous:{title:"Throttle with retries",permalink:"/interchain-security/adrs/adr-008-throttle-retries"},next:{title:"Standalone to Consumer Changeover",permalink:"/interchain-security/adrs/adr-010-standalone-changeover"}},l={},d=[{value:"ADR 009: Soft Opt-Out",id:"adr-009-soft-opt-out",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function c(e){const t={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,i.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h2,{id:"adr-009-soft-opt-out",children:"ADR 009: Soft Opt-Out"}),"\n",(0,n.jsx)(t.h2,{id:"changelog",children:"Changelog"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"6/13/23: Initial draft of ADR. Feature already implemented and in production."}),"\n",(0,n.jsx)(t.li,{children:"6/19/24: Change status to deprecated"}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"status",children:"Status"}),"\n",(0,n.jsxs)(t.p,{children:["Deprecated\nDeprecated by ",(0,n.jsx)(t.a,{href:"/interchain-security/adrs/adr-015-partial-set-security",children:"Partial Set Security"})]}),"\n",(0,n.jsx)(t.h2,{id:"context",children:"Context"}),"\n",(0,n.jsxs)(t.p,{children:["Some small validators may not have the resources needed to validate all consumer chains. Therefore a need exists to allow the bottom ",(0,n.jsx)(t.code,{children:"x%"})," of validators to opt-out of validating a consumer chain. Meaning downtime infractions for these validators are dropped without ever reaching the provider."]}),"\n",(0,n.jsx)(t.p,{children:"This document specifies a modification to the ccv protocol which allows the bottom x% of the validator set by power to opt out of validating consumer chains without being jailed or otherwise punished for it. The feature is implemented with entirely consumer-side code."}),"\n",(0,n.jsx)(t.h2,{id:"decision",children:"Decision"}),"\n",(0,n.jsxs)(t.p,{children:["A consumer param exists, known as ",(0,n.jsx)(t.code,{children:"SoftOptOutThreshold"}),", which is a string decimal in the range of [0, 0.2], that determines the portion of validators which are allowed to opt out of validating that specific consumer."]}),"\n",(0,n.jsxs)(t.p,{children:["In every consumer beginblocker, a function is ran which determines the so called ",(0,n.jsx)(t.em,{children:"smallest non opt-out voting power"}),". Validators with voting power greater than or equal to this value must validate the consumer chain, while validators below this value may opt out of validating the consumer chain."]}),"\n",(0,n.jsxs)(t.p,{children:["The smallest non opt-out voting power is recomputed every beginblocker in ",(0,n.jsx)(t.code,{children:"UpdateSmallestNonOptOutPower()"}),". In a nutshell, the method obtains the total voting power of the consumer, iterates through the full valset (ordered power ascending) keeping track of a power sum, and when ",(0,n.jsx)(t.code,{children:"powerSum / totalPower > SoftOptOutThreshold"}),", the ",(0,n.jsx)(t.code,{children:"SmallestNonOptOutPower"})," is found and persisted."]}),"\n",(0,n.jsxs)(t.p,{children:["Then, whenever the ",(0,n.jsx)(t.code,{children:"Slash()"})," interface is executed on the consumer, if the voting power of the relevant validator being slashed is less than ",(0,n.jsx)(t.code,{children:"SmallestNonOptOutPower"})," for that block, the slash request is dropped and never sent to the provider."]}),"\n",(0,n.jsx)(t.h2,{id:"consequences",children:"Consequences"}),"\n",(0,n.jsx)(t.h3,{id:"positive",children:"Positive"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"Small validators can opt out of validating specific consumers without being punished for it."}),"\n"]}),"\n",(0,n.jsx)(t.h3,{id:"negative",children:"Negative"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["The bottom ",(0,n.jsx)(t.code,{children:"x%"})," is still part of the total voting power of the consumer chain. This means that if the soft opt-out threshold is set to ",(0,n.jsx)(t.code,{children:"10%"})," for example, and every validator in the bottom ",(0,n.jsx)(t.code,{children:"10%"})," opts out from validating the consumer, then a ",(0,n.jsx)(t.code,{children:"24%"})," downtime of the remaining voting power would halt the chain. This may be especially problematic during consumer upgrades."]}),"\n",(0,n.jsxs)(t.li,{children:["In nominal scenarios, consumers with soft opt out enabled will be constructing slash packets for small vals, which may be dropped. This is wasted computation, but necessary to keep implementation simple. Note that the sdk's ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/d3f09c222243bb3da3464969f0366330dcb977a8/x/slashing/keeper/infractions.go#L75",children:"full downtime logic"})," is always executed on the consumer, which can be computationally expensive and slow down certain blocks."]}),"\n",(0,n.jsx)(t.li,{children:"In a consumer chain, when a validator that has opted out becomes the proposer, there will naturally be no proposal made and validators would need to move to the next consensus round for the same height to reach a decision. As a result, we would need more time to finalize blocks on a consumer chain."}),"\n"]}),"\n",(0,n.jsx)(t.h3,{id:"neutral",children:"Neutral"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"Validators in the bottom of the valset who don't have to validate, may receive large delegation(s) which suddenly boost the validator to the subset that has to validate. This may catch the validator off guard."}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"references",children:"References"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["Original issue with some napkin math ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/issues/784",children:"#784"})]}),"\n"]})]})}function h(e={}){const{wrapper:t}={...(0,i.a)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(c,{...e})}):c(e)}},1151:(e,t,o)=>{o.d(t,{Z:()=>r,a:()=>a});var n=o(7294);const i={},s=n.createContext(i);function a(e){const t=n.useContext(s);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),n.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/935f2afb.78bd90f6.js b/assets/js/935f2afb.78bd90f6.js new file mode 100644 index 0000000000..78ff237bc2 --- /dev/null +++ b/assets/js/935f2afb.78bd90f6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[53],{1109:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"current","label":"main","banner":"unreleased","badge":true,"noIndex":false,"className":"docs-version-current","isLast":false,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Interchain Security Docs","href":"/interchain-security/","docId":"index","unlisted":false},{"type":"category","label":"Introduction","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/introduction/overview","docId":"introduction/overview","unlisted":false},{"type":"link","label":"Terminology","href":"/interchain-security/introduction/terminology","docId":"introduction/terminology","unlisted":false},{"type":"link","label":"Interchain Security Parameters","href":"/interchain-security/introduction/params","docId":"introduction/params","unlisted":false},{"type":"link","label":"Technical Specification","href":"/interchain-security/introduction/technical-specification","docId":"introduction/technical-specification","unlisted":false}]},{"type":"category","label":"Upgrading","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Upgrading to ICS v5.0.0","href":"/interchain-security/upgrading/migrate_v4_v5","docId":"upgrading/migrate_v4_v5","unlisted":false}]},{"type":"category","label":"Features","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Key Assignment","href":"/interchain-security/features/key-assignment","docId":"features/key-assignment","unlisted":false},{"type":"link","label":"Reward Distribution","href":"/interchain-security/features/reward-distribution","docId":"features/reward-distribution","unlisted":false},{"type":"link","label":"ICS Provider Proposals","href":"/interchain-security/features/proposals","docId":"features/proposals","unlisted":false},{"type":"link","label":"Consumer Initiated Slashing","href":"/interchain-security/features/slashing","docId":"features/slashing","unlisted":false},{"type":"link","label":"Democracy modules","href":"/interchain-security/features/democracy-modules","docId":"features/democracy-modules","unlisted":false},{"type":"link","label":"Partial Set Security","href":"/interchain-security/features/partial-set-security","docId":"features/partial-set-security","unlisted":false},{"type":"link","label":"Power Shaping","href":"/interchain-security/features/power-shaping","docId":"features/power-shaping","unlisted":false}]},{"type":"category","label":"Consumer Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Developing an ICS consumer chain","href":"/interchain-security/consumer-development/app-integration","docId":"consumer-development/app-integration","unlisted":false},{"type":"link","label":"Consumer Chain Governance","href":"/interchain-security/consumer-development/consumer-chain-governance","docId":"consumer-development/consumer-chain-governance","unlisted":false},{"type":"link","label":"Onboarding Checklist","href":"/interchain-security/consumer-development/onboarding","docId":"consumer-development/onboarding","unlisted":false},{"type":"link","label":"Offboarding Checklist","href":"/interchain-security/consumer-development/offboarding","docId":"consumer-development/offboarding","unlisted":false},{"type":"link","label":"Changeover Procedure","href":"/interchain-security/consumer-development/changeover-procedure","docId":"consumer-development/changeover-procedure","unlisted":false},{"type":"link","label":"Consumer Genesis Transformation","href":"/interchain-security/consumer-development/consumer-genesis-transformation","docId":"consumer-development/consumer-genesis-transformation","unlisted":false}]},{"type":"category","label":"Validators Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/validators/overview","docId":"validators/overview","unlisted":false},{"type":"link","label":"Joining Interchain Security testnet","href":"/interchain-security/validators/joining-testnet","docId":"validators/joining-testnet","unlisted":false},{"type":"link","label":"Consumer chain validator rewards","href":"/interchain-security/validators/withdraw_rewards","docId":"validators/withdraw_rewards","unlisted":false},{"type":"link","label":"Validator Instructions for Changeover Procedure","href":"/interchain-security/validators/changeover-procedure","docId":"validators/changeover-procedure","unlisted":false},{"type":"link","label":"Joining Neutron","href":"/interchain-security/validators/joining-neutron","docId":"validators/joining-neutron","unlisted":false},{"type":"link","label":"Joining Stride","href":"/interchain-security/validators/joining-stride","docId":"validators/joining-stride","unlisted":false},{"type":"link","label":"Partial Set Security","href":"/interchain-security/validators/partial-set-security-for-validators","docId":"validators/partial-set-security-for-validators","unlisted":false}]},{"type":"link","label":"Frequently Asked Questions","href":"/interchain-security/faq","docId":"frequently-asked-questions","unlisted":false},{"type":"category","label":"ADRs","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/adrs/intro","docId":"adrs/intro","unlisted":false},{"type":"link","label":"Denom DOS fixes","href":"/interchain-security/adrs/adr-004-denom-dos-fixes","docId":"adrs/adr-004-denom-dos-fixes","unlisted":false},{"type":"link","label":"Pause validator unbonding during equivocation proposal","href":"/interchain-security/adrs/adr-007-pause-unbonding-on-eqv-prop","docId":"adrs/adr-007-pause-unbonding-on-eqv-prop","unlisted":false},{"type":"link","label":"Key Assignment","href":"/interchain-security/adrs/adr-001-key-assignment","docId":"adrs/adr-001-key-assignment","unlisted":false},{"type":"link","label":"Jail Throttling","href":"/interchain-security/adrs/adr-002-throttle","docId":"adrs/adr-002-throttle","unlisted":false},{"type":"link","label":"Equivocation governance proposal","href":"/interchain-security/adrs/adr-003-equivocation-gov-proposal","docId":"adrs/adr-003-equivocation-gov-proposal","unlisted":false},{"type":"link","label":"Cryptographic verification of equivocation evidence","href":"/interchain-security/adrs/adr-005-cryptographic-equivocation-verification","docId":"adrs/adr-005-cryptographic-equivocation-verification","unlisted":false},{"type":"link","label":"Throttle with retries","href":"/interchain-security/adrs/adr-008-throttle-retries","docId":"adrs/adr-008-throttle-retries","unlisted":false},{"type":"link","label":"Soft Opt-Out","href":"/interchain-security/adrs/adr-009-soft-opt-out","docId":"adrs/adr-009-soft-opt-out","unlisted":false},{"type":"link","label":"Standalone to Consumer Changeover","href":"/interchain-security/adrs/adr-010-standalone-changeover","docId":"adrs/adr-010-standalone-changeover","unlisted":false},{"type":"link","label":"Improving testing and increasing confidence","href":"/interchain-security/adrs/adr-011-improving-test-confidence","docId":"adrs/adr-011-improving-test-confidence","unlisted":false},{"type":"link","label":"Separate Releasing","href":"/interchain-security/adrs/adr-012-separate-releasing","docId":"adrs/adr-012-separate-releasing","unlisted":false},{"type":"link","label":"Slashing on the provider for consumer equivocation","href":"/interchain-security/adrs/adr-013-equivocation-slashing","docId":"adrs/adr-013-equivocation-slashing","unlisted":false},{"type":"link","label":"Epochs","href":"/interchain-security/adrs/adr-014-epochs","docId":"adrs/adr-014-epochs","unlisted":false},{"type":"link","label":"Partial Set Security","href":"/interchain-security/adrs/adr-015-partial-set-security","docId":"adrs/adr-015-partial-set-security","unlisted":false},{"type":"link","label":"Security aggregation","href":"/interchain-security/adrs/adr-016-securityaggregation","docId":"adrs/adr-016-securityaggregation","unlisted":false},{"type":"link","label":"ICS with Inactive Provider Validators","href":"/interchain-security/adrs/adr-017-allowing-inactive-validators","docId":"adrs/adr-017-allowing-inactive-validators","unlisted":false}]}]},"docs":{"adrs/adr-001-key-assignment":{"id":"adrs/adr-001-key-assignment","title":"Key Assignment","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-002-throttle":{"id":"adrs/adr-002-throttle","title":"Jail Throttling","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-003-equivocation-gov-proposal":{"id":"adrs/adr-003-equivocation-gov-proposal","title":"Equivocation governance proposal","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-004-denom-dos-fixes":{"id":"adrs/adr-004-denom-dos-fixes","title":"Denom DOS fixes","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-005-cryptographic-equivocation-verification":{"id":"adrs/adr-005-cryptographic-equivocation-verification","title":"Cryptographic verification of equivocation evidence","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-007-pause-unbonding-on-eqv-prop":{"id":"adrs/adr-007-pause-unbonding-on-eqv-prop","title":"Pause validator unbonding during equivocation proposal","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-008-throttle-retries":{"id":"adrs/adr-008-throttle-retries","title":"Throttle with retries","description":"ADR 008: Throttle with retries","sidebar":"tutorialSidebar"},"adrs/adr-009-soft-opt-out":{"id":"adrs/adr-009-soft-opt-out","title":"Soft Opt-Out","description":"ADR 009: Soft Opt-Out","sidebar":"tutorialSidebar"},"adrs/adr-010-standalone-changeover":{"id":"adrs/adr-010-standalone-changeover","title":"Standalone to Consumer Changeover","description":"ADR 010: Standalone to Consumer Changeover","sidebar":"tutorialSidebar"},"adrs/adr-011-improving-test-confidence":{"id":"adrs/adr-011-improving-test-confidence","title":"Improving testing and increasing confidence","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-012-separate-releasing":{"id":"adrs/adr-012-separate-releasing","title":"Separate Releasing","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-013-equivocation-slashing":{"id":"adrs/adr-013-equivocation-slashing","title":"Slashing on the provider for consumer equivocation","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-014-epochs":{"id":"adrs/adr-014-epochs","title":"Epochs","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-015-partial-set-security":{"id":"adrs/adr-015-partial-set-security","title":"Partial Set Security","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-016-securityaggregation":{"id":"adrs/adr-016-securityaggregation","title":"Security aggregation","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-017-allowing-inactive-validators":{"id":"adrs/adr-017-allowing-inactive-validators","title":"ICS with Inactive Provider Validators","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/intro":{"id":"adrs/intro","title":"Overview","description":"This is a location to record all high-level architecture decisions in the Interchain Security project.","sidebar":"tutorialSidebar"},"consumer-development/app-integration":{"id":"consumer-development/app-integration","title":"Developing an ICS consumer chain","description":"When developing an ICS consumer chain, besides just focusing on your chain\'s logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.","sidebar":"tutorialSidebar"},"consumer-development/changeover-procedure":{"id":"consumer-development/changeover-procedure","title":"Changeover Procedure","description":"Chains that were not initially launched as consumers of Interchain Security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.","sidebar":"tutorialSidebar"},"consumer-development/consumer-chain-governance":{"id":"consumer-development/consumer-chain-governance","title":"Consumer Chain Governance","description":"Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the \\"Whitelist\\" section below.","sidebar":"tutorialSidebar"},"consumer-development/consumer-genesis-transformation":{"id":"consumer-development/consumer-genesis-transformation","title":"Consumer Genesis Transformation","description":"Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentation on Onboarding and Changeover).","sidebar":"tutorialSidebar"},"consumer-development/offboarding":{"id":"consumer-development/offboarding","title":"Offboarding Checklist","description":"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).","sidebar":"tutorialSidebar"},"consumer-development/onboarding":{"id":"consumer-development/onboarding","title":"Onboarding Checklist","description":"The following checklists will aid in onboarding a new consumer chain to interchain security.","sidebar":"tutorialSidebar"},"features/democracy-modules":{"id":"features/democracy-modules","title":"Democracy modules","description":"This section is relevant for chains transitioning from a standalone chain and new consumer chains that require some functionality from the x/staking module.","sidebar":"tutorialSidebar"},"features/key-assignment":{"id":"features/key-assignment","title":"Key Assignment","description":"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.","sidebar":"tutorialSidebar"},"features/partial-set-security":{"id":"features/partial-set-security","title":"Partial Set Security","description":"Partial Set Security (PSS) allows consumer chains to leverage only a subset of validators from the provider chain, which offers more flexibility than the traditional Replicated Security model. By introducing the top_N parameter, each consumer chain can choose the extent of security needed:","sidebar":"tutorialSidebar"},"features/power-shaping":{"id":"features/power-shaping","title":"Power Shaping","description":"To give consumer chains more flexibility in choosing their validator set, Interchain Security offers","sidebar":"tutorialSidebar"},"features/proposals":{"id":"features/proposals","title":"ICS Provider Proposals","description":"Interchain security module introduces new proposal types to the provider.","sidebar":"tutorialSidebar"},"features/reward-distribution":{"id":"features/reward-distribution","title":"Reward Distribution","description":"Sending and distributing rewards from consumer chains to the provider chain is handled by the Reward Distribution sub-protocol.","sidebar":"tutorialSidebar"},"features/slashing":{"id":"features/slashing","title":"Consumer Initiated Slashing","description":"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the Interchain Security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.","sidebar":"tutorialSidebar"},"frequently-asked-questions":{"id":"frequently-asked-questions","title":"Frequently Asked Questions","description":"What is a consumer chain?","sidebar":"tutorialSidebar"},"index":{"id":"index","title":"Interchain Security Docs","description":"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.","sidebar":"tutorialSidebar"},"introduction/overview":{"id":"introduction/overview","title":"Overview","description":"Interchain Security is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.","sidebar":"tutorialSidebar"},"introduction/params":{"id":"introduction/params","title":"Interchain Security Parameters","description":"The parameters necessary for Interchain Security (ICS) are defined in","sidebar":"tutorialSidebar"},"introduction/technical-specification":{"id":"introduction/technical-specification","title":"Technical Specification","description":"For a technical deep dive into the replicated security protocol, see the specification.","sidebar":"tutorialSidebar"},"introduction/terminology":{"id":"introduction/terminology","title":"Terminology","description":"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.","sidebar":"tutorialSidebar"},"upgrading/migrate_v4_v5":{"id":"upgrading/migrate_v4_v5","title":"Upgrading to ICS v5.0.0","description":"This ICS version uses cosmos-sdk v0.50.x and ibc-go v8.x.","sidebar":"tutorialSidebar"},"validators/changeover-procedure":{"id":"validators/changeover-procedure","title":"Validator Instructions for Changeover Procedure","description":"More details available in Changeover Procedure documentation.","sidebar":"tutorialSidebar"},"validators/joining-neutron":{"id":"validators/joining-neutron","title":"Joining Neutron","description":"Neutron is the first consumer chain to implement ICS.","sidebar":"tutorialSidebar"},"validators/joining-stride":{"id":"validators/joining-stride","title":"Joining Stride","description":"Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.","sidebar":"tutorialSidebar"},"validators/joining-testnet":{"id":"validators/joining-testnet","title":"Joining Interchain Security testnet","description":"Introduction","sidebar":"tutorialSidebar"},"validators/overview":{"id":"validators/overview","title":"Overview","description":"We advise that you join the Interchain Security testnet to gain hands-on experience with running consumer chains.","sidebar":"tutorialSidebar"},"validators/partial-set-security-for-validators":{"id":"validators/partial-set-security-for-validators","title":"Partial Set Security","description":"Partial Set Security allows consumer chains to join as Opt-In or Top N.","sidebar":"tutorialSidebar"},"validators/withdraw_rewards":{"id":"validators/withdraw_rewards","title":"Consumer chain validator rewards","description":"A validator can only receive rewards from a consumer chain if the validator has been validating the consumer chain","sidebar":"tutorialSidebar"}}}')}}]); \ No newline at end of file diff --git a/assets/js/94b74966.577b76d7.js b/assets/js/94b74966.577b76d7.js new file mode 100644 index 0000000000..ada9cf20fc --- /dev/null +++ b/assets/js/94b74966.577b76d7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6673],{2546:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>r,toc:()=>d});var s=i(5893),t=i(1151);const o={sidebar_position:5},a="Changeover Procedure",r={id:"consumer-development/changeover-procedure",title:"Changeover Procedure",description:"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.",source:"@site/versioned_docs/version-v4.2.0-docs/consumer-development/changeover-procedure.md",sourceDirName:"consumer-development",slug:"/consumer-development/changeover-procedure",permalink:"/interchain-security/v4.2.0/consumer-development/changeover-procedure",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Offboarding Checklist",permalink:"/interchain-security/v4.2.0/consumer-development/offboarding"},next:{title:"Consumer Genesis Transformation",permalink:"/interchain-security/v4.2.0/consumer-development/consumer-genesis-transformation"}},c={},d=[{value:"Overview",id:"overview",level:2},{value:"1. ConsumerAddition proposal submitted to the <code>provider</code> chain",id:"1-consumeraddition-proposal-submitted-to-the-provider-chain",level:3},{value:"2. upgrade proposal on standalone chain",id:"2-upgrade-proposal-on-standalone-chain",level:3},{value:"3. spawn time is reached",id:"3-spawn-time-is-reached",level:3},{value:"4. standalone chain upgrade",id:"4-standalone-chain-upgrade",level:3},{value:"Notes",id:"notes",level:4},{value:"Onboarding Checklist",id:"onboarding-checklist",level:2},{value:"1. Complete testing & integration",id:"1-complete-testing--integration",level:2},{value:"2. Create an Onboarding Repository",id:"2-create-an-onboarding-repository",level:2},{value:"3. Submit a ConsumerChainAddition Governance Proposal to the provider",id:"3-submit-a-consumerchainaddition-governance-proposal-to-the-provider",level:2},{value:"3. Submit an Upgrade Proposal & Prepare for Changeover",id:"3-submit-an-upgrade-proposal--prepare-for-changeover",level:2},{value:"4. Upgrade time \ud83d\ude80",id:"4-upgrade-time-",level:2}];function l(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",input:"input",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"changeover-procedure",children:"Changeover Procedure"}),"\n",(0,s.jsxs)(n.p,{children:["Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the ",(0,s.jsx)(n.strong,{children:"changeover procedure"})," and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain."]}),"\n",(0,s.jsx)(n.p,{children:"The relevant protocol specifications are available below:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md#channel-initialization-existing-chains",children:"ICS-28 with existing chains"}),"."]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-010-standalone-changeover",children:"ADR in ICS repo"})}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"overview",children:"Overview"}),"\n",(0,s.jsx)(n.p,{children:"Standalone to consumer changeover procedure can roughly be separated into 4 parts:"}),"\n",(0,s.jsxs)(n.h3,{id:"1-consumeraddition-proposal-submitted-to-the-provider-chain",children:["1. ConsumerAddition proposal submitted to the ",(0,s.jsx)(n.code,{children:"provider"})," chain"]}),"\n",(0,s.jsx)(n.p,{children:'The proposal is equivalent to the "normal" ConsumerAddition proposal submitted by new consumer chains.'}),"\n",(0,s.jsx)(n.p,{children:"However, here are the most important notes and differences between a new consumer chain and a standalone chain performing a changeover:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"chain_id"})," must be equal to the standalone chain id"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"initial_height"})," field has additional rules to abide by:"]}),"\n"]}),"\n",(0,s.jsxs)(n.admonition,{type:"caution",children:[(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:'{\n...\n "initial_height" : {\n // must correspond to current revision number of standalone chain\n // e.g. stride-1 => "revision_number": 1\n "revision_number": 1,\n\n // must correspond to a height that is at least 1 block after the upgrade\n // that will add the `consumer` module to the standalone chain\n // e.g. "upgrade_height": 100 => "revision_height": 101\n "revision_height": 1,\n },\n...\n}\n'})}),(0,s.jsx)(n.p,{children:"RevisionNumber: 0, RevisionHeight: 111"})]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"genesis_hash"})," can be safely ignored because the chain is already running. A hash of the standalone chain's initial genesis may be used"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"binary_hash"})," may not be available ahead of time. All chains performing the changeover go through rigorous testing - if bugs are caught and fixed the hash listed in the proposal may not be the most recent one."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"spawn_time"})," listed in the proposal MUST be before the ",(0,s.jsx)(n.code,{children:"upgrade_height"})," listed in the upgrade proposal on the standalone chain."]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.admonition,{type:"caution",children:(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"spawn_time"})," must occur before the ",(0,s.jsx)(n.code,{children:"upgrade_height"})," on the standalone chain is reached because the ",(0,s.jsx)(n.code,{children:"provider"})," chain must generate the ",(0,s.jsx)(n.code,{children:"ConsumerGenesis"})," that contains the ",(0,s.jsx)(n.strong,{children:"validator set"})," that will be used after the changeover."]})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"unbonding_period"})," must correspond to the value used on the standalone chain. Otherwise, the clients used for the ccv protocol may be incorrectly initialized."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"distribution_transmission_channel"})," ",(0,s.jsx)(n.strong,{children:"should be set"}),"."]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.admonition,{type:"note",children:[(0,s.jsxs)(n.p,{children:["Populating ",(0,s.jsx)(n.code,{children:"distribution_transmission_channel"})," will enable the standalone chain to reuse one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ",(0,s.jsx)(n.code,{children:"ibc denom"})," that may already be in use."]}),(0,s.jsx)(n.p,{children:"If the parameter is not set, a new channel will be created."})]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"ccv_timeout_period"})," has no important notes"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"transfer_timeout_period"})," has no important notes"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"consumer_redistribution_fraction"})," has no important notes"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"blocks_per_distribution_transmission"})," has no important notes"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"historical_entries"})," has no important notes"]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"2-upgrade-proposal-on-standalone-chain",children:"2. upgrade proposal on standalone chain"}),"\n",(0,s.jsxs)(n.p,{children:["The standalone chain creates an upgrade proposal to include the ",(0,s.jsx)(n.code,{children:"interchain-security/x/ccv/consumer"})," module."]}),"\n",(0,s.jsx)(n.admonition,{type:"caution",children:(0,s.jsxs)(n.p,{children:["The upgrade height in the proposal should correspond to a height that is after the ",(0,s.jsx)(n.code,{children:"spawn_time"})," in the consumer addition proposal submitted to the ",(0,s.jsx)(n.code,{children:"provider"})," chain."]})}),"\n",(0,s.jsx)(n.p,{children:"Otherwise, the upgrade is indistinguishable from a regular on-chain upgrade proposal."}),"\n",(0,s.jsx)(n.h3,{id:"3-spawn-time-is-reached",children:"3. spawn time is reached"}),"\n",(0,s.jsxs)(n.p,{children:["When the ",(0,s.jsx)(n.code,{children:"spawn_time"})," is reached on the ",(0,s.jsx)(n.code,{children:"provider"})," it will generate a ",(0,s.jsx)(n.code,{children:"ConsumerGenesis"})," that contains the validator set that will supersede the ",(0,s.jsx)(n.code,{children:"standalone"})," validator set."]}),"\n",(0,s.jsxs)(n.p,{children:["This ",(0,s.jsx)(n.code,{children:"ConsumerGenesis"})," must be available on the standalone chain during the on-chain upgrade."]}),"\n",(0,s.jsx)(n.h3,{id:"4-standalone-chain-upgrade",children:"4. standalone chain upgrade"}),"\n",(0,s.jsxs)(n.p,{children:["Performing the on-chain upgrade on the standalone chain will add the ",(0,s.jsx)(n.code,{children:"ccv/consumer"})," module and allow the chain to become a ",(0,s.jsx)(n.code,{children:"consumer"})," of replicated security."]}),"\n",(0,s.jsxs)(n.admonition,{type:"caution",children:[(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"ConsumerGenesis"})," must be exported to a file and placed in the correct folder on the standalone chain before the upgrade."]}),(0,s.jsx)(n.p,{children:"The file must be placed at the exact specified location, otherwise the upgrade will not be executed correctly."}),(0,s.jsxs)(n.p,{children:["Usually the file is placed in ",(0,s.jsx)(n.code,{children:"$NODE_HOME/config"}),", but the file name and the exact directory is dictated by the upgrade code on the ",(0,s.jsx)(n.code,{children:"standalone"})," chain."]}),(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["please check exact instructions provided by the ",(0,s.jsx)(n.code,{children:"standalone"})," chain team"]}),"\n"]})]}),"\n",(0,s.jsxs)(n.p,{children:["After the ",(0,s.jsx)(n.code,{children:"genesis.json"})," file has been made available, the process is equivalent to a normal on-chain upgrade. The standalone validator set will sign the next couple of blocks before transferring control to ",(0,s.jsx)(n.code,{children:"provider"})," validator set."]}),"\n",(0,s.jsxs)(n.p,{children:["The standalone validator set can still be slashed for any infractions if evidence is submitted within the ",(0,s.jsx)(n.code,{children:"unboding_period"}),"."]}),"\n",(0,s.jsx)(n.h4,{id:"notes",children:"Notes"}),"\n",(0,s.jsx)(n.p,{children:"The changeover procedure may be updated in the future to create a seamless way of providing the validator set information to the standalone chain."}),"\n",(0,s.jsx)(n.h2,{id:"onboarding-checklist",children:"Onboarding Checklist"}),"\n",(0,s.jsxs)(n.p,{children:["This onboarding checklist is slightly different from the one under ",(0,s.jsx)(n.a,{href:"/interchain-security/v4.2.0/consumer-development/onboarding",children:"Onboarding"})]}),"\n",(0,s.jsxs)(n.p,{children:["Additionally, you can check the ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/CONSUMER_LAUNCH_GUIDE.md",children:"testnet repo"})," for a comprehensive guide on preparing and launching consumer chains."]}),"\n",(0,s.jsx)(n.h2,{id:"1-complete-testing--integration",children:"1. Complete testing & integration"}),"\n",(0,s.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","test integration with gaia"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","test your protocol with supported relayer versions (minimum hermes 1.4.1)"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","test the changeover procedure"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","reach out to the ICS team if you are facing issues"]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"2-create-an-onboarding-repository",children:"2. Create an Onboarding Repository"}),"\n",(0,s.jsx)(n.p,{children:"To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain."}),"\n",(0,s.jsx)(n.p,{children:"This should include (at minimum):"}),"\n",(0,s.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see ",(0,s.jsx)(n.a,{href:"/interchain-security/v4.2.0/consumer-development/consumer-genesis-transformation",children:"Transform Consumer Genesis"}),")"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","information about relevant seed/peer nodes you are running"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","relayer information (compatible versions)"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","copy of your governance proposal (as JSON)"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","a script showing how to start your chain and connect to peers (optional)"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable"]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["Example of such a repository can be found ",(0,s.jsx)(n.a,{href:"https://github.com/hyphacoop/ics-testnets/tree/main/game-of-chains-2022/sputnik",children:"here"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"3-submit-a-consumerchainaddition-governance-proposal-to-the-provider",children:"3. Submit a ConsumerChainAddition Governance Proposal to the provider"}),"\n",(0,s.jsxs)(n.p,{children:["Before you submit a ",(0,s.jsx)(n.code,{children:"ConsumerChainAddition"})," proposal, please provide a ",(0,s.jsx)(n.code,{children:"spawn_time"})," that is ",(0,s.jsx)(n.strong,{children:"before"})," the ",(0,s.jsx)(n.code,{children:"upgrade_height"})," of the upgrade that will introduce the ",(0,s.jsx)(n.code,{children:"ccv module"})," to your chain."]}),"\n",(0,s.jsx)(n.admonition,{type:"danger",children:(0,s.jsxs)(n.p,{children:["If the ",(0,s.jsx)(n.code,{children:"spawn_time"})," happens after your ",(0,s.jsx)(n.code,{children:"upgrade_height"})," the provider will not be able to communicate the new validator set to be used after the changeover."]})}),"\n",(0,s.jsxs)(n.p,{children:["Additionally, reach out to the community via the ",(0,s.jsx)(n.a,{href:"https://forum.cosmos.network/",children:"forum"})," to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers."]}),"\n",(0,s.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","determine your chain's spawn time"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","determine consumer chain parameters to be put in the proposal"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","take note to include a link to your onboarding repository"]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["Example of a consumer chain addition proposal (compare with the ",(0,s.jsx)(n.a,{href:"/interchain-security/v4.2.0/consumer-development/onboarding#3-submit-a-governance-proposal",children:"ConsumerAdditionProposal"})," in the ICS Provider Proposals section for chains that ",(0,s.jsx)(n.em,{children:"launch"})," as consumers):"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-js",children:'// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain or add a standalone chain.\n// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.\n// It is recommended that spawn time occurs after the proposal end time and that it is scheduled to happen before the standalone chain upgrade\n// that sill introduce the ccv module.\n{\n // Title of the proposal\n "title": "Changeover Standalone chain",\n // Description of the proposal\n // format the text as a .md file and include the file in your onboarding repository\n "description": ".md description of your chain and all other relevant information",\n // Proposed chain-id of the new consumer chain.\n // Must be unique from all other consumer chain ids of the executing provider chain.\n "chain_id": "standalone-1",\n // Initial height of new consumer chain.\n "initial_height" : {\n // must correspond to current revision number of standalone chain\n // e.g. standalone-1 => "revision_number": 1\n "revision_number": 1,\n\n // must correspond to a height that is at least 1 block after the upgrade\n // that will add the `consumer` module to the standalone chain\n // e.g. "upgrade_height": 100 => "revision_height": 101\n "revision_number": 1,\n },\n // Hash of the consumer chain genesis state without the consumer CCV module genesis params.\n // => not relevant for changeover procedure\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n // Hash of the consumer chain binary that should be run by validators on standalone chain upgrade\n // => not relevant for changeover procedure as it may become stale\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n // Unbonding period for the consumer chain.\n // It should should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n // IBC transfer packets will timeout after this interval elapses.\n "transfer_timeout_period": 1800000000000,\n // The fraction of tokens allocated to the consumer redistribution address during distribution events.\n // The fraction is a string representing a decimal number. For example "0.75" would represent 75%.\n // The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.\n "consumer_redistribution_fraction": "0.75",\n // BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.\n // eg. send rewards to the provider every 1000 blocks\n "blocks_per_distribution_transmission": 1000,\n // The number of historical info entries to persist in store.\n // This param is a part of the cosmos sdk staking module. In the case of\n // a ccv enabled consumer chain, the ccv module acts as the staking module.\n "historical_entries": 10000,\n // The ID of a token transfer channel used for the Reward Distribution\n\t// sub-protocol. If DistributionTransmissionChannel == "", a new transfer\n\t// channel is created on top of the same connection as the CCV channel.\n\t// Note that transfer_channel_id is the ID of the channel end on the consumer chain.\n // it is most relevant for chains performing a standalone to consumer changeover\n // in order to maintain the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123" // NOTE: use existing transfer channel if available\n}\n'})}),"\n",(0,s.jsx)(n.h2,{id:"3-submit-an-upgrade-proposal--prepare-for-changeover",children:"3. Submit an Upgrade Proposal & Prepare for Changeover"}),"\n",(0,s.jsxs)(n.p,{children:["This proposal should add the ccv ",(0,s.jsx)(n.code,{children:"consumer"})," module to your chain."]}),"\n",(0,s.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","proposal ",(0,s.jsx)(n.code,{children:"upgrade_height"})," must happen after ",(0,s.jsx)(n.code,{children:"spawn_time"})," in the ",(0,s.jsx)(n.code,{children:"ConsumerAdditionProposal"})]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","advise validators about the exact procedure for your chain and point them to your onboarding repository"]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"4-upgrade-time-",children:"4. Upgrade time \ud83d\ude80"}),"\n",(0,s.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","after ",(0,s.jsx)(n.code,{children:"spawn_time"}),", request ",(0,s.jsx)(n.code,{children:"ConsumerGenesis"})," from the ",(0,s.jsx)(n.code,{children:"provider"})," and place it in ",(0,s.jsx)(n.code,{children:"<CURRENT_USER_HOME_DIR>/.sovereign/config/genesis.json"})]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","upgrade the binary to the one listed in your ",(0,s.jsx)(n.code,{children:"UpgradeProposal"})]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:['The chain starts after at least 66.67% of standalone voting power comes online. The consumer chain is considered interchain secured once the "old" validator set signs a couple of blocks and transfers control to the ',(0,s.jsx)(n.code,{children:"provider"})," validator set."]}),"\n",(0,s.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","provide a repo with onboarding instructions for validators (it should already be listed in the proposal)"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","genesis.json after ",(0,s.jsx)(n.code,{children:"spawn_time"})," obtained from ",(0,s.jsx)(n.code,{children:"provider"})," (MUST contain the initial validator set)"]}),"\n",(0,s.jsxs)(n.li,{className:"task-list-item",children:[(0,s.jsx)(n.input,{type:"checkbox",disabled:!0})," ","maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>r,a:()=>a});var s=i(7294);const t={},o=s.createContext(t);function a(e){const n=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:a(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/95875ea0.a97a223d.js b/assets/js/95875ea0.a97a223d.js new file mode 100644 index 0000000000..903c081201 --- /dev/null +++ b/assets/js/95875ea0.a97a223d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3813],{2180:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>d,frontMatter:()=>s,metadata:()=>r,toc:()=>l});var i=t(5893),a=t(1151);const s={sidebar_position:3,title:"Onboarding Checklist"},o="Consumer Onboarding Checklist",r={id:"consumer-development/onboarding",title:"Onboarding Checklist",description:"The following checklists will aid in onboarding a new consumer chain to interchain security.",source:"@site/docs/consumer-development/onboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/onboarding",permalink:"/interchain-security/consumer-development/onboarding",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Onboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Consumer Chain Governance",permalink:"/interchain-security/consumer-development/consumer-chain-governance"},next:{title:"Offboarding Checklist",permalink:"/interchain-security/consumer-development/offboarding"}},c={},l=[{value:"1. Complete testing & integration",id:"1-complete-testing--integration",level:2},{value:"2. Create an Onboarding Repository",id:"2-create-an-onboarding-repository",level:2},{value:"3. Submit a Governance Proposal",id:"3-submit-a-governance-proposal",level:2},{value:"4. Launch",id:"4-launch",level:2}];function h(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",input:"input",li:"li",p:"p",pre:"pre",ul:"ul",...(0,a.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"consumer-onboarding-checklist",children:"Consumer Onboarding Checklist"}),"\n",(0,i.jsx)(n.p,{children:"The following checklists will aid in onboarding a new consumer chain to interchain security."}),"\n",(0,i.jsxs)(n.p,{children:["Additionally, you can check the ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/CONSUMER_LAUNCH_GUIDE.md",children:"testnet repo"})," for a comprehensive guide on preparing and launching consumer chains."]}),"\n",(0,i.jsx)(n.h2,{id:"1-complete-testing--integration",children:"1. Complete testing & integration"}),"\n",(0,i.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","test integration with gaia"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","test your protocol with supported relayer versions (minimum hermes 1.4.1)"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","reach out to the ICS team if you are facing issues"]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"2-create-an-onboarding-repository",children:"2. Create an Onboarding Repository"}),"\n",(0,i.jsx)(n.p,{children:"To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain."}),"\n",(0,i.jsx)(n.p,{children:"This should include (at minimum):"}),"\n",(0,i.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","genesis.json without CCV data (before the proposal passes)"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see ",(0,i.jsx)(n.a,{href:"/interchain-security/consumer-development/consumer-genesis-transformation",children:"Transform Consumer Genesis"}),")"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","information about relevant seed/peer nodes you are running"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","relayer information (compatible versions)"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","copy of your governance proposal (as JSON)"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","a script showing how to start your chain and connect to peers (optional)"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable"]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["Example of such a repository can be found ",(0,i.jsx)(n.a,{href:"https://github.com/hyphacoop/ics-testnets/tree/main/game-of-chains-2022/sputnik",children:"here"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"3-submit-a-governance-proposal",children:"3. Submit a Governance Proposal"}),"\n",(0,i.jsxs)(n.p,{children:["Before you submit a ",(0,i.jsx)(n.code,{children:"ConsumerChainAddition"})," proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch.\nIf possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues."]}),"\n",(0,i.jsxs)(n.p,{children:["Additionally, reach out to the community via the ",(0,i.jsx)(n.a,{href:"https://forum.cosmos.network/",children:"forum"})," to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers."]}),"\n",(0,i.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","determine your chain's spawn time"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","determine consumer chain parameters to be put in the proposal"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","take note to include a link to your onboarding repository"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","describe the purpose and benefits of running your chain"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","determine whether your chain should be an Opt-In chain or a Top N chain (see ",(0,i.jsx)(n.a,{href:"/interchain-security/features/partial-set-security",children:"Partial Set Security"}),")"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","if desired, decide on power-shaping parameters (see ",(0,i.jsx)(n.a,{href:"/interchain-security/features/power-shaping",children:"Power Shaping"}),")"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Example of a consumer chain addition proposal."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-js",children:'// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.\n// If it passes, if the top_N parameter is not equal to 0, the top N% of validators by voting power on the provider chain are expected to validate the consumer chain at spawn time.\n// Otherwise, only validators that opted in during the proposal period are expected to validate the consumer chain at spawn time.\n// It is recommended that spawn time occurs after the proposal end time.\n{\n // Title of the proposal\n "title": "Add consumer chain",\n // Description of the proposal\n // format the text as a .md file and include the file in your onboarding repository\n "description": ".md description of your chain and all other relevant information",\n // Proposed chain-id of the new consumer chain.\n // Must be unique from all other consumer chain ids of the executing provider chain.\n "chain_id": "newchain-1",\n // Initial height of new consumer chain.\n // For a completely new chain, this will be {0,1}.\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Hash of the consumer chain genesis state without the consumer CCV module genesis params.\n // It is used for off-chain confirmation of genesis.json validity by validators and other parties.\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n // Hash of the consumer chain binary that should be run by validators on chain initialization.\n // It is used for off-chain confirmation of binary validity by validators and other parties.\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n // Time on the provider chain at which the consumer chain genesis is finalized and validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n // Unbonding period for the consumer chain.\n // It should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n // IBC transfer packets will timeout after this interval elapses.\n "transfer_timeout_period": 1800000000000,\n // The fraction of tokens allocated to the consumer redistribution address during distribution events.\n // The fraction is a string representing a decimal number. For example "0.75" would represent 75%.\n // The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.\n "consumer_redistribution_fraction": "0.75",\n // BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.\n // eg. send rewards to the provider every 1000 blocks\n "blocks_per_distribution_transmission": 1000,\n // The number of historical info entries to persist in store.\n // This param is a part of the cosmos sdk staking module. In the case of\n // a ccv enabled consumer chain, the ccv module acts as the staking module.\n "historical_entries": 10000,\n // The ID of a token transfer channel used for the Reward Distribution\n\t// sub-protocol. If DistributionTransmissionChannel == "", a new transfer\n\t// channel is created on top of the same connection as the CCV channel.\n\t// Note that transfer_channel_id is the ID of the channel end on the consumer chain.\n // it is most relevant for chains performing a standalone to consumer changeover\n // in order to maintain the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123",\n // Corresponds to the percentage of validators that have to validate the chain under the Top N case.\n // For example, 53 corresponds to a Top 53% chain, meaning that the top 53% provider validators by voting power\n // have to validate the proposed consumer chain. top_N can either be 0 or any value in [50, 100].\n // A chain can join with top_N == 0 as an Opt In chain, or with top_N \u2208 [50, 100] as a Top N chain.\n "top_N": 95,\n // Corresponds to the maximum power (percentage-wise) a validator can have on the consumer chain. For instance, if\n // `validators_power_cap` is set to 32, it means that no validator can have more than 32% of the voting power on the\n // consumer chain. Note that this might not be feasible. For example, think of a consumer chain with only\n // 5 validators and with `validators_power_cap` set to 10%. In such a scenario, at least one validator would need\n // to have more than 20% of the total voting power. Therefore, `validators_power_cap` operates on a best-effort basis.\n "validators_power_cap": 0,\n // Corresponds to the maximum number of validators that can validate a consumer chain.\n // Only applicable to Opt In chains. Setting `validator_set_cap` on a Top N chain is a no-op.\n "validator_set_cap": 0,\n // Corresponds to a list of provider consensus addresses of validators that are the ONLY ones that can validate\n // the consumer chain.\n "allowlist": [],\n // Corresponds to a list of provider consensus addresses of validators that CANNOT validate the consumer chain.\n "denylist": []\n}\n'})}),"\n",(0,i.jsx)(n.h2,{id:"4-launch",children:"4. Launch"}),"\n",(0,i.jsxs)(n.p,{children:["The consumer chain starts after at least 66.67% of its voting power comes online.\nNote that this means 66.67% of the voting power in the ",(0,i.jsx)(n.em,{children:"consumer"})," validator set, which will be comprised of all validators that either opted in to the chain or are part of the top N% of the provider chain (and are thus automatically opted in).\nThe consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer"]}),"\n",(0,i.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","provide a repo with onboarding instructions for validators (it should already be listed in the proposal)"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","genesis.json with ccv data populated (MUST contain the initial validator set)"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","have a block explorer in place to track chain activity & health"]}),"\n"]})]})}function d(e={}){const{wrapper:n}={...(0,a.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>r,a:()=>o});var i=t(7294);const a={},s=i.createContext(a);function o(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:o(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/97662a95.fa11ce6a.js b/assets/js/97662a95.fa11ce6a.js new file mode 100644 index 0000000000..654f393379 --- /dev/null +++ b/assets/js/97662a95.fa11ce6a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3859],{9541:(e,r,n)=>{n.r(r),n.d(r,{assets:()=>o,contentTitle:()=>t,default:()=>h,frontMatter:()=>s,metadata:()=>d,toc:()=>c});var a=n(5893),i=n(1151);const s={sidebar_position:3},t="Withdrawing consumer chain validator rewards",d={id:"validators/withdraw_rewards",title:"Withdrawing consumer chain validator rewards",description:"Here are example steps for withdrawing rewards from consumer chains in the provider chain",source:"@site/versioned_docs/version-v4.2.0-docs/validators/withdraw_rewards.md",sourceDirName:"validators",slug:"/validators/withdraw_rewards",permalink:"/interchain-security/v4.2.0/validators/withdraw_rewards",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Joining Interchain Security testnet",permalink:"/interchain-security/v4.2.0/validators/joining-testnet"},next:{title:"Validator Instructions for Changeover Procedure",permalink:"/interchain-security/v4.2.0/validators/changeover-procedure"}},o={},c=[{value:"Querying validator rewards",id:"querying-validator-rewards",level:2},{value:"Withdrawing rewards and commission",id:"withdrawing-rewards-and-commission",level:2},{value:"1. Withdraw rewards",id:"1-withdraw-rewards",level:3},{value:"2. Confirm withdrawal",id:"2-confirm-withdrawal",level:3}];function l(e){const r={admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,i.a)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(r.h1,{id:"withdrawing-consumer-chain-validator-rewards",children:"Withdrawing consumer chain validator rewards"}),"\n",(0,a.jsx)(r.p,{children:"Here are example steps for withdrawing rewards from consumer chains in the provider chain"}),"\n",(0,a.jsxs)(r.admonition,{type:"info",children:[(0,a.jsxs)(r.p,{children:["The examples used are from ",(0,a.jsx)(r.code,{children:"rs-testnet"}),", the replicated security persistent testnet."]}),(0,a.jsxs)(r.p,{children:["Validator operator address: ",(0,a.jsx)(r.code,{children:"cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6"}),"\nSelf-delegation address: ",(0,a.jsx)(r.code,{children:"cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf"})]})]}),"\n",(0,a.jsx)(r.p,{children:"Prior to withdrawing rewards, query balances for self-delegation address:"}),"\n",(0,a.jsx)(r.pre,{children:(0,a.jsx)(r.code,{className:"language-bash",children:'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "1000000000000"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n'})}),"\n",(0,a.jsx)(r.h2,{id:"querying-validator-rewards",children:"Querying validator rewards"}),"\n",(0,a.jsx)(r.p,{children:"Query rewards for the validator address:"}),"\n",(0,a.jsx)(r.pre,{children:(0,a.jsx)(r.code,{className:"language-bash",children:'gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6\n\nrewards:\n- amount: "158.069895000000000000"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "841842390516.072526500000000000"\n denom: uatom\n'})}),"\n",(0,a.jsxs)(r.p,{children:["The ",(0,a.jsx)(r.code,{children:"ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD"})," denom represents rewards from a consumer chain."]}),"\n",(0,a.jsx)(r.h2,{id:"withdrawing-rewards-and-commission",children:"Withdrawing rewards and commission"}),"\n",(0,a.jsx)(r.h3,{id:"1-withdraw-rewards",children:"1. Withdraw rewards"}),"\n",(0,a.jsx)(r.pre,{children:(0,a.jsx)(r.code,{className:"language-bash",children:"gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y\n\ntxhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A\n"})}),"\n",(0,a.jsx)(r.h3,{id:"2-confirm-withdrawal",children:"2. Confirm withdrawal"}),"\n",(0,a.jsx)(r.p,{children:"After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:"}),"\n",(0,a.jsx)(r.pre,{children:(0,a.jsx)(r.code,{className:"language-bash",children:'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "216"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "2233766225342"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n'})})]})}function h(e={}){const{wrapper:r}={...(0,i.a)(),...e.components};return r?(0,a.jsx)(r,{...e,children:(0,a.jsx)(l,{...e})}):l(e)}},1151:(e,r,n)=>{n.d(r,{Z:()=>d,a:()=>t});var a=n(7294);const i={},s=a.createContext(i);function t(e){const r=a.useContext(s);return a.useMemo((function(){return"function"==typeof e?e(r):{...r,...e}}),[r,e])}function d(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:t(e.components),a.createElement(s.Provider,{value:r},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/98891868.9f022861.js b/assets/js/98891868.9f022861.js new file mode 100644 index 0000000000..7483a9017f --- /dev/null +++ b/assets/js/98891868.9f022861.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4964],{2177:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>d,contentTitle:()=>i,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>c});var r=s(5893),t=s(1151);const a={sidebar_position:3,title:"Key Assignment"},i="ADR 001: Key Assignment",o={id:"adrs/adr-001-key-assignment",title:"Key Assignment",description:"Changelog",source:"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-001-key-assignment.md",sourceDirName:"adrs",slug:"/adrs/adr-001-key-assignment",permalink:"/interchain-security/v4.2.0/adrs/adr-001-key-assignment",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Key Assignment"},sidebar:"tutorialSidebar",previous:{title:"ADR Template",permalink:"/interchain-security/v4.2.0/adrs/adr-template"},next:{title:"Jail Throttling",permalink:"/interchain-security/v4.2.0/adrs/adr-002-throttle"}},d={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"State required",id:"state-required",level:3},{value:"Protocol overview",id:"protocol-overview",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,t.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"adr-001-key-assignment",children:"ADR 001: Key Assignment"}),"\n",(0,r.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"2022-12-01: Initial Draft"}),"\n",(0,r.jsx)(n.li,{children:"2024-03-01: Updated to take into account they key-assigment-replacement deprecation."}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,r.jsx)(n.p,{children:"Accepted"}),"\n",(0,r.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,r.jsx)(n.p,{children:"KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate."}),"\n",(0,r.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,r.jsxs)(n.p,{children:["It is possible to change the keys at any time by submitting a transaction (i.e., ",(0,r.jsx)(n.code,{children:"MsgAssignConsumerKey"}),")."]}),"\n",(0,r.jsx)(n.h3,{id:"state-required",children:"State required"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"ValidatorConsumerPubKey"})," - Stores the validator assigned keys for every consumer chain."]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey\n"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"ValidatorByConsumerAddr"})," - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol."]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress\n"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"ConsumerAddrsToPrune"})," - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ",(0,r.jsx)(n.code,{children:"ValidatorByConsumerAddr"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses\n"})}),"\n",(0,r.jsx)(n.h3,{id:"protocol-overview",children:"Protocol overview"}),"\n",(0,r.jsxs)(n.p,{children:["On receiving a ",(0,r.jsx)(n.code,{children:"MsgAssignConsumerKey(chainID, providerAddr, consumerKey)"})," message:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"// get validator from staking module \nvalidator, found := stakingKeeper.GetValidator(providerAddr)\nif !found {\n return ErrNoValidatorFound\n}\nproviderConsAddr := validator.GetConsAddr()\n\n// make sure consumer key is not in use\nconsumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)\nif _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {\n return ErrInvalidConsumerConsensusPubKey\n}\n\n// check whether the consumer chain is already registered\n// i.e., a client to the consumer was already created\nif _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {\n // get the previous key assigned for this validator on this consumer chain\n oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)\n if found {\n // mark this old consumer key as prunable once the VSCMaturedPacket\n // for the current VSC ID is received\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n vscID := GetValidatorSetUpdateId()\n AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)\n }\n} else {\n // if the consumer chain is not registered, then remove the previous reverse mapping\n if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)\n }\n}\n\n\n// set the mapping from this validator's provider address to the new consumer key\nSetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)\n\n// set the reverse mapping: from this validator's new consensus address \n// on the consumer to its consensus address on the provider\nSetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)\n"})}),"\n",(0,r.jsxs)(n.p,{children:["When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see ",(0,r.jsx)(n.code,{children:"MakeConsumerGenesis"}),")."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {\n // ...\n // get initial valset from the staking module\n var updates []abci.ValidatorUpdate{}\n stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {\n validator := stakingKeeper.GetValidator(providerAddr)\n providerKey := validator.TmConsPublicKey()\n\t\tupdates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})\n\t\treturn false\n\t})\n\n // applies the key assignment to the initial validator\n\tfor i, update := range updates {\n\t\tproviderAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)\n\t\tif consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {\n\t\t\tupdates[i].PubKey = consumerKey\n\t\t}\n\t}\n gen.InitialValSet = updates\n\n // get a hash of the consumer validator set from the update\n\tupdatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)\n\thash := tendermint.NewValidatorSet(updatesAsValSet).Hash()\n\n\treturn gen, hash, nil\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Note that key assignment works hand-in-hand with ",(0,r.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-014-epochs.md",children:"epochs"}),".\nFor each consumer chain, we store the consumer validator set that is currently (i.e., in this epoch) validating the consumer chain.\nSpecifically, for each validator in the set we store among others, the public key that it is using on the consumer chain during the current (i.e., ongoing) epoch.\nAt the end of every epoch, if there were validator set changes on the provider, then for every consumer chain, we construct a ",(0,r.jsx)(n.code,{children:"VSCPacket"}),"\nwith all the validator updates and add it to the list of ",(0,r.jsx)(n.code,{children:"PendingVSCPacket"}),"s. We compute the validator updates needed by a consumer chain by\ncomparing the stored list of consumer validators with the current bonded validators on the provider, with something similar to this:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"// get the valset that has been validating the consumer chain during this epoch \ncurrentValidators := GetConsumerValSet(consumerChain)\n// generate the validator updates needed to be sent through a `VSCPacket` by comparing the current validators \n// in the epoch with the latest bonded validators\nvalUpdates := DiffValidators(currentValidators, stakingmodule.GetBondedValidators())\n// update the current validators set for the upcoming epoch to be the latest bonded validators instead\nSetConsumerValSet(stakingmodule.GetBondedValidators())\n"})}),"\n",(0,r.jsxs)(n.p,{children:["where ",(0,r.jsx)(n.code,{children:"DiffValidators"})," internally checks if the consumer public key for a validator has changed since the last\nepoch and if so generates a validator update. This way, a validator can change its consumer public key for a consumer\nchain an arbitrary amount of times and only the last set consumer public key would be taken into account."]}),"\n",(0,r.jsxs)(n.p,{children:["On receiving a ",(0,r.jsx)(n.code,{children:"SlashPacket"})," from a consumer chain with id ",(0,r.jsx)(n.code,{children:"chainID"})," for a infraction of a validator ",(0,r.jsx)(n.code,{children:"data.Validator"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {\n // ...\n // the slash packet validator address may be known only on the consumer chain;\n\t// in this case, it must be mapped back to the consensus address on the provider chain\n consumerAddr := sdk.ConsAddress(data.Validator.Address)\n providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)\n if !found {\n // the validator has the same key on the consumer as on the provider\n providerAddr = consumerAddr\n }\n // ...\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["On receiving a ",(0,r.jsx)(n.code,{children:"VSCMatured"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {\n // ...\n // prune previous consumer validator address that are no longer needed\n consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n\tfor _, addr := range consumerAddrs {\n\t\tDeleteValidatorByConsumerAddr(chainID, addr)\n\t}\n\tDeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n // ...\n}\n"})}),"\n",(0,r.jsx)(n.p,{children:"On stopping a consumer chain:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {\n // ...\n // deletes all the state needed for key assignments on this consumer chain\n // ...\n}\n"})}),"\n",(0,r.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,r.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Validators can use different consensus keys on the consumer chains."}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"None"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["The consensus state necessary to create a client to the consumer chain must use the hash returned by the ",(0,r.jsx)(n.code,{children:"MakeConsumerGenesis"})," method as the ",(0,r.jsx)(n.code,{children:"nextValsHash"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:["The consumer chain can no longer check the initial validator set against the consensus state on ",(0,r.jsx)(n.code,{children:"InitGenesis"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/26",children:"Key assignment issue"})}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},1151:(e,n,s)=>{s.d(n,{Z:()=>o,a:()=>i});var r=s(7294);const t={},a=r.createContext(t);function i(e){const n=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:i(e.components),r.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/99394557.c883f412.js b/assets/js/99394557.c883f412.js new file mode 100644 index 0000000000..c9f6935628 --- /dev/null +++ b/assets/js/99394557.c883f412.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9897],{3347:(e,r,n)=>{n.r(r),n.d(r,{assets:()=>u,contentTitle:()=>c,default:()=>m,frontMatter:()=>a,metadata:()=>d,toc:()=>h});var t=n(5893),i=n(1151),s=n(2307),o=n(8758);const a={sidebar_position:1},c="Interchain Security Docs",d={id:"index",title:"Interchain Security Docs",description:"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.",source:"@site/versioned_docs/version-v4.2.0-docs/index.mdx",sourceDirName:".",slug:"/",permalink:"/interchain-security/v4.2.0/",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",next:{title:"Overview",permalink:"/interchain-security/v4.2.0/introduction/overview"}},u={},h=[];function l(e){const r={h1:"h1",p:"p",...(0,i.a)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(r.h1,{id:"interchain-security-docs",children:"Interchain Security Docs"}),"\n",(0,t.jsx)(r.p,{children:"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains."}),"\n",(0,t.jsx)(r.p,{children:"Here you can find information about replicated security, consumer chain development and instructions for validator onboarding."}),"\n",(0,t.jsx)(s.Z,{cards:o.Z})]})}function m(e={}){const{wrapper:r}={...(0,i.a)(),...e.components};return r?(0,t.jsx)(r,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},2307:(e,r,n)=>{n.d(r,{Z:()=>s});n(7294);var t=n(5893);const i=function(e){return(0,t.jsx)("a",{href:e.href,className:"border shadow rounded-sm border-stone-200 dark:border-stone-800 dark:bg-neutral-900 hover:border-stone-300 hover:shadow-lg dark:hover:border-stone-200 transition-all duration-200 no-underline",children:(0,t.jsxs)("div",{className:"p-6",children:[(0,t.jsx)("h2",{className:"",children:e.header}),(0,t.jsx)("p",{className:"",children:e.summary})]})})};const s=function(e){return(0,t.jsx)("div",{className:"card-section grid grid-cols-1 lg:grid-cols-2 gap-4 no-underline",children:e.cards.map(((e,r)=>(0,t.jsx)(i,{href:e.href,header:e.header,summary:e.summary},r)))})}},8758:(e,r,n)=>{n.d(r,{Z:()=>t});const t=[{href:"/interchain-security/introduction/overview",header:"Basic concepts",summary:"Get started with the basic concepts and ideas."},{href:"/interchain-security/consumer-development/app-integration",header:"Start building",summary:"Click here to start building with Interchain security"},{href:"/interchain-security/features/key-assignment",header:"Feature: Key Assignment",summary:"Learn about the key assignment feature"},{href:"/interchain-security/features/reward-distribution",header:"Feature: Reward Distribution",summary:"Learn about consumer chain rewards distribution"},{href:"/interchain-security/consumer-development/onboarding",header:"Onboarding Checklist",summary:"Checklist to help you integrate Interchain Security, get support and onboard validators"},{href:"/interchain-security/faq",header:"FAQ",summary:"Frequently asked questions about the protocol and its implications"}]},1151:(e,r,n)=>{n.d(r,{Z:()=>a,a:()=>o});var t=n(7294);const i={},s=t.createContext(i);function o(e){const r=t.useContext(s);return t.useMemo((function(){return"function"==typeof e?e(r):{...r,...e}}),[r,e])}function a(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),t.createElement(s.Provider,{value:r},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/99c91eb8.ebba5ec5.js b/assets/js/99c91eb8.ebba5ec5.js new file mode 100644 index 0000000000..949c64f126 --- /dev/null +++ b/assets/js/99c91eb8.ebba5ec5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5112],{9697:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var i=s(5893),t=s(1151);const r={sidebar_position:2,title:"Joining Interchain Security testnet"},o=void 0,a={id:"validators/joining-testnet",title:"Joining Interchain Security testnet",description:"Introduction",source:"@site/versioned_docs/version-v5.0.0/validators/joining-testnet.md",sourceDirName:"validators",slug:"/validators/joining-testnet",permalink:"/interchain-security/v5.0.0/validators/joining-testnet",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"Joining Interchain Security testnet"},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/v5.0.0/validators/overview"},next:{title:"Withdrawing consumer chain validator rewards",permalink:"/interchain-security/v5.0.0/validators/withdraw_rewards"}},c={},d=[{value:"Introduction",id:"introduction",level:2},{value:"Joining the provider chain",id:"joining-the-provider-chain",level:2},{value:"Initialization",id:"initialization",level:2},{value:"Joining consumer chains",id:"joining-consumer-chains",level:2},{value:"Re-using consensus key",id:"re-using-consensus-key",level:2},{value:"Assigning consensus keys",id:"assigning-consensus-keys",level:2}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,t.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,i.jsxs)(n.p,{children:["This short guide will teach you how to join the ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/testnets/tree/master/interchain-security",children:"Interchain Security testnet"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"The experience gained in the testnet will prepare you for validating interchain secured chains."}),"\n",(0,i.jsxs)(n.admonition,{type:"tip",children:[(0,i.jsx)(n.p,{children:"Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set."}),(0,i.jsxs)(n.p,{children:["For general information about running cosmos-sdk based chains check out the ",(0,i.jsx)(n.a,{href:"https://hub.cosmos.network/validators/validator-setup",children:"validator basics"})," and ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/main/run-node/run-node",children:"Running a Node section"})," of Cosmos SDK docs"]})]}),"\n",(0,i.jsx)(n.h2,{id:"joining-the-provider-chain",children:"Joining the provider chain"}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsx)(n.p,{children:"At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain."})}),"\n",(0,i.jsxs)(n.p,{children:["A comprehensive guide is available ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/testnets/tree/master/interchain-security/provider",children:"here"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"initialization",children:"Initialization"}),"\n",(0,i.jsxs)(n.p,{children:["First, initialize your ",(0,i.jsx)(n.code,{children:"$NODE_HOME"})," using the ",(0,i.jsx)(n.code,{children:"provider"})," chain binary."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"NODE_MONIKER=<your_node>\nCHAIN_ID=provider\nNODE_HOME=<path_to_your_home>\n\ngaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Add your key to the keyring - more details available ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/main/run-node/keyring",children:"here"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["In this example we will use the ",(0,i.jsx)(n.code,{children:"test"})," keyring-backend. This option is not safe to use in production."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad keys add <key_moniker> --keyring-backend test\n\n# save the address as variable for later use\nMY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Before issuing any transactions, use the ",(0,i.jsx)(n.code,{children:"provider"})," testnet faucet to add funds to your address."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider\n\n# example output:\n{\n "address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",\n "amount": "10000000uatom",\n "chain": "provider",\n "hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",\n "status": "success"\n}\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Then, use the account associated with the keyring to issue a ",(0,i.jsx)(n.code,{children:"create-validator"})," transaction which will register your validator on chain."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'gaiad tx staking create-validator \\\n --amount=1000000uatom \\\n --pubkey=$(gaiad tendermint show-validator) \\\n --moniker="choose a moniker" \\\n --chain-id=$CHAIN_ID" \\\n --commission-rate="0.10" \\\n --commission-max-rate="0.20" \\\n --commission-max-change-rate="0.01" \\\n --min-self-delegation="1000000" \\\n --gas="auto" \\\n --gas-prices="0.0025uatom" \\\n --from=<key_moniker>\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["Check this ",(0,i.jsx)(n.a,{href:"https://hub.cosmos.network/validators/validator-setup#edit-validator-description",children:"guide"})," to edit your validator."]})}),"\n",(0,i.jsxs)(n.p,{children:["After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use ",(0,i.jsx)(n.code,{children:"statesync"})," to catch up to the rest of the network."]}),"\n",(0,i.jsxs)(n.p,{children:["You can use this script to modify your ",(0,i.jsx)(n.code,{children:"config.toml"})," with the required statesync parameters."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"# create the statesync script\n$: cd $NODE_HOME\n$: touch statesync.sh\n$ chmod 700 statesync.sh # make executable\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Paste the following instructions into the ",(0,i.jsx)(n.code,{children:"statesync.sh"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'#!/bin/bash\n\nSNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"\n\nLATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \\\nBLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \\\nTRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)\n\nsed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\\1true| ; \\\ns|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\\1\\"$SNAP_RPC,$SNAP_RPC\\"| ; \\\ns|^(trust_height[[:space:]]+=[[:space:]]+).*$|\\1$BLOCK_HEIGHT| ; \\\ns|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\\1\\"$TRUST_HASH\\"|" $NODE_HOME/config/config.toml\n'})}),"\n",(0,i.jsx)(n.p,{children:"Then, you can execute the script:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"$: ./statesync.sh # setup config.toml for statesync\n"})}),"\n",(0,i.jsx)(n.p,{children:"Finally, copy the provider genesis and start your node:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/interchain-security/provider/provider-genesis.json\n$: wget $GENESIS_URL -O genesis.json\n$: genesis.json $NODE_HOME/config/genesis.json\n# start the service\n$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Additional scripts to setup your nodes are available ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/provider/join-ics-provider.sh",children:"here"})," and ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/provider/join-ics-provider-cv.sh",children:"here"}),". The scripts will configure your node and create the required services - the scripts only work in linux environments."]}),"\n",(0,i.jsx)(n.h2,{id:"joining-consumer-chains",children:"Joining consumer chains"}),"\n",(0,i.jsxs)(n.admonition,{type:"tip",children:[(0,i.jsx)(n.p,{children:"Once you reach the active set on the provider chain, you will be required to validate all available consumer chains."}),(0,i.jsxs)(n.p,{children:["You can use the same consensus key on all consumer chains, or opt to use a different key on each consumer chain.\nCheck out this ",(0,i.jsx)(n.a,{href:"/interchain-security/v5.0.0/features/key-assignment",children:"guide"})," to learn more about key assignment in interchain security."]})]}),"\n",(0,i.jsx)(n.p,{children:"To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries."}),"\n",(0,i.jsxs)(n.admonition,{type:"info",children:[(0,i.jsxs)(n.p,{children:["When running the provider chain and consumers on the same machine please update the ",(0,i.jsx)(n.code,{children:"PORT"})," numbers for each of them and make sure they do not overlap (otherwise the binaries will not start)."]}),(0,i.jsx)(n.p,{children:"Important ports to re-configure:"}),(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"--rpc.laddr"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"--p2p.laddr"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"--api.address"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"--grpc.address"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"--grpc-web.address"})}),"\n"]})]}),"\n",(0,i.jsx)(n.h2,{id:"re-using-consensus-key",children:"Re-using consensus key"}),"\n",(0,i.jsxs)(n.p,{children:["To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the ",(0,i.jsx)(n.code,{children:"priv_validator_key.json"})," into the home directory of your consumer chain (",(0,i.jsx)(n.code,{children:"<consumer_home>/config/priv_validator_key.json"}),")."]}),"\n",(0,i.jsx)(n.p,{children:"When you start the chain, the consensus key will be the same on the provider and the consumer chain."}),"\n",(0,i.jsx)(n.h2,{id:"assigning-consensus-keys",children:"Assigning consensus keys"}),"\n",(0,i.jsx)(n.p,{children:"Whenever you initialize a new node, it will be configured with a consensus key you can use."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'# machine running consumer chain\nconsumerd init <node_moniker> --home <home_path> --chain-id consumer-1\n\n# use the output of this command to get the consumer chain consensus key\nconsumerd tendermint show-validator\n# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}\n'})}),"\n",(0,i.jsx)(n.p,{children:"Then, let the provider know which key you will be using for the consumer chain:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"# machine running the provider chain\ngaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b sync -y -o json\n"})}),"\n",(0,i.jsxs)(n.p,{children:["After this step, you are ready to copy the consumer genesis into your nodes's ",(0,i.jsx)(n.code,{children:"/config"})," folder, start your consumer chain node and catch up to the network."]})]})}function l(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},1151:(e,n,s)=>{s.d(n,{Z:()=>a,a:()=>o});var i=s(7294);const t={},r=i.createContext(t);function o(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/9b334c7f.4eb2d589.js b/assets/js/9b334c7f.4eb2d589.js new file mode 100644 index 0000000000..ed2d3d2e9a --- /dev/null +++ b/assets/js/9b334c7f.4eb2d589.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5118],{9651:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>c,contentTitle:()=>s,default:()=>p,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var t=o(5893),i=o(1151);const r={sidebar_position:4,title:"Offboarding Checklist"},s="Consumer Offboarding",a={id:"consumer-development/offboarding",title:"Offboarding Checklist",description:"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).",source:"@site/versioned_docs/version-v5.0.0/consumer-development/offboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/offboarding",permalink:"/interchain-security/v5.0.0/consumer-development/offboarding",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Offboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Onboarding Checklist",permalink:"/interchain-security/v5.0.0/consumer-development/onboarding"},next:{title:"Changeover Procedure",permalink:"/interchain-security/v5.0.0/consumer-development/changeover-procedure"}},c={},d=[];function l(e){const n={code:"code",h1:"h1",p:"p",pre:"pre",...(0,i.a)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"consumer-offboarding",children:"Consumer Offboarding"}),"\n",(0,t.jsxs)(n.p,{children:["To offboard a consumer chain simply submit a ",(0,t.jsx)(n.code,{children:"ConsumerRemovalProposal"})," governance proposal listing a ",(0,t.jsx)(n.code,{children:"stop_time"}),". After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates)."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:'// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.\n// If it passes, all the consumer chain\'s state is removed from the provider chain. The outstanding unbonding\n// operation funds are released.\n{\n // the title of the proposal\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"More information will be listed in a future version of this document."})]})}function p(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},1151:(e,n,o)=>{o.d(n,{Z:()=>a,a:()=>s});var t=o(7294);const i={},r=t.createContext(i);function s(e){const n=t.useContext(r);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:s(e.components),t.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/9be59c75.cfc66a57.js b/assets/js/9be59c75.cfc66a57.js new file mode 100644 index 0000000000..c814ffbf35 --- /dev/null +++ b/assets/js/9be59c75.cfc66a57.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6420],{4408:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>h,contentTitle:()=>s,default:()=>d,frontMatter:()=>o,metadata:()=>r,toc:()=>l});var n=i(5893),a=i(1151);const o={sidebar_position:7},s="Power Shaping",r={id:"features/power-shaping",title:"Power Shaping",description:"To give consumer chains more flexibility in choosing their validator set, Interchain Security offers",source:"@site/docs/features/power-shaping.md",sourceDirName:"features",slug:"/features/power-shaping",permalink:"/interchain-security/features/power-shaping",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:7,frontMatter:{sidebar_position:7},sidebar:"tutorialSidebar",previous:{title:"Partial Set Security",permalink:"/interchain-security/features/partial-set-security"},next:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/consumer-development/app-integration"}},h={},l=[{value:"Guidelines for setting power shaping parameters",id:"guidelines-for-setting-power-shaping-parameters",level:2}];function c(e){const t={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"power-shaping",children:"Power Shaping"}),"\n",(0,n.jsx)(t.p,{children:'To give consumer chains more flexibility in choosing their validator set, Interchain Security offers\nseveral "power shaping" mechanisms for consumer chains.'}),"\n",(0,n.jsx)(t.p,{children:"These are:"}),"\n",(0,n.jsxs)(t.ol,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.strong,{children:"Capping the size of the validator set"}),": The consumer chain can specify a maximum number of validators it\nwants to have in its validator set. This can be used to limit the number of validators in the set, which can\nbe useful for chains that want to have a smaller validator set for faster blocks or lower overhead. If more validators\nthan the maximum size have opted in on a consumer chain, only the validators with the highest power, up to the specified\nmaximum, will validate the consumer chain."]}),"\n"]}),"\n",(0,n.jsx)(t.admonition,{type:"info",children:(0,n.jsx)(t.p,{children:"This is only applicable to Opt In chains (chains with Top N = 0)."})}),"\n",(0,n.jsxs)(t.ol,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.strong,{children:"Capping the fraction of power any single validator can have"}),": The consumer chain can specify a maximum fraction\nof the total voting power that any single validator in its validator set should have.\nThis is a security measure with the intention of making it harder for a single large validator to take over a consumer chain. This mitigates the risk of an Opt In chain with only a few validators being dominated by a validator with a large amount of stake opting in.\nFor example, setting this fraction to e.g. 33% would mean that no single validator can have more than 33% of the total voting power,\nand thus there is no single validator who would stop the chain by going offline."]}),"\n"]}),"\n",(0,n.jsx)(t.admonition,{type:"info",children:(0,n.jsx)(t.p,{children:"This is a soft cap, and the actual power of a validator can exceed this fraction if the validator set is small (e.g. there are only 3 validators and the cap is 20%)."})}),"\n",(0,n.jsx)(t.admonition,{type:"info",children:(0,n.jsx)(t.p,{children:"Rewards are distributed proportionally to validators with respect to their capped voting power on the consumer,\nnot their total voting power on the provider."})}),"\n",(0,n.jsxs)(t.ol,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.strong,{children:"Allowlist and denylist"}),": The consumer chain can specify a list of validators that are allowed or disallowed from participating in the validator set. If an allowlist is set, all validators not on the allowlist cannot validate the consumer chain. If a validator is on both lists, the denylist takes precedence, that is, they cannot validate the consumer chain. If neither list is set, all validators are able to validate the consumer chain."]}),"\n"]}),"\n",(0,n.jsx)(t.admonition,{type:"warning",children:(0,n.jsxs)(t.p,{children:["Note that if denylisting is used in a Top N consumer chain, then the chain might not be secured by N% of the total provider's\npower. For example, consider that the top validator ",(0,n.jsx)(t.code,{children:"V"})," on the provider chain has 10% of the voting power, and we have a Top 50% consumer chain,\nthen if ",(0,n.jsx)(t.code,{children:"V"})," is denylisted, the consumer chain would only be secured by at least 40% of the provider's power."]})}),"\n",(0,n.jsxs)(t.p,{children:["All these mechanisms are set by the consumer chain in the ",(0,n.jsx)(t.code,{children:"ConsumerAdditionProposal"}),". They operate ",(0,n.jsx)(t.em,{children:"solely on the provider chain"}),", meaning the consumer chain simply receives the validator set after these rules have been applied and does not have any knowledge about whether they are applied."]}),"\n",(0,n.jsxs)(t.p,{children:["Each of these mechanisms is ",(0,n.jsx)(t.em,{children:"set during the consumer addition proposal"})," (see ",(0,n.jsx)(t.a,{href:"/interchain-security/consumer-development/onboarding#3-submit-a-governance-proposal",children:"Onboarding"}),"), and is currently ",(0,n.jsx)(t.em,{children:"immutable"})," after the chain has been added."]}),"\n",(0,n.jsx)(t.p,{children:"The values can be seen by querying the list of consumer chains:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-bash",children:"interchain-security-pd query provider list-consumer-chains\n"})}),"\n",(0,n.jsx)(t.h2,{id:"guidelines-for-setting-power-shaping-parameters",children:"Guidelines for setting power shaping parameters"}),"\n",(0,n.jsx)(t.p,{children:"When setting power shaping parameters, please consider the following guidelines:"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["Do not cap the validator set size too low: Notice that this number is the *",(0,n.jsx)(t.em,{children:"maximum"})," number of validators that will ever validate the consumer chain. If this number is too low, the chain will be very limited in the\namount of stake that secures it. The validator set size cap should only be used if there are strong reasons to prefer fewer validators. Consider that setting the cap will mean that\neven if the whole validator set of the provider wants to validate on the chain, some validators will simply not be able to."]}),"\n",(0,n.jsx)(t.li,{children:"Capping the fraction of power any single validator can have is a decent security measure, but it's good to be aware of the interactions with the size of the validator set.\nFor example, if there are only 3 validators, and the cap is 20%, this will not be possible (since even splitting the power fairly would mean that each validator has 33% of the power, so is above the cap).\nHowever, the cap can be a good measure to prevent a single large validator from essentially taking over the chain.\nIn general, values under 33% make sense (since a validator that has 33% of the chains power would halt the chain if they go offline).\nNotice that the smaller this value is, the more the original voting power gets distorted, which could discourage large validators from deciding to opt in to the chain."}),"\n",(0,n.jsxs)(t.li,{children:["If the allowlist is ",(0,n.jsx)(t.em,{children:"empty"}),", all validators can validate the chain. If it is ",(0,n.jsx)(t.em,{children:"non empty"}),", then ",(0,n.jsx)(t.em,{children:"only"})," validators on the allowlist can validate the chain.\nThus, an allowlist containing too few validators is a security risk. In particular, consider that if the validators on the allowlist lose a lot of stake or stop being validators,\nan allowlist that is too short can very quickly become outdated and leave too few validators, or validators with too little stake, to secure the chain in a decentralized way."]}),"\n",(0,n.jsx)(t.li,{children:"If the denylist is too full, this can likewise be problematic. If too many large validators are denylisted, the chain might not be secured by a large enough fraction of the provider's power, in particular when\nthe power distribution on the provider shifts and the denylisted validators gain more power."}),"\n"]}),"\n",(0,n.jsx)(t.p,{children:"In general, when setting these parameters, consider that the voting power distribution in the future might be very different from the one right now,\nand that the chain should be secure even if the power distribution changes significantly."}),"\n",(0,n.jsx)(t.admonition,{type:"tip",children:(0,n.jsxs)(t.p,{children:["The power shaping parameters of a running consumer chain can be changed through a ",(0,n.jsx)(t.a,{href:"/interchain-security/features/proposals#consumermodificationproposal",children:(0,n.jsx)(t.code,{children:"ConsumerModificationProposal"})}),"."]})})]})}function d(e={}){const{wrapper:t}={...(0,a.a)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(c,{...e})}):c(e)}},1151:(e,t,i)=>{i.d(t,{Z:()=>r,a:()=>s});var n=i(7294);const a={},o=n.createContext(a);function s(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:s(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/9c202c81.4de6f0b5.js b/assets/js/9c202c81.4de6f0b5.js new file mode 100644 index 0000000000..ee46d08e9e --- /dev/null +++ b/assets/js/9c202c81.4de6f0b5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6625],{5626:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>l,frontMatter:()=>t,metadata:()=>a,toc:()=>c});var i=r(5893),s=r(1151);const t={sidebar_position:2},o="Reward Distribution",a={id:"features/reward-distribution",title:"Reward Distribution",description:"Sending and distributing rewards from consumer chains to the provider chain is handled by the Reward Distribution sub-protocol.",source:"@site/versioned_docs/version-v5.0.0/features/reward-distribution.md",sourceDirName:"features",slug:"/features/reward-distribution",permalink:"/interchain-security/v5.0.0/features/reward-distribution",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/v5.0.0/features/key-assignment"},next:{title:"ICS Provider Proposals",permalink:"/interchain-security/v5.0.0/features/proposals"}},d={},c=[{value:"Whitelisting Reward Denoms",id:"whitelisting-reward-denoms",level:2}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"reward-distribution",children:"Reward Distribution"}),"\n",(0,i.jsxs)(n.p,{children:["Sending and distributing rewards from consumer chains to the provider chain is handled by the ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md#reward-distribution",children:"Reward Distribution sub-protocol"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["Consumer chains have the option of sharing (a portion of) their block rewards (inflation tokens and fees) with the provider chain validators and delegators.\nIn replicated security, block rewards are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel.\nThis channel is created during consumer chain initialization, unless it is provided via the ",(0,i.jsx)(n.code,{children:"ConsumerAdditionProposal"})," when adding a new consumer chain.\nFor more details, see the ",(0,i.jsx)(n.a,{href:"/interchain-security/v5.0.0/introduction/params#reward-distribution-parameters",children:"reward distribution parameters"}),"."]}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["Providing an IBC transfer channel (see ",(0,i.jsx)(n.code,{children:"DistributionTransmissionChannel"}),") enables a consumer chain to re-use one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ",(0,i.jsx)(n.code,{children:"ibc denom"})," that may already be in use.\nThis is especially important for standalone chains transitioning to become consumer chains.\nFor more details, see the ",(0,i.jsx)(n.a,{href:"/interchain-security/v5.0.0/consumer-development/changeover-procedure",children:"changeover procedure"}),"."]})}),"\n",(0,i.jsx)(n.p,{children:"Reward distribution on the provider is handled by the distribution module."}),"\n",(0,i.jsx)(n.h2,{id:"whitelisting-reward-denoms",children:"Whitelisting Reward Denoms"}),"\n",(0,i.jsxs)(n.p,{children:["The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the ",(0,i.jsx)(n.code,{children:"ConsumerRewardsPool"}),".\nTo avoid spam, the provider must whitelist denoms before accepting them as ICS rewards.\nOnly whitelisted denoms are transferred from the ",(0,i.jsx)(n.code,{children:"ConsumerRewardsPool"})," to the ",(0,i.jsx)(n.code,{children:"FeePoolAddress"}),", to be distributed to delegators and validators.\nThe whitelisted denoms can be adjusted through governance by sending a ",(0,i.jsx)(n.a,{href:"/interchain-security/v5.0.0/features/proposals#changerewarddenomproposal",children:(0,i.jsx)(n.code,{children:"ChangeRewardDenomProposal"})}),"."]}),"\n",(0,i.jsx)(n.p,{children:"To query the list of whitelisted reward denoms on the Cosmos Hub, use the following command:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"> gaiad q provider registered-consumer-reward-denoms\ndenoms:\n- ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5\n- ibc/6B8A3F5C2AD51CD6171FA41A7E8C35AD594AB69226438DB94450436EA57B3A89\n- uatom\n"})}),"\n",(0,i.jsxs)(n.admonition,{type:"tip",children:[(0,i.jsxs)(n.p,{children:["Use the following command to get a human readable denom from the ",(0,i.jsx)(n.code,{children:"ibc/*"})," denom trace format:"]}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"> gaiad query ibc-transfer denom-trace ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5\ndenom_trace:\n base_denom: untrn\n path: transfer/channel-569\n"})})]})]})}function l(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},1151:(e,n,r)=>{r.d(n,{Z:()=>a,a:()=>o});var i=r(7294);const s={},t=i.createContext(s);function o(e){const n=i.useContext(t);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/9fa21ee5.9bb946f7.js b/assets/js/9fa21ee5.9bb946f7.js new file mode 100644 index 0000000000..ca6d148617 --- /dev/null +++ b/assets/js/9fa21ee5.9bb946f7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3500],{7809:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>s,metadata:()=>r,toc:()=>c});var i=a(5893),t=a(1151);const s={sidebar_position:4},o="Validator Instructions for Changeover Procedure",r={id:"validators/changeover-procedure",title:"Validator Instructions for Changeover Procedure",description:"More details available in Changeover Procedure documentation.",source:"@site/versioned_docs/version-v5.0.0/validators/changeover-procedure.md",sourceDirName:"validators",slug:"/validators/changeover-procedure",permalink:"/interchain-security/v5.0.0/validators/changeover-procedure",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Withdrawing consumer chain validator rewards",permalink:"/interchain-security/v5.0.0/validators/withdraw_rewards"},next:{title:"Joining Neutron",permalink:"/interchain-security/v5.0.0/validators/joining-neutron"}},d={},c=[{value:"Timeline",id:"timeline",level:2},{value:"1. <code>ConsumerAdditionProposal</code> on provider chain",id:"1-consumeradditionproposal-on-provider-chain",level:3},{value:"2. <code>SoftwareUpgradeProposal</code> on the standalone/consumer chain",id:"2-softwareupgradeproposal-on-the-standaloneconsumer-chain",level:3},{value:"3. Assigning a consumer key",id:"3-assigning-a-consumer-key",level:3},{value:"4. Perform the software upgrade on standalone chain",id:"4-perform-the-software-upgrade-on-standalone-chain",level:3},{value:"FAQ",id:"faq",level:2},{value:"Can I reuse the same validator key for the <code>consumer</code> chain that I am already using on the <code>standalone</code> chain? Will I need to perform a <code>AssignConsumerKey</code> tx with this key before spawn time?",id:"can-i-reuse-the-same-validator-key-for-the-consumer-chain-that-i-am-already-using-on-the-standalone-chain-will-i-need-to-perform-a-assignconsumerkey-tx-with-this-key-before-spawn-time",level:3},{value:"Can I continue using the same node that was validating the <code>standalone</code> chain?",id:"can-i-continue-using-the-same-node-that-was-validating-the-standalone-chain",level:3},{value:"Can I set up a new node to validate the <code>standalone/consumer</code> chain after it transitions to replicated security?",id:"can-i-set-up-a-new-node-to-validate-the-standaloneconsumer-chain-after-it-transitions-to-replicated-security",level:3},{value:"What happens to the <code>standalone</code> validator set after it transitions to replicated security?",id:"what-happens-to-the-standalone-validator-set-after-it-transitions-to-replicated-security",level:3},{value:"Credits",id:"credits",level:2}];function l(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"validator-instructions-for-changeover-procedure",children:"Validator Instructions for Changeover Procedure"}),"\n",(0,i.jsxs)(n.p,{children:["More details available in ",(0,i.jsx)(n.a,{href:"/interchain-security/v5.0.0/consumer-development/changeover-procedure",children:"Changeover Procedure documentation"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"A major difference between launching a new consumer chain vs. onboarding a standalone chain to ICS is that there is no consumer genesis available for the standalone chain. Since a standalone chain already exists, its state must be preserved once it transitions to being a consumer chain."}),"\n",(0,i.jsx)(n.h2,{id:"timeline",children:"Timeline"}),"\n",(0,i.jsxs)(n.p,{children:["Upgrading standalone chains can be best visualised using a timeline, such as the one available ",(0,i.jsx)(n.a,{href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt",children:"Excalidraw graphic by Stride"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"There is some flexibility with regards to how the changeover procedure is executed, so please make sure to follow the guides provided by the team doing the changeover."}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Standalone to consumer transition timeline",src:a(7509).Z+"",width:"5307",height:"2157"})}),"\n",(0,i.jsxs)(n.h3,{id:"1-consumeradditionproposal-on-provider-chain",children:["1. ",(0,i.jsx)(n.code,{children:"ConsumerAdditionProposal"})," on provider chain"]}),"\n",(0,i.jsxs)(n.p,{children:["This step will add the standalone chain to the list of consumer chains secured by the provider.\nThis step dictates the ",(0,i.jsx)(n.code,{children:"spawn_time"}),". After ",(0,i.jsx)(n.code,{children:"spawn_time"})," the CCV state (initial validator set of the provider) will be available to the consumer."]}),"\n",(0,i.jsx)(n.p,{children:"To obtain it from the provider use:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad q provider consumer-genesis stride-1 -o json > ccv-state.json\njq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' genesis.json ccv-state.json > ccv.json\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Transformation of the exported consumer genesis state to the target version of the consumer might be needed in case the provider and consumer formats are incompatible.\nRefer to the compatibility notes ",(0,i.jsx)(n.a,{href:"../../../RELEASES.md#backwards-compatibility",children:"here"})," to check if data transformation is needed for your case.\nInstructions on how to transform the exported CCV genesis state (",(0,i.jsx)(n.code,{children:"ccv-state.json"})," in the example above) to the required target version can be found ",(0,i.jsx)(n.a,{href:"/interchain-security/v5.0.0/consumer-development/consumer-genesis-transformation",children:"here"})]}),"\n",(0,i.jsxs)(n.h3,{id:"2-softwareupgradeproposal-on-the-standaloneconsumer-chain",children:["2. ",(0,i.jsx)(n.code,{children:"SoftwareUpgradeProposal"})," on the standalone/consumer chain"]}),"\n",(0,i.jsx)(n.p,{children:"This upgrade proposal will introduce ICS to the standalone chain, making it a consumer."}),"\n",(0,i.jsx)(n.h3,{id:"3-assigning-a-consumer-key",children:"3. Assigning a consumer key"}),"\n",(0,i.jsxs)(n.p,{children:["After ",(0,i.jsx)(n.code,{children:"spawn_time"}),", make sure to assign a consumer key if you intend to use one."]}),"\n",(0,i.jsxs)(n.p,{children:["Instructions are available ",(0,i.jsx)(n.a,{href:"/interchain-security/v5.0.0/features/key-assignment",children:"here"})]}),"\n",(0,i.jsx)(n.h3,{id:"4-perform-the-software-upgrade-on-standalone-chain",children:"4. Perform the software upgrade on standalone chain"}),"\n",(0,i.jsx)(n.p,{children:"Please use instructions provided by the standalone chain team and make sure to reach out if you are facing issues.\nThe upgrade preparation depends on your setup, so please make sure you prepare ahead of time."}),"\n",(0,i.jsxs)(n.admonition,{type:"danger",children:[(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"ccv.json"})," from step 1. must be made available on the machine running the standalone/consumer chain at standalone chain ",(0,i.jsx)(n.code,{children:"upgrade_height"}),". This file contains the initial validator set and parameters required for normal ICS operation."]}),(0,i.jsxs)(n.p,{children:["Usually, the file is placed in ",(0,i.jsx)(n.code,{children:"$NODE_HOME/config"})," but this is not a strict requirement. The exact details are available in the upgrade code of the standalone/consumer chain."]})]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Performing this upgrade will transition the standalone chain to be a consumer chain."})}),"\n",(0,i.jsxs)(n.p,{children:['After 3 blocks, the standalone chain will stop using the "old" validator set and begin using the ',(0,i.jsx)(n.code,{children:"provider"})," validator set."]}),"\n",(0,i.jsx)(n.h2,{id:"faq",children:"FAQ"}),"\n",(0,i.jsxs)(n.h3,{id:"can-i-reuse-the-same-validator-key-for-the-consumer-chain-that-i-am-already-using-on-the-standalone-chain-will-i-need-to-perform-a-assignconsumerkey-tx-with-this-key-before-spawn-time",children:["Can I reuse the same validator key for the ",(0,i.jsx)(n.code,{children:"consumer"})," chain that I am already using on the ",(0,i.jsx)(n.code,{children:"standalone"})," chain? Will I need to perform a ",(0,i.jsx)(n.code,{children:"AssignConsumerKey"})," tx with this key before spawn time?"]}),"\n",(0,i.jsxs)(n.p,{children:["Validators must either assign a key or use the same key as on the ",(0,i.jsx)(n.code,{children:"provider"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["If you are validating both the ",(0,i.jsx)(n.code,{children:"standalone"})," and the ",(0,i.jsx)(n.code,{children:"provider"}),", you ",(0,i.jsx)(n.strong,{children:"can"})," use your current ",(0,i.jsx)(n.code,{children:"standalone"})," key with some caveats:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["you must submit an ",(0,i.jsx)(n.code,{children:"AssignConsumerKey"})," tx with your current ",(0,i.jsx)(n.code,{children:"standalone"})," validator key"]}),"\n",(0,i.jsxs)(n.li,{children:["it is best to submit ",(0,i.jsx)(n.code,{children:"AssignConsumerKey"})," tx before ",(0,i.jsx)(n.code,{children:"spawn_time"})]}),"\n",(0,i.jsxs)(n.li,{children:["if you do not submit the Tx, it is assumed that you will be re-using your ",(0,i.jsx)(n.code,{children:"provider"})," key to validate the ",(0,i.jsx)(n.code,{children:"standalone/consumer"})," chain"]}),"\n"]}),"\n",(0,i.jsxs)(n.h3,{id:"can-i-continue-using-the-same-node-that-was-validating-the-standalone-chain",children:["Can I continue using the same node that was validating the ",(0,i.jsx)(n.code,{children:"standalone"})," chain?"]}),"\n",(0,i.jsx)(n.p,{children:"Yes."}),"\n",(0,i.jsx)(n.p,{children:"Please assign your consensus key as stated above."}),"\n",(0,i.jsxs)(n.h3,{id:"can-i-set-up-a-new-node-to-validate-the-standaloneconsumer-chain-after-it-transitions-to-replicated-security",children:["Can I set up a new node to validate the ",(0,i.jsx)(n.code,{children:"standalone/consumer"})," chain after it transitions to replicated security?"]}),"\n",(0,i.jsx)(n.p,{children:"Yes."}),"\n",(0,i.jsxs)(n.p,{children:["If you are planning to do this please make sure that the node is synced with ",(0,i.jsx)(n.code,{children:"standalone"})," network and to submit ",(0,i.jsx)(n.code,{children:"AssignConsumerKey"})," tx before ",(0,i.jsx)(n.code,{children:"spawn_time"}),"."]}),"\n",(0,i.jsxs)(n.h3,{id:"what-happens-to-the-standalone-validator-set-after-it-transitions-to-replicated-security",children:["What happens to the ",(0,i.jsx)(n.code,{children:"standalone"})," validator set after it transitions to replicated security?"]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"standalone"})," chain validators will stop being validators after the first 3 blocks are created while using replicated security. The ",(0,i.jsx)(n.code,{children:"standalone"})," validators will become ",(0,i.jsx)(n.strong,{children:"governors"})," and still can receive delegations if the ",(0,i.jsx)(n.code,{children:"consumer"})," chain is using the ",(0,i.jsx)(n.code,{children:"consumer-democracy"})," module."]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Governors DO NOT VALIDATE BLOCKS"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"Instead, they can participate in the governance process and take on other chain-specific roles."}),"\n",(0,i.jsx)(n.h2,{id:"credits",children:"Credits"}),"\n",(0,i.jsx)(n.p,{children:"Thank you Stride team for providing detailed instructions about the changeover procedure."})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},7509:(e,n,a)=>{a.d(n,{Z:()=>i});const i=a.p+"assets/images/ics_changeover_timeline_stride-9bcad1834fef24a0fea7f2c80c9ccd71.png"},1151:(e,n,a)=>{a.d(n,{Z:()=>r,a:()=>o});var i=a(7294);const t={},s=i.createContext(t);function o(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/a088363e.e8d00cce.js b/assets/js/a088363e.e8d00cce.js new file mode 100644 index 0000000000..b7ec44f91c --- /dev/null +++ b/assets/js/a088363e.e8d00cce.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6530],{6682:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>d,contentTitle:()=>s,default:()=>h,frontMatter:()=>t,metadata:()=>a,toc:()=>c});var r=o(5893),i=o(1151);const t={sidebar_position:3},s="ICS Provider Proposals",a={id:"features/proposals",title:"ICS Provider Proposals",description:"Interchain security module introduces 3 new proposal types to the provider.",source:"@site/versioned_docs/version-v4.2.0-docs/features/proposals.md",sourceDirName:"features",slug:"/features/proposals",permalink:"/interchain-security/v4.2.0/features/proposals",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Reward Distribution",permalink:"/interchain-security/v4.2.0/features/reward-distribution"},next:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/v4.2.0/features/slashing"}},d={},c=[{value:"<code>ConsumerAdditionProposal</code>",id:"consumeradditionproposal",level:2},{value:"<code>ConsumerRemovalProposal</code>",id:"consumerremovalproposal",level:2},{value:"ChangeRewardDenomProposal",id:"changerewarddenomproposal",level:2}];function l(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"ics-provider-proposals",children:"ICS Provider Proposals"}),"\n",(0,r.jsx)(n.p,{children:"Interchain security module introduces 3 new proposal types to the provider."}),"\n",(0,r.jsx)(n.p,{children:"The proposals are used to propose upcoming interchain security events through governance."}),"\n",(0,r.jsx)(n.h2,{id:"consumeradditionproposal",children:(0,r.jsx)(n.code,{children:"ConsumerAdditionProposal"})}),"\n",(0,r.jsx)(n.admonition,{type:"info",children:(0,r.jsxs)(n.p,{children:["If you are preparing a ",(0,r.jsx)(n.code,{children:"ConsumerAdditionProposal"})," you can find more information in the ",(0,r.jsx)(n.a,{href:"/interchain-security/v4.2.0/consumer-development/onboarding",children:"consumer onboarding checklist"}),"."]})}),"\n",(0,r.jsx)(n.p,{children:"Proposal type used to suggest adding a new consumer chain."}),"\n",(0,r.jsxs)(n.p,{children:["When proposals of this type are passed and the ",(0,r.jsx)(n.code,{children:"spawn_time"})," specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain."]}),"\n",(0,r.jsx)(n.p,{children:"Minimal example:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",children:'{\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n "title": "Add consumer chain",\n "description": ".md description of your chain and all other relevant information",\n "chain_id": "newchain-1",\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Unbonding period for the consumer chain.\n // It should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n "transfer_timeout_period": 1800000000000,\n "consumer_redistribution_fraction": "0.75",\n "blocks_per_distribution_transmission": 1000,\n "historical_entries": 10000,\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n "distribution_transmission_channel": "channel-123",\n "top_N": 95,\n "validators_power_cap": 0,\n "validator_set_cap": 0,\n "allowlist": [],\n "denylist": []\n}\n'})}),"\n",(0,r.jsxs)(n.p,{children:["More examples can be found in the interchain security testnet repository ",(0,r.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/stopped/baryon-1/proposal-baryon-1.json",children:"here"})," and ",(0,r.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/stopped/noble-1/start-proposal-noble-1.json",children:"here"}),"."]}),"\n",(0,r.jsx)(n.h2,{id:"consumerremovalproposal",children:(0,r.jsx)(n.code,{children:"ConsumerRemovalProposal"})}),"\n",(0,r.jsx)(n.p,{children:"Proposal type used to suggest removing an existing consumer chain."}),"\n",(0,r.jsx)(n.p,{children:"When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain.\nAfter the consumer chain removal, the chain in question will no longer be secured by the provider's validator set."}),"\n",(0,r.jsx)(n.admonition,{type:"info",children:(0,r.jsxs)(n.p,{children:["The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain.\nAdditional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set.\nMore information will be made available in the ",(0,r.jsx)(n.a,{href:"/interchain-security/v4.2.0/consumer-development/offboarding",children:"Consumer Offboarding Checklist"}),"."]})}),"\n",(0,r.jsx)(n.p,{children:"Minimal example:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",children:'{\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details"\n}\n'})}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsx)(n.p,{children:'Before the introduction of Partial Set Security, consumer chains typically included a "soft opt-out mechanism"\nwhich allows the bottom N% of the provider\'s validators to not validate the consumer chain, without being jailed for downtime on the provider.\nAfter the introduction of Partial Set Security, the use of the soft opt-out mechanism is discouraged, and consumer chains are\nencouraged to use the topN parameter to not force validators with little stake to validate the chain.'})}),"\n",(0,r.jsx)(n.h2,{id:"changerewarddenomproposal",children:"ChangeRewardDenomProposal"}),"\n",(0,r.jsx)(n.p,{children:"Proposal type used to mutate the set of denoms accepted by the provider as rewards."}),"\n",(0,r.jsx)(n.admonition,{type:"tip",children:(0,r.jsxs)(n.p,{children:["A ",(0,r.jsx)(n.code,{children:"ChangeRewardDenomProposal"})," will only be accepted on the provider chain if at least one of the ",(0,r.jsx)(n.code,{children:"denomsToAdd"})," or ",(0,r.jsx)(n.code,{children:"denomsToRemove"})," fields is populated with at least one denom. Also, a denom cannot be repeated in both sets."]})}),"\n",(0,r.jsx)(n.p,{children:"Minimal example:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",children:'{\n "title": "Add uatom as a reward denom",\n "description": "Here is more information about the proposal",\n "denomsToAdd": ["uatom"],\n "denomsToRemove": []\n}\n'})}),"\n",(0,r.jsxs)(n.admonition,{type:"tip",children:[(0,r.jsxs)(n.p,{children:["Besides native provider denoms (e.g., ",(0,r.jsx)(n.code,{children:"uatom"})," for the Cosmos Hub), please use the ",(0,r.jsx)(n.code,{children:"ibc/*"})," denom trace format.\nFor example, for ",(0,r.jsx)(n.code,{children:"untrn"})," transferred over the path ",(0,r.jsx)(n.code,{children:"transfer/channel-569"}),", the denom trace\ncan be queried using the following command:"]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"> gaiad query ibc-transfer denom-hash transfer/channel-569/untrn\nhash: 0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5\n"})}),(0,r.jsxs)(n.p,{children:["Then use the resulting hash in the ",(0,r.jsx)(n.code,{children:"ChangeRewardDenomProposal"}),", e.g.,"]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",children:'{\n "title": "Add untrn as a reward denom",\n "description": "Here is more information about the proposal",\n "denomsToAdd": ["ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5"],\n "denomsToRemove": []\n}\n'})})]})]})}function h(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},1151:(e,n,o)=>{o.d(n,{Z:()=>a,a:()=>s});var r=o(7294);const i={},t=r.createContext(i);function s(e){const n=r.useContext(t);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:s(e.components),r.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/a09d3327.4f88cf6f.js b/assets/js/a09d3327.4f88cf6f.js new file mode 100644 index 0000000000..2e36b2e63a --- /dev/null +++ b/assets/js/a09d3327.4f88cf6f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8270],{3696:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>r,metadata:()=>a,toc:()=>h});var i=t(5893),s=t(1151);const r={sidebar_position:15,title:"Epochs"},o="ADR 014: Epochs",a={id:"adrs/adr-014-epochs",title:"Epochs",description:"Changelog",source:"@site/docs/adrs/adr-014-epochs.md",sourceDirName:"adrs",slug:"/adrs/adr-014-epochs",permalink:"/interchain-security/adrs/adr-014-epochs",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:15,frontMatter:{sidebar_position:15,title:"Epochs"},sidebar:"tutorialSidebar",previous:{title:"Slashing on the provider for consumer equivocation",permalink:"/interchain-security/adrs/adr-013-equivocation-slashing"},next:{title:"Partial Set Security",permalink:"/interchain-security/adrs/adr-015-partial-set-security"}},c={},h=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function d(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"adr-014-epochs",children:"ADR 014: Epochs"}),"\n",(0,i.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"2024-01-05: Proposed, first draft of ADR."}),"\n",(0,i.jsx)(n.li,{children:"2024-02-29: Updated so that it describes the implementation where we store the whole consumer validator set."}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(n.p,{children:"Accepted"}),"\n",(0,i.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,i.jsxs)(n.p,{children:["In every block that the provider valset changes, a ",(0,i.jsx)(n.code,{children:"VSCPacket"})," must be sent to every consumer and a corresponding ",(0,i.jsx)(n.code,{children:"VSCMaturedPacket"})," sent back.\nGiven that the validator powers may change very often on the provider chain (e.g., the Cosmos Hub), this approach results in a large workload for the relayers.\nAlthough the validator powers may change very often, these changes are usually small and have an insignificant impact on the chain's security.\nIn other words, the valset on the consumers can be slightly outdated without affecting security.\nAs a matter of fact, this already happens due to relaying delays."]}),"\n",(0,i.jsxs)(n.p,{children:["As a solution, this ADR introduces the concept of ",(0,i.jsx)(n.em,{children:"epochs"}),".\nAn epoch consists of multiple blocks.\nThe provider sends ",(0,i.jsx)(n.code,{children:"VSCPacket"}),"s once per epoch.\nA ",(0,i.jsx)(n.code,{children:"VSCPacket"})," contains all the validator updates that are needed by a consumer chain."]}),"\n",(0,i.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,i.jsx)(n.p,{children:"The implementation of epochs requires the following changes:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"For each consumer chain, we store the consumer validator set that is currently (i.e., in this epoch) validating the\nconsumer chain. For each validator in the set we store i) its voting power, and ii) the public key that it is\nusing on the consumer chain during the current (i.e., ongoing) epoch.\nThe initial consumer validator set for a chain is set during the creation of the consumer genesis."}),"\n",(0,i.jsxs)(n.li,{children:["We introduce the ",(0,i.jsx)(n.code,{children:"BlocksPerEpoch"})," param that sets the number of blocks in an epoch. By default, ",(0,i.jsx)(n.code,{children:"BlocksPerEpoch"})," is\nset to be 600 which corresponds to 1 hour, assuming 6 seconds per block. This param can be changed through\na ",(0,i.jsx)(n.em,{children:"governance proposal"}),". In the provider ",(0,i.jsx)(n.code,{children:"EndBlock"})," we check ",(0,i.jsx)(n.code,{children:"BlockHeight() % BlocksPerEpoch() == 0"}),"\nto decide when an epoch has ended."]}),"\n",(0,i.jsxs)(n.li,{children:["At the end of every epoch, if there were validator set changes on the provider, then for every consumer chain, we\nconstruct a ",(0,i.jsx)(n.code,{children:"VSCPacket"})," with all the validator updates and add it to the list of ",(0,i.jsx)(n.code,{children:"PendingVSCPackets"}),". We compute the\nvalidator updates needed by a consumer chain by comparing the stored list of consumer validators with the current\nbonded validators on the provider, with something similar to this:"]}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-go",children:"// get the valset that has been validating the consumer chain during this epoch \ncurrentValidators := GetConsumerValSet(consumerChain)\n// generate the validator updates needed to be sent through a `VSCPacket` by comparing the current validators \n// in the epoch with the latest bonded validators\nvalUpdates := DiffValidators(currentValidators, stakingmodule.GetBondedValidators())\n// update the current validators set for the upcoming epoch to be the latest bonded validators instead\nSetConsumerValSet(stakingmodule.GetBondedValidators())\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Note that a validator can change its consumer public key for a specific consumer chain an arbitrary amount of times during\na block and during an epoch. Then, when we generate the validator updates in ",(0,i.jsx)(n.code,{children:"DiffValidators"}),", we have to check whether\nthe current consumer public key (retrieved by calling ",(0,i.jsx)(n.code,{children:"GetValidatorConsumerPubKey"}),") is different from the consumer public\nkey the validator was using in the current epoch."]}),"\n",(0,i.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,i.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Reduce the cost of relaying."}),"\n",(0,i.jsx)(n.li,{children:"Reduce the amount of IBC packets needed for ICS."}),"\n",(0,i.jsxs)(n.li,{children:["Simplifies ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-001-key-assignment.md",children:"key-assignment code"})," because\nwe only need to check if the ",(0,i.jsx)(n.code,{children:"consumer_public_key"})," has been modified since the last epoch to generate an update."]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Increase the delay in the propagation of validator set changes (but for reasonable epoch lengths on the order of ~hours or less, this is unlikely to be significant)."}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,i.jsx)(n.p,{children:"N/A"}),"\n",(0,i.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/1087",children:"EPIC"})}),"\n"]})]})}function l(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>a,a:()=>o});var i=t(7294);const s={},r=i.createContext(s);function o(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/a2707102.27890462.js b/assets/js/a2707102.27890462.js new file mode 100644 index 0000000000..3836677406 --- /dev/null +++ b/assets/js/a2707102.27890462.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[457],{5077:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>o,contentTitle:()=>c,default:()=>l,frontMatter:()=>s,metadata:()=>a,toc:()=>d});var r=i(5893),t=i(1151);const s={sidebar_position:1,title:"Overview"},c="Overview",a={id:"adrs/intro",title:"Overview",description:"This is a location to record all high-level architecture decisions in the Interchain Security project.",source:"@site/docs/adrs/intro.md",sourceDirName:"adrs",slug:"/adrs/intro",permalink:"/interchain-security/adrs/intro",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1,title:"Overview"},sidebar:"tutorialSidebar",previous:{title:"Frequently Asked Questions",permalink:"/interchain-security/faq"},next:{title:"Denom DOS fixes",permalink:"/interchain-security/adrs/adr-004-denom-dos-fixes"}},o={},d=[{value:"Table of Contents",id:"table-of-contents",level:2},{value:"Accepted",id:"accepted",level:3},{value:"Proposed",id:"proposed",level:3},{value:"Rejected",id:"rejected",level:3},{value:"Deprecated",id:"deprecated",level:3}];function h(e){const n={a:"a",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,t.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"overview",children:"Overview"}),"\n",(0,r.jsx)(n.p,{children:"This is a location to record all high-level architecture decisions in the Interchain Security project."}),"\n",(0,r.jsxs)(n.p,{children:["You can read more about the Architecture Decision Record (ADR) concept in this ",(0,r.jsx)(n.a,{href:"https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0#.78xhdix6t",children:"blog post"}),"."]}),"\n",(0,r.jsx)(n.p,{children:"An ADR should provide:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Context on the relevant goals and the current state"}),"\n",(0,r.jsx)(n.li,{children:"Proposed changes to achieve the goals"}),"\n",(0,r.jsx)(n.li,{children:"Summary of pros and cons"}),"\n",(0,r.jsx)(n.li,{children:"References"}),"\n",(0,r.jsx)(n.li,{children:"Changelog"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and\njustification for a change in architecture, or for the architecture of something\nnew. The spec is much more compressed and streamlined summary of everything as\nit is or should be."}),"\n",(0,r.jsx)(n.p,{children:"If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match."}),"\n",(0,r.jsx)(n.p,{children:"Note the context/background should be written in the present tense."}),"\n",(0,r.jsxs)(n.p,{children:["To suggest an ADR, please make use of the ",(0,r.jsx)(n.a,{href:"./templates/adr-template.md",children:"ADR template"})," provided."]}),"\n",(0,r.jsx)(n.h2,{id:"table-of-contents",children:"Table of Contents"}),"\n",(0,r.jsx)(n.h3,{id:"accepted",children:"Accepted"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/adrs/adr-001-key-assignment",children:"ADR 001: Key Assignment"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/adrs/adr-002-throttle",children:"ADR 002: Jail Throttling"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/adrs/adr-004-denom-dos-fixes",children:"ADR 004: Denom DOS fixes"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/adrs/adr-005-cryptographic-equivocation-verification",children:"ADR 005: Cryptographic verification of equivocation evidence"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/adrs/adr-008-throttle-retries",children:"ADR 008: Throttle with retries"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/adrs/adr-010-standalone-changeover",children:"ADR 010: Standalone to Consumer Changeover"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/adrs/adr-013-equivocation-slashing",children:"ADR 013: Slashing on the provider for consumer equivocation"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/adrs/adr-014-epochs",children:"ADR 014: Epochs"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/adrs/adr-015-partial-set-security",children:"ADR 015: Partial Set Security"})}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"proposed",children:"Proposed"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/adrs/adr-011-improving-test-confidence",children:"ADR 011: Improving testing and increasing confidence"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/adrs/adr-016-securityaggregation",children:"ADR 016: Security aggregation"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/adrs/adr-017-allowing-inactive-validators",children:"ADR 017: ICS with Inactive Provider Validators"})}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"rejected",children:"Rejected"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/adrs/adr-007-pause-unbonding-on-eqv-prop",children:"ADR 007: Pause validator unbonding during equivocation proposal"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/adrs/adr-012-separate-releasing",children:"ADR 012: Separate Releasing"})}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"deprecated",children:"Deprecated"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/adrs/adr-003-equivocation-gov-proposal",children:"ADR 003: Equivocation governance proposal"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/adrs/adr-009-soft-opt-out",children:"ADR 009: Soft Opt-Out"})}),"\n"]})]})}function l(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>a,a:()=>c});var r=i(7294);const t={},s=r.createContext(t);function c(e){const n=r.useContext(s);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:c(e.components),r.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/a6888f58.4bb14d96.js b/assets/js/a6888f58.4bb14d96.js new file mode 100644 index 0000000000..25da85fecd --- /dev/null +++ b/assets/js/a6888f58.4bb14d96.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7487],{4753:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>d,contentTitle:()=>i,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>c});var r=s(5893),t=s(1151);const a={sidebar_position:3,title:"Key Assignment"},i="ADR 001: Key Assignment",o={id:"adrs/adr-001-key-assignment",title:"Key Assignment",description:"Changelog",source:"@site/versioned_docs/version-v5.0.0/adrs/adr-001-key-assignment.md",sourceDirName:"adrs",slug:"/adrs/adr-001-key-assignment",permalink:"/interchain-security/v5.0.0/adrs/adr-001-key-assignment",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Key Assignment"},sidebar:"tutorialSidebar",previous:{title:"ADR Template",permalink:"/interchain-security/v5.0.0/adrs/adr-template"},next:{title:"Jail Throttling",permalink:"/interchain-security/v5.0.0/adrs/adr-002-throttle"}},d={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"State required",id:"state-required",level:3},{value:"Protocol overview",id:"protocol-overview",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,t.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"adr-001-key-assignment",children:"ADR 001: Key Assignment"}),"\n",(0,r.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"2022-12-01: Initial Draft"}),"\n",(0,r.jsx)(n.li,{children:"2024-03-01: Updated to take into account they key-assigment-replacement deprecation."}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,r.jsx)(n.p,{children:"Accepted"}),"\n",(0,r.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,r.jsx)(n.p,{children:"KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate."}),"\n",(0,r.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,r.jsxs)(n.p,{children:["It is possible to change the keys at any time by submitting a transaction (i.e., ",(0,r.jsx)(n.code,{children:"MsgAssignConsumerKey"}),")."]}),"\n",(0,r.jsx)(n.h3,{id:"state-required",children:"State required"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"ValidatorConsumerPubKey"})," - Stores the validator assigned keys for every consumer chain."]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey\n"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"ValidatorByConsumerAddr"})," - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol."]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress\n"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"ConsumerAddrsToPrune"})," - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ",(0,r.jsx)(n.code,{children:"ValidatorByConsumerAddr"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses\n"})}),"\n",(0,r.jsx)(n.h3,{id:"protocol-overview",children:"Protocol overview"}),"\n",(0,r.jsxs)(n.p,{children:["On receiving a ",(0,r.jsx)(n.code,{children:"MsgAssignConsumerKey(chainID, providerAddr, consumerKey)"})," message:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"// get validator from staking module \nvalidator, found := stakingKeeper.GetValidator(providerAddr)\nif !found {\n return ErrNoValidatorFound\n}\nproviderConsAddr := validator.GetConsAddr()\n\n// make sure consumer key is not in use\nconsumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)\nif _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {\n return ErrInvalidConsumerConsensusPubKey\n}\n\n// check whether the consumer chain is already registered\n// i.e., a client to the consumer was already created\nif _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {\n // get the previous key assigned for this validator on this consumer chain\n oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)\n if found {\n // mark this old consumer key as prunable once the VSCMaturedPacket\n // for the current VSC ID is received\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n vscID := GetValidatorSetUpdateId()\n AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)\n }\n} else {\n // if the consumer chain is not registered, then remove the previous reverse mapping\n if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)\n }\n}\n\n\n// set the mapping from this validator's provider address to the new consumer key\nSetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)\n\n// set the reverse mapping: from this validator's new consensus address \n// on the consumer to its consensus address on the provider\nSetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)\n"})}),"\n",(0,r.jsxs)(n.p,{children:["When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see ",(0,r.jsx)(n.code,{children:"MakeConsumerGenesis"}),")."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {\n // ...\n // get initial valset from the staking module\n var updates []abci.ValidatorUpdate{}\n stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {\n validator := stakingKeeper.GetValidator(providerAddr)\n providerKey := validator.TmConsPublicKey()\n\t\tupdates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})\n\t\treturn false\n\t})\n\n // applies the key assignment to the initial validator\n\tfor i, update := range updates {\n\t\tproviderAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)\n\t\tif consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {\n\t\t\tupdates[i].PubKey = consumerKey\n\t\t}\n\t}\n gen.InitialValSet = updates\n\n // get a hash of the consumer validator set from the update\n\tupdatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)\n\thash := tendermint.NewValidatorSet(updatesAsValSet).Hash()\n\n\treturn gen, hash, nil\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Note that key assignment works hand-in-hand with ",(0,r.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-014-epochs.md",children:"epochs"}),".\nFor each consumer chain, we store the consumer validator set that is currently (i.e., in this epoch) validating the consumer chain.\nSpecifically, for each validator in the set we store among others, the public key that it is using on the consumer chain during the current (i.e., ongoing) epoch.\nAt the end of every epoch, if there were validator set changes on the provider, then for every consumer chain, we construct a ",(0,r.jsx)(n.code,{children:"VSCPacket"}),"\nwith all the validator updates and add it to the list of ",(0,r.jsx)(n.code,{children:"PendingVSCPacket"}),"s. We compute the validator updates needed by a consumer chain by\ncomparing the stored list of consumer validators with the current bonded validators on the provider, with something similar to this:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"// get the valset that has been validating the consumer chain during this epoch \ncurrentValidators := GetConsumerValSet(consumerChain)\n// generate the validator updates needed to be sent through a `VSCPacket` by comparing the current validators \n// in the epoch with the latest bonded validators\nvalUpdates := DiffValidators(currentValidators, stakingmodule.GetBondedValidators())\n// update the current validators set for the upcoming epoch to be the latest bonded validators instead\nSetConsumerValSet(stakingmodule.GetBondedValidators())\n"})}),"\n",(0,r.jsxs)(n.p,{children:["where ",(0,r.jsx)(n.code,{children:"DiffValidators"})," internally checks if the consumer public key for a validator has changed since the last\nepoch and if so generates a validator update. This way, a validator can change its consumer public key for a consumer\nchain an arbitrary amount of times and only the last set consumer public key would be taken into account."]}),"\n",(0,r.jsxs)(n.p,{children:["On receiving a ",(0,r.jsx)(n.code,{children:"SlashPacket"})," from a consumer chain with id ",(0,r.jsx)(n.code,{children:"chainID"})," for a infraction of a validator ",(0,r.jsx)(n.code,{children:"data.Validator"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {\n // ...\n // the slash packet validator address may be known only on the consumer chain;\n\t// in this case, it must be mapped back to the consensus address on the provider chain\n consumerAddr := sdk.ConsAddress(data.Validator.Address)\n providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)\n if !found {\n // the validator has the same key on the consumer as on the provider\n providerAddr = consumerAddr\n }\n // ...\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["On receiving a ",(0,r.jsx)(n.code,{children:"VSCMatured"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {\n // ...\n // prune previous consumer validator address that are no longer needed\n consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n\tfor _, addr := range consumerAddrs {\n\t\tDeleteValidatorByConsumerAddr(chainID, addr)\n\t}\n\tDeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n // ...\n}\n"})}),"\n",(0,r.jsx)(n.p,{children:"On stopping a consumer chain:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-golang",children:"func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {\n // ...\n // deletes all the state needed for key assignments on this consumer chain\n // ...\n}\n"})}),"\n",(0,r.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,r.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Validators can use different consensus keys on the consumer chains."}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"None"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["The consensus state necessary to create a client to the consumer chain must use the hash returned by the ",(0,r.jsx)(n.code,{children:"MakeConsumerGenesis"})," method as the ",(0,r.jsx)(n.code,{children:"nextValsHash"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:["The consumer chain can no longer check the initial validator set against the consensus state on ",(0,r.jsx)(n.code,{children:"InitGenesis"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/26",children:"Key assignment issue"})}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},1151:(e,n,s)=>{s.d(n,{Z:()=>o,a:()=>i});var r=s(7294);const t={},a=r.createContext(t);function i(e){const n=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:i(e.components),r.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/a7bd4aaa.687d6c08.js b/assets/js/a7bd4aaa.687d6c08.js new file mode 100644 index 0000000000..74fed2fec3 --- /dev/null +++ b/assets/js/a7bd4aaa.687d6c08.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8518],{8564:(e,n,s)=>{s.r(n),s.d(n,{default:()=>d});s(7294);var r=s(1944),o=s(3320),t=s(4477),i=s(8790),c=s(197),u=s(5893);function a(e){const{version:n}=e;return(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(c.Z,{version:n.version,tag:(0,o.os)(n.pluginId,n.version)}),(0,u.jsx)(r.d,{children:n.noIndex&&(0,u.jsx)("meta",{name:"robots",content:"noindex, nofollow"})})]})}function l(e){const{version:n,route:s}=e;return(0,u.jsx)(r.FG,{className:n.className,children:(0,u.jsx)(t.q,{version:n,children:(0,i.H)(s.routes)})})}function d(e){return(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(a,{...e}),(0,u.jsx)(l,{...e})]})}}}]); \ No newline at end of file diff --git a/assets/js/a8cc50aa.4e815e71.js b/assets/js/a8cc50aa.4e815e71.js new file mode 100644 index 0000000000..9c8b19919d --- /dev/null +++ b/assets/js/a8cc50aa.4e815e71.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[787],{2973:(s,e,a)=>{a.r(e),a.d(e,{assets:()=>h,contentTitle:()=>l,default:()=>d,frontMatter:()=>t,metadata:()=>r,toc:()=>c});var i=a(5893),n=a(1151);const t={sidebar_position:3,title:"Jail Throttling"},l="ADR 002: Jail Throttling",r={id:"adrs/adr-002-throttle",title:"Jail Throttling",description:"Changelog",source:"@site/versioned_docs/version-v5.0.0/adrs/adr-002-throttle.md",sourceDirName:"adrs",slug:"/adrs/adr-002-throttle",permalink:"/interchain-security/v5.0.0/adrs/adr-002-throttle",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Jail Throttling"},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/v5.0.0/adrs/adr-001-key-assignment"},next:{title:"Equivocation governance proposal",permalink:"/interchain-security/v5.0.0/adrs/adr-003-equivocation-gov-proposal"}},h={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Required State",id:"required-state",level:3},{value:"Params",id:"params",level:3},{value:"Protocol Overview",id:"protocol-overview",level:3},{value:"OnRecvSlashPacket",id:"onrecvslashpacket",level:4},{value:"OnRecvVSCMaturedPacket",id:"onrecvvscmaturedpacket",level:4},{value:"Endblocker",id:"endblocker",level:4},{value:"Slash Meter Replenishment",id:"slash-meter-replenishment",level:5},{value:"Handle Leading VSCMaturedPackets",id:"handle-leading-vscmaturedpackets",level:5},{value:"Handle Throttle Queues",id:"handle-throttle-queues",level:5},{value:"System Properties",id:"system-properties",level:3},{value:"Main Throttling Property",id:"main-throttling-property",level:3},{value:"How Unjailing Affects the Main Throttling Property",id:"how-unjailing-affects-the-main-throttling-property",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function m(s){const e={a:"a",annotation:"annotation",blockquote:"blockquote",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",li:"li",math:"math",mfrac:"mfrac",mi:"mi",mn:"mn",mo:"mo",mrow:"mrow",msub:"msub",ol:"ol",p:"p",pre:"pre",semantics:"semantics",span:"span",strong:"strong",ul:"ul",...(0,n.a)(),...s.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"adr-002-jail-throttling",children:"ADR 002: Jail Throttling"}),"\n",(0,i.jsx)(e.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:"2023-01-26: Initial Draft"}),"\n",(0,i.jsx)(e.li,{children:"2023-02-07: Property refined, ADR ready to review/merge"}),"\n",(0,i.jsx)(e.li,{children:"2023-11-22: Refactor for better understanding"}),"\n"]}),"\n",(0,i.jsx)(e.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(e.p,{children:"Accepted"}),"\n",(0,i.jsx)(e.h2,{id:"context",children:"Context"}),"\n",(0,i.jsx)(e.p,{children:"The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols.\nIn practice, this assumption may not hold.\nA malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider."}),"\n",(0,i.jsx)(e.p,{children:"Before the throttling feature was implemented, the following attack was possible.\nAttacker(s) would create provider validators just below the provider's active set.\nUsing a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once.\nControl of the provider would then pass over to the attackers' validators.\nThis enables the attacker(s) to halt the provider.\nOr even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC."}),"\n",(0,i.jsx)(e.h2,{id:"decision",children:"Decision"}),"\n",(0,i.jsx)(e.p,{children:"The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack,\ni.e., this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time."}),"\n",(0,i.jsx)(e.h3,{id:"required-state",children:"Required State"}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:"Slash meter:"})," There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time.\nThis meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params."]}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:"Global entry queue:"}),' There exists a single queue which stores "global slash entries".\nThese entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering.\nThis queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.']}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:"Per-chain data queue:"}),' For each established consumer, there exists a queue which stores "throttled packet data",\ni.e.,pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering.\nOrder is enforced by IBC sequence number.\nThese "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.']}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.em,{children:"Note:"})," The reason for a multiple-queue design is the ",(0,i.jsx)(e.em,{children:"VSC Maturity and Slashing Order"})," property (see ",(0,i.jsx)(e.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing",children:"spec"}),").\nThere are other ways to ensure such a property (like a queue of linked lists, etc.), but the proposed approach seemed to be the most understandable and easiest to implement with a KV store."]}),"\n",(0,i.jsx)(e.h3,{id:"params",children:"Params"}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:"SlashMeterReplenishPeriod"})," -- the period after which the slash meter is replenished."]}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," -- the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs. This param also serves as a maximum fraction of total voting power that the slash meter can hold."]}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:"MaxThrottledPackets"})," -- the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value.\nThis param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness."]}),"\n",(0,i.jsx)(e.h3,{id:"protocol-overview",children:"Protocol Overview"}),"\n",(0,i.jsx)(e.h4,{id:"onrecvslashpacket",children:"OnRecvSlashPacket"}),"\n",(0,i.jsx)(e.p,{children:"Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:"}),"\n",(0,i.jsxs)(e.ol,{children:["\n",(0,i.jsx)(e.li,{children:"A global slash entry is queued."}),"\n",(0,i.jsx)(e.li,{children:"The data of such a packet is added to the per-chain queue."}),"\n"]}),"\n",(0,i.jsx)(e.h4,{id:"onrecvvscmaturedpacket",children:"OnRecvVSCMaturedPacket"}),"\n",(0,i.jsx)(e.p,{children:"Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue."}),"\n",(0,i.jsx)(e.h4,{id:"endblocker",children:"Endblocker"}),"\n",(0,i.jsxs)(e.p,{children:["In the ",(0,i.jsx)(e.code,{children:"EndBlock"})," of the provider CCV module, there are three actions performed:"]}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:"replenish the slash meter;"}),"\n",(0,i.jsxs)(e.li,{children:["handle the leading ",(0,i.jsx)(e.code,{children:"VSCMaturedPackets"}),";"]}),"\n",(0,i.jsx)(e.li,{children:"and handle the throttle queues."}),"\n"]}),"\n",(0,i.jsx)(e.h5,{id:"slash-meter-replenishment",children:"Slash Meter Replenishment"}),"\n",(0,i.jsxs)(e.p,{children:["Once the slash meter becomes not full, it'll be replenished after ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishPeriod"})," by incrementing the meter with its allowance for the replenishment block, where ",(0,i.jsx)(e.code,{children:"allowance"})," = ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," * ",(0,i.jsx)(e.code,{children:"currentTotalVotingPower"}),".\nThe slash meter will never exceed its current allowance (function of the total voting power for the block) in value."]}),"\n",(0,i.jsx)(e.p,{children:"Note a few things:"}),"\n",(0,i.jsxs)(e.ol,{children:["\n",(0,i.jsx)(e.li,{children:"The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power.\nIn such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods."}),"\n",(0,i.jsx)(e.li,{children:"Total voting power of a chain changes over time, especially as validators are jailed.\nAs validators are jailed, total voting power decreases, and so does the jailing allowance.\nSee below for more detailed throttling property discussion."}),"\n",(0,i.jsxs)(e.li,{children:["The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1.\nIf the ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," is set too low, integer rounding will put this minimum value into effect.\nThat is, if ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," * ",(0,i.jsx)(e.code,{children:"currentTotalVotingPower"})," < 1, then the effective allowance would be 1.\nThis min value of allowance ensures that there's some packets handled over time, even if that is a very long time.\nIt's a crude solution to an edge case caused by too small of a replenishment fraction."]}),"\n"]}),"\n",(0,i.jsxs)(e.p,{children:["The behavior described above is achieved by executing ",(0,i.jsx)(e.code,{children:"CheckForSlashMeterReplenishment()"})," every ",(0,i.jsx)(e.code,{children:"EndBlock"}),", BEFORE ",(0,i.jsx)(e.code,{children:"HandleThrottleQueues()"})," is executed."]}),"\n",(0,i.jsx)(e.h5,{id:"handle-leading-vscmaturedpackets",children:"Handle Leading VSCMaturedPackets"}),"\n",(0,i.jsxs)(e.p,{children:["In every block, it is possible that ",(0,i.jsx)(e.code,{children:"VSCMaturedPacket"}),' data was queued before any slash packet data.\nSince this "leading" VSCMatured packet data does not have to be throttled (see ',(0,i.jsx)(e.em,{children:"VSC Maturity and Slashing Order"}),"), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes."]}),"\n",(0,i.jsx)(e.h5,{id:"handle-throttle-queues",children:"Handle Throttle Queues"}),"\n",(0,i.jsxs)(e.p,{children:["In every ",(0,i.jsx)(e.code,{children:"EndBlock"}),", the following logic is executed to handle data from the throttle queues."]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-typescript",children:"meter := getSlashMeter()\n\n// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist \nwhile meter.IsPositiveOrZero() && entriesExist() {\n // Get next entry in queue\n entry := getNextGlobalSlashEntry()\n // Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet\n valPower := entry.getValPower()\n meter = meter - valPower\n // Using the per-chain queue, handle the single slash packet using its queued data,\n // then handle all trailing VSCMatured packets for this consumer\n handleSlashPacketAndTrailingVSCMaturedPackets(entry)\n // Delete entry in global queue, delete handled data\n entry.Delete()\n deleteThrottledSlashPacketData()\n deleteTrailingVSCMaturedPacketData()\n}\n"})}),"\n",(0,i.jsx)(e.h3,{id:"system-properties",children:"System Properties"}),"\n",(0,i.jsxs)(e.p,{children:["All CCV system properties should be maintained by implementing this feature, see ",(0,i.jsx)(e.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing",children:"CCV spec - Consumer Initiated Slashing"}),"."]}),"\n",(0,i.jsxs)(e.p,{children:["One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than ",(0,i.jsx)(e.code,{children:"MaxThrottledPackets"}),", then the provider binary will panic, and the provider chain will halt.\nTherefore this param should be set carefully. See ",(0,i.jsx)(e.code,{children:"SetThrottledPacketDataSize"}),".\nThis behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators."]}),"\n",(0,i.jsx)(e.h3,{id:"main-throttling-property",children:"Main Throttling Property"}),"\n",(0,i.jsx)(e.p,{children:"Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions."}),"\n",(0,i.jsx)(e.p,{children:"First, we introduce the following definitions:"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:'A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.'}),"\n",(0,i.jsx)(e.li,{children:'The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.'}),"\n",(0,i.jsxs)(e.li,{children:["There is a list of honest validators such that if they are jailed, ",(0,i.jsx)(e.code,{children:"X"}),"% of the initial validator set will be jailed."]}),"\n"]}),"\n",(0,i.jsx)(e.p,{children:"For the Throttling Property to hold, the following assumptions must be true:"}),"\n",(0,i.jsxs)(e.ol,{children:["\n",(0,i.jsx)(e.li,{children:"We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack."}),"\n",(0,i.jsxs)(e.li,{children:["No validator has more than ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," of total voting power on the provider."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," is large enough that ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," * ",(0,i.jsx)(e.code,{children:"currentTotalVotingPower"})," > 1,\ni.e., the replenish fraction is set high enough that we can ignore the effects of rounding."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:"SlashMeterReplenishPeriod"})," is sufficiently longer than the time it takes to produce a block."]}),"\n"]}),"\n",(0,i.jsx)(e.p,{children:(0,i.jsx)(e.em,{children:"Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined."})}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:"Throttling Property"}),": The time it takes to jail/tombstone ",(0,i.jsx)(e.code,{children:"X"}),"% of the initial validator set will be greater than or equal to\n",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"S"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"M"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"R"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"p"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"n"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"P"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"o"}),(0,i.jsx)(e.mi,{children:"d"})]}),(0,i.jsx)(e.mo,{children:"\u22c5"}),(0,i.jsxs)(e.mfrac,{children:[(0,i.jsx)(e.mi,{children:"X"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"S"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"M"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"R"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"p"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"n"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"F"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"c"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"o"}),(0,i.jsx)(e.mi,{children:"n"})]})]}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mn,{children:"2"}),(0,i.jsx)(e.mo,{children:"\u22c5"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"S"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"M"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"R"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"p"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"n"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"P"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"o"}),(0,i.jsx)(e.mi,{children:"d"})]})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\mathit{SlashMeterReplenishPeriod} \\cdot \\frac{X}{\\mathit{SlashMeterReplenishFraction}} - 2 \\cdot \\mathit{SlashMeterReplenishPeriod}"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,i.jsx)(e.span,{className:"mord",children:(0,i.jsx)(e.span,{className:"mord mathit",children:"SlashMeterReplenishPeriod"})}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u22c5"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"1.3534em",verticalAlign:"-0.4811em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,i.jsx)(e.span,{className:"mfrac",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsxs)(e.span,{className:"vlist",style:{height:"0.8723em"},children:[(0,i.jsxs)(e.span,{style:{top:"-2.655em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"SlashMeterReplenishFraction"})})})})]}),(0,i.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,i.jsxs)(e.span,{style:{top:"-3.394em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.07847em"},children:"X"})})})]})]}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.4811em"},children:(0,i.jsx)(e.span,{})})})]})}),(0,i.jsx)(e.span,{className:"mclose nulldelimiter"})]}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6444em"}}),(0,i.jsx)(e.span,{className:"mord",children:"2"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u22c5"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,i.jsx)(e.span,{className:"mord",children:(0,i.jsx)(e.span,{className:"mord mathit",children:"SlashMeterReplenishPeriod"})})]})]})]}),"."]}),"\n",(0,i.jsxs)(e.blockquote,{children:["\n",(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:"Intuition"})}),"\n",(0,i.jsx)(e.p,{children:"Let's use the following notation:"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:[(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"C"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"})]})})]}),": Number of replenishment cycles"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"P"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"P"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"P"})]})})]}),": ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"S"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"M"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"R"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"p"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"n"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"P"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"o"}),(0,i.jsx)(e.mi,{children:"d"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\mathit{SlashMeterReplenishPeriod}"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,i.jsx)(e.span,{className:"mord",children:(0,i.jsx)(e.span,{className:"mord mathit",children:"SlashMeterReplenishPeriod"})})]})})]})]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"F"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"F"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"})]})})]}),": ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"S"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"M"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"R"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"p"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"n"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"F"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"c"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"o"}),(0,i.jsx)(e.mi,{children:"n"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\mathit{SlashMeterReplenishFraction}"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,i.jsx)(e.span,{className:"mord",children:(0,i.jsx)(e.span,{className:"mord mathit",children:"SlashMeterReplenishFraction"})})]})})]})]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsxs)(e.msub,{children:[(0,i.jsx)(e.mi,{children:"V"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"m"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"x"})]})]})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"V_{\\mathit{max}}"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.22222em"},children:"V"}),(0,i.jsx)(e.span,{className:"msupsub",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.1514em"},children:(0,i.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.2222em",marginRight:"0.05em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"max"})})})})]})}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,i.jsx)(e.span,{})})})]})})]})]})})]}),": Max power of a validator as a fraction of total voting power"]}),"\n"]}),"\n",(0,i.jsxs)(e.p,{children:["In ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"C"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"})]})})]})," number of replenishment cycles, the fraction of total voting power that can be removed, ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"a"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"a"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.4306em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",children:"a"})]})})]}),", is ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mo,{children:"\u2264"}),(0,i.jsx)(e.mi,{children:"F"}),(0,i.jsx)(e.mo,{children:"\u22c5"}),(0,i.jsx)(e.mi,{children:"C"}),(0,i.jsx)(e.mo,{children:"+"}),(0,i.jsxs)(e.msub,{children:[(0,i.jsx)(e.mi,{children:"V"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"m"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"x"})]})]})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"a \\leq F \\cdot C + V_{\\mathit{max}}"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.7719em",verticalAlign:"-0.136em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",children:"a"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,i.jsx)(e.span,{className:"mrel",children:"\u2264"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u22c5"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.7667em",verticalAlign:"-0.0833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"+"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.22222em"},children:"V"}),(0,i.jsx)(e.span,{className:"msupsub",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.1514em"},children:(0,i.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.2222em",marginRight:"0.05em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"max"})})})})]})}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,i.jsx)(e.span,{})})})]})})]})]})]})]})," (where ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsxs)(e.msub,{children:[(0,i.jsx)(e.mi,{children:"V"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"m"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"x"})]})]})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"V_{\\mathit{max}}"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.22222em"},children:"V"}),(0,i.jsx)(e.span,{className:"msupsub",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.1514em"},children:(0,i.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.2222em",marginRight:"0.05em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"max"})})})})]})}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,i.jsx)(e.span,{})})})]})})]})]})})]})," is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value)."]}),"\n",(0,i.jsxs)(e.p,{children:["So, we need at least ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"C"}),(0,i.jsx)(e.mo,{children:"\u2265"}),(0,i.jsxs)(e.mfrac,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsxs)(e.msub,{children:[(0,i.jsx)(e.mi,{children:"V"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"m"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"x"})]})]})]}),(0,i.jsx)(e.mi,{children:"F"})]})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C \\geq \\frac{a - V_{\\mathit{max}}}{F}"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8193em",verticalAlign:"-0.136em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,i.jsx)(e.span,{className:"mrel",children:"\u2265"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"1.2334em",verticalAlign:"-0.345em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,i.jsx)(e.span,{className:"mfrac",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsxs)(e.span,{className:"vlist",style:{height:"0.8884em"},children:[(0,i.jsxs)(e.span,{style:{top:"-2.655em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"})})})]}),(0,i.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,i.jsxs)(e.span,{style:{top:"-3.4101em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mord mathnormal mtight",children:"a"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u2212"}),(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.22222em"},children:"V"}),(0,i.jsx)(e.span,{className:"msupsub",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.1645em"},children:(0,i.jsxs)(e.span,{style:{top:"-2.357em",marginLeft:"-0.2222em",marginRight:"0.0714em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"2.5em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size3 size1 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"max"})})})})]})}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.143em"},children:(0,i.jsx)(e.span,{})})})]})})]})]})})]})]}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.345em"},children:(0,i.jsx)(e.span,{})})})]})}),(0,i.jsx)(e.span,{className:"mclose nulldelimiter"})]})]})]})]})," cycles to remove ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"a"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"a"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.4306em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",children:"a"})]})})]})," fraction of the total voting power."]}),"\n",(0,i.jsxs)(e.p,{children:["Since we defined the start of the attack to be the moment when the first slash request arrives, then ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"F"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"F"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"})]})})]})," fraction of the initial validator set can be jailed immediately. For the remaining ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"X"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mi,{children:"F"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"X - F"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.7667em",verticalAlign:"-0.0833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07847em"},children:"X"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"})]})]})]})," fraction of the initial validator set to be jailed, it takes at least ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"C"}),(0,i.jsx)(e.mo,{children:"\u2265"}),(0,i.jsxs)(e.mfrac,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mo,{stretchy:"false",children:"("}),(0,i.jsx)(e.mi,{children:"X"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mi,{children:"F"}),(0,i.jsx)(e.mo,{stretchy:"false",children:")"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsxs)(e.msub,{children:[(0,i.jsx)(e.mi,{children:"V"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"m"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"x"})]})]})]}),(0,i.jsx)(e.mi,{children:"F"})]})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C \\geq \\frac{(X - F) - V_{\\mathit{max}}}{F}"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8193em",verticalAlign:"-0.136em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,i.jsx)(e.span,{className:"mrel",children:"\u2265"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"1.355em",verticalAlign:"-0.345em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,i.jsx)(e.span,{className:"mfrac",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsxs)(e.span,{className:"vlist",style:{height:"1.01em"},children:[(0,i.jsxs)(e.span,{style:{top:"-2.655em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"})})})]}),(0,i.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,i.jsxs)(e.span,{style:{top:"-3.485em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mopen mtight",children:"("}),(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.07847em"},children:"X"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"}),(0,i.jsx)(e.span,{className:"mclose mtight",children:")"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u2212"}),(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.22222em"},children:"V"}),(0,i.jsx)(e.span,{className:"msupsub",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.1645em"},children:(0,i.jsxs)(e.span,{style:{top:"-2.357em",marginLeft:"-0.2222em",marginRight:"0.0714em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"2.5em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size3 size1 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"max"})})})})]})}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.143em"},children:(0,i.jsx)(e.span,{})})})]})})]})]})})]})]}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.345em"},children:(0,i.jsx)(e.span,{})})})]})}),(0,i.jsx)(e.span,{className:"mclose nulldelimiter"})]})]})]})]})," cycles. Using the assumption that ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsxs)(e.msub,{children:[(0,i.jsx)(e.mi,{children:"V"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"m"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"x"})]})]}),(0,i.jsx)(e.mo,{children:"\u2264"}),(0,i.jsx)(e.mi,{children:"F"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"V_{\\mathit{max}} \\leq F"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.22222em"},children:"V"}),(0,i.jsx)(e.span,{className:"msupsub",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.1514em"},children:(0,i.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.2222em",marginRight:"0.05em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"max"})})})})]})}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,i.jsx)(e.span,{})})})]})})]}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,i.jsx)(e.span,{className:"mrel",children:"\u2264"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"})]})]})]})," (assumption 2), we get ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"C"}),(0,i.jsx)(e.mo,{children:"\u2265"}),(0,i.jsxs)(e.mfrac,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"X"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mn,{children:"2"}),(0,i.jsx)(e.mi,{children:"F"})]}),(0,i.jsx)(e.mi,{children:"F"})]})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C \\geq \\frac{X - 2F}{F}"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8193em",verticalAlign:"-0.136em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,i.jsx)(e.span,{className:"mrel",children:"\u2265"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"1.2173em",verticalAlign:"-0.345em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,i.jsx)(e.span,{className:"mfrac",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsxs)(e.span,{className:"vlist",style:{height:"0.8723em"},children:[(0,i.jsxs)(e.span,{style:{top:"-2.655em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"})})})]}),(0,i.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,i.jsxs)(e.span,{style:{top:"-3.394em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.07847em"},children:"X"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mord mtight",children:"2"}),(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"})]})})]})]}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.345em"},children:(0,i.jsx)(e.span,{})})})]})}),(0,i.jsx)(e.span,{className:"mclose nulldelimiter"})]})]})]})]})," cycles."]}),"\n",(0,i.jsxs)(e.p,{children:["In order to execute ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"C"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"})]})})]})," cycles, we need ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"C"}),(0,i.jsx)(e.mo,{children:"\u22c5"}),(0,i.jsx)(e.mi,{children:"P"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C \\cdot P"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u22c5"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"P"})]})]})]})," time."]}),"\n",(0,i.jsxs)(e.p,{children:["Thus, jailing the remaining ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"X"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mi,{children:"F"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"X - F"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.7667em",verticalAlign:"-0.0833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07847em"},children:"X"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"})]})]})]})," fraction of the initial validator set corresponds to ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsxs)(e.mfrac,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"P"}),(0,i.jsx)(e.mo,{children:"\u22c5"}),(0,i.jsx)(e.mo,{stretchy:"false",children:"("}),(0,i.jsx)(e.mi,{children:"X"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mn,{children:"2"}),(0,i.jsx)(e.mi,{children:"F"}),(0,i.jsx)(e.mo,{stretchy:"false",children:")"})]}),(0,i.jsx)(e.mi,{children:"F"})]})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\frac{P \\cdot (X - 2F)}{F}"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"1.355em",verticalAlign:"-0.345em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,i.jsx)(e.span,{className:"mfrac",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsxs)(e.span,{className:"vlist",style:{height:"1.01em"},children:[(0,i.jsxs)(e.span,{style:{top:"-2.655em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"})})})]}),(0,i.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,i.jsxs)(e.span,{style:{top:"-3.485em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"P"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u22c5"}),(0,i.jsx)(e.span,{className:"mopen mtight",children:"("}),(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.07847em"},children:"X"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mord mtight",children:"2"}),(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"}),(0,i.jsx)(e.span,{className:"mclose mtight",children:")"})]})})]})]}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.345em"},children:(0,i.jsx)(e.span,{})})})]})}),(0,i.jsx)(e.span,{className:"mclose nulldelimiter"})]})]})})]})," time."]}),"\n",(0,i.jsxs)(e.p,{children:["In other words, the attack must take at least ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsxs)(e.mfrac,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"P"}),(0,i.jsx)(e.mo,{children:"\u22c5"}),(0,i.jsx)(e.mi,{children:"X"})]}),(0,i.jsx)(e.mi,{children:"F"})]}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mn,{children:"2"}),(0,i.jsx)(e.mi,{children:"P"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\frac{P \\cdot X}{F} - 2P"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"1.2173em",verticalAlign:"-0.345em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,i.jsx)(e.span,{className:"mfrac",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsxs)(e.span,{className:"vlist",style:{height:"0.8723em"},children:[(0,i.jsxs)(e.span,{style:{top:"-2.655em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"})})})]}),(0,i.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,i.jsxs)(e.span,{style:{top:"-3.394em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"P"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u22c5"}),(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.07847em"},children:"X"})]})})]})]}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.345em"},children:(0,i.jsx)(e.span,{})})})]})}),(0,i.jsx)(e.span,{className:"mclose nulldelimiter"})]}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord",children:"2"}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"P"})]})]})]})," time (in the units of replenish period ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"P"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"P"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"P"})]})})]}),")."]}),"\n"]}),"\n",(0,i.jsxs)(e.p,{children:["This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests.\nFor example, if ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," is set to ",(0,i.jsx)(e.code,{children:"0.06"}),", then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub.\nNote that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power."]}),"\n",(0,i.jsx)(e.p,{children:"Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings."}),"\n",(0,i.jsx)(e.h3,{id:"how-unjailing-affects-the-main-throttling-property",children:"How Unjailing Affects the Main Throttling Property"}),"\n",(0,i.jsx)(e.p,{children:"Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained."}),"\n",(0,i.jsx)(e.p,{children:"If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider."}),"\n",(0,i.jsx)(e.p,{children:"In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack."}),"\n",(0,i.jsx)(e.h2,{id:"consequences",children:"Consequences"}),"\n",(0,i.jsx)(e.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:"The described attack is slowed down in seemingly all cases."}),"\n",(0,i.jsx)(e.li,{children:"If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded."}),"\n"]}),"\n",(0,i.jsx)(e.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:["Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below.\nHowever, this is sacrificing liveness in a edge case scenario for the sake of security.\nAs an improvement, ",(0,i.jsx)(e.a,{href:"https://github.com/cosmos/interchain-security/issues/713",children:"using retries"})," would fully prevent this attack vector."]}),"\n"]}),"\n",(0,i.jsx)(e.h3,{id:"neutral",children:"Neutral"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:"Additional state is introduced to the provider chain."}),"\n",(0,i.jsx)(e.li,{children:"VSCMatured and slash packet data is not always handled in the same block that it is received."}),"\n"]}),"\n",(0,i.jsx)(e.h2,{id:"references",children:"References"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:"https://github.com/cosmos/interchain-security/issues/404",children:"Original issue inspiring throttling feature"})}),"\n",(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:"https://github.com/cosmos/interchain-security/issues/594",children:"Issue on DOS vector"})}),"\n",(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:"https://github.com/cosmos/interchain-security/issues/685",children:"Consideration of another attack vector"})}),"\n"]})]})}function d(s={}){const{wrapper:e}={...(0,n.a)(),...s.components};return e?(0,i.jsx)(e,{...s,children:(0,i.jsx)(m,{...s})}):m(s)}},1151:(s,e,a)=>{a.d(e,{Z:()=>r,a:()=>l});var i=a(7294);const n={},t=i.createContext(n);function l(s){const e=i.useContext(t);return i.useMemo((function(){return"function"==typeof s?s(e):{...e,...s}}),[e,s])}function r(s){let e;return e=s.disableParentContext?"function"==typeof s.components?s.components(n):s.components||n:l(s.components),i.createElement(t.Provider,{value:e},s.children)}}}]); \ No newline at end of file diff --git a/assets/js/a94703ab.3856b628.js b/assets/js/a94703ab.3856b628.js new file mode 100644 index 0000000000..e887c1dcf3 --- /dev/null +++ b/assets/js/a94703ab.3856b628.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4368],{2674:(e,t,n)=>{n.r(t),n.d(t,{default:()=>be});var a=n(7294),o=n(512),i=n(1944),s=n(5281),l=n(2802),r=n(1116),c=n(5999),d=n(2466),u=n(5936);const m={backToTopButton:"backToTopButton_sjWU",backToTopButtonShow:"backToTopButtonShow_xfvO"};var b=n(5893);function h(){const{shown:e,scrollToTop:t}=function(e){let{threshold:t}=e;const[n,o]=(0,a.useState)(!1),i=(0,a.useRef)(!1),{startScroll:s,cancelScroll:l}=(0,d.Ct)();return(0,d.RF)(((e,n)=>{let{scrollY:a}=e;const s=n?.scrollY;s&&(i.current?i.current=!1:a>=s?(l(),o(!1)):a<t?o(!1):a+window.innerHeight<document.documentElement.scrollHeight&&o(!0))})),(0,u.S)((e=>{e.location.hash&&(i.current=!0,o(!1))})),{shown:n,scrollToTop:()=>s(0)}}({threshold:300});return(0,b.jsx)("button",{"aria-label":(0,c.I)({id:"theme.BackToTopButton.buttonAriaLabel",message:"Scroll back to top",description:"The ARIA label for the back to top button"}),className:(0,o.Z)("clean-btn",s.k.common.backToTopButton,m.backToTopButton,e&&m.backToTopButtonShow),type:"button",onClick:t})}var p=n(1442),x=n(6550),f=n(7524),j=n(6668),k=n(1327);function _(e){return(0,b.jsx)("svg",{width:"20",height:"20","aria-hidden":"true",...e,children:(0,b.jsxs)("g",{fill:"#7a7a7a",children:[(0,b.jsx)("path",{d:"M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"}),(0,b.jsx)("path",{d:"M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"})]})})}const v={collapseSidebarButton:"collapseSidebarButton_PEFL",collapseSidebarButtonIcon:"collapseSidebarButtonIcon_kv0_"};function g(e){let{onClick:t}=e;return(0,b.jsx)("button",{type:"button",title:(0,c.I)({id:"theme.docs.sidebar.collapseButtonTitle",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),"aria-label":(0,c.I)({id:"theme.docs.sidebar.collapseButtonAriaLabel",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),className:(0,o.Z)("button button--secondary button--outline",v.collapseSidebarButton),onClick:t,children:(0,b.jsx)(_,{className:v.collapseSidebarButtonIcon})})}var C=n(9689),S=n(902);const I=Symbol("EmptyContext"),N=a.createContext(I);function T(e){let{children:t}=e;const[n,o]=(0,a.useState)(null),i=(0,a.useMemo)((()=>({expandedItem:n,setExpandedItem:o})),[n]);return(0,b.jsx)(N.Provider,{value:i,children:t})}var B=n(6043),Z=n(8596),A=n(9960),L=n(2389);function y(e){let{collapsed:t,categoryLabel:n,onClick:a}=e;return(0,b.jsx)("button",{"aria-label":t?(0,c.I)({id:"theme.DocSidebarItem.expandCategoryAriaLabel",message:"Expand sidebar category '{label}'",description:"The ARIA label to expand the sidebar category"},{label:n}):(0,c.I)({id:"theme.DocSidebarItem.collapseCategoryAriaLabel",message:"Collapse sidebar category '{label}'",description:"The ARIA label to collapse the sidebar category"},{label:n}),type:"button",className:"clean-btn menu__caret",onClick:a})}function w(e){let{item:t,onItemClick:n,activePath:i,level:r,index:c,...d}=e;const{items:u,label:m,collapsible:h,className:p,href:x}=t,{docs:{sidebar:{autoCollapseCategories:f}}}=(0,j.L)(),k=function(e){const t=(0,L.Z)();return(0,a.useMemo)((()=>e.href&&!e.linkUnlisted?e.href:!t&&e.collapsible?(0,l.LM)(e):void 0),[e,t])}(t),_=(0,l._F)(t,i),v=(0,Z.Mg)(x,i),{collapsed:g,setCollapsed:C}=(0,B.u)({initialState:()=>!!h&&(!_&&t.collapsed)}),{expandedItem:T,setExpandedItem:w}=function(){const e=(0,a.useContext)(N);if(e===I)throw new S.i6("DocSidebarItemsExpandedStateProvider");return e}(),E=function(e){void 0===e&&(e=!g),w(e?null:c),C(e)};return function(e){let{isActive:t,collapsed:n,updateCollapsed:o}=e;const i=(0,S.D9)(t);(0,a.useEffect)((()=>{t&&!i&&n&&o(!1)}),[t,i,n,o])}({isActive:_,collapsed:g,updateCollapsed:E}),(0,a.useEffect)((()=>{h&&null!=T&&T!==c&&f&&C(!0)}),[h,T,c,C,f]),(0,b.jsxs)("li",{className:(0,o.Z)(s.k.docs.docSidebarItemCategory,s.k.docs.docSidebarItemCategoryLevel(r),"menu__list-item",{"menu__list-item--collapsed":g},p),children:[(0,b.jsxs)("div",{className:(0,o.Z)("menu__list-item-collapsible",{"menu__list-item-collapsible--active":v}),children:[(0,b.jsx)(A.Z,{className:(0,o.Z)("menu__link",{"menu__link--sublist":h,"menu__link--sublist-caret":!x&&h,"menu__link--active":_}),onClick:h?e=>{n?.(t),x?E(!1):(e.preventDefault(),E())}:()=>{n?.(t)},"aria-current":v?"page":void 0,"aria-expanded":h?!g:void 0,href:h?k??"#":k,...d,children:m}),x&&h&&(0,b.jsx)(y,{collapsed:g,categoryLabel:m,onClick:e=>{e.preventDefault(),E()}})]}),(0,b.jsx)(B.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:g,children:(0,b.jsx)(V,{items:u,tabIndex:g?-1:0,onItemClick:n,activePath:i,level:r+1})})]})}var E=n(3919),H=n(9471);const M={menuExternalLink:"menuExternalLink_NmtK"};function R(e){let{item:t,onItemClick:n,activePath:a,level:i,index:r,...c}=e;const{href:d,label:u,className:m,autoAddBaseUrl:h}=t,p=(0,l._F)(t,a),x=(0,E.Z)(d);return(0,b.jsx)("li",{className:(0,o.Z)(s.k.docs.docSidebarItemLink,s.k.docs.docSidebarItemLinkLevel(i),"menu__list-item",m),children:(0,b.jsxs)(A.Z,{className:(0,o.Z)("menu__link",!x&&M.menuExternalLink,{"menu__link--active":p}),autoAddBaseUrl:h,"aria-current":p?"page":void 0,to:d,...x&&{onClick:n?()=>n(t):void 0},...c,children:[u,!x&&(0,b.jsx)(H.Z,{})]})},u)}const W={menuHtmlItem:"menuHtmlItem_M9Kj"};function F(e){let{item:t,level:n,index:a}=e;const{value:i,defaultStyle:l,className:r}=t;return(0,b.jsx)("li",{className:(0,o.Z)(s.k.docs.docSidebarItemLink,s.k.docs.docSidebarItemLinkLevel(n),l&&[W.menuHtmlItem,"menu__list-item"],r),dangerouslySetInnerHTML:{__html:i}},a)}function P(e){let{item:t,...n}=e;switch(t.type){case"category":return(0,b.jsx)(w,{item:t,...n});case"html":return(0,b.jsx)(F,{item:t,...n});default:return(0,b.jsx)(R,{item:t,...n})}}function D(e){let{items:t,...n}=e;const a=(0,l.f)(t,n.activePath);return(0,b.jsx)(T,{children:a.map(((e,t)=>(0,b.jsx)(P,{item:e,index:t,...n},t)))})}const V=(0,a.memo)(D),U={menu:"menu_SIkG",menuWithAnnouncementBar:"menuWithAnnouncementBar_GW3s"};function K(e){let{path:t,sidebar:n,className:i}=e;const l=function(){const{isActive:e}=(0,C.nT)(),[t,n]=(0,a.useState)(e);return(0,d.RF)((t=>{let{scrollY:a}=t;e&&n(0===a)}),[e]),e&&t}();return(0,b.jsx)("nav",{"aria-label":(0,c.I)({id:"theme.docs.sidebar.navAriaLabel",message:"Docs sidebar",description:"The ARIA label for the sidebar navigation"}),className:(0,o.Z)("menu thin-scrollbar",U.menu,l&&U.menuWithAnnouncementBar,i),children:(0,b.jsx)("ul",{className:(0,o.Z)(s.k.docs.docSidebarMenu,"menu__list"),children:(0,b.jsx)(V,{items:n,activePath:t,level:1})})})}const Y="sidebar_njMd",z="sidebarWithHideableNavbar_wUlq",G="sidebarHidden_VK0M",O="sidebarLogo_isFc";function q(e){let{path:t,sidebar:n,onCollapse:a,isHidden:i}=e;const{navbar:{hideOnScroll:s},docs:{sidebar:{hideable:l}}}=(0,j.L)();return(0,b.jsxs)("div",{className:(0,o.Z)(Y,s&&z,i&&G),children:[s&&(0,b.jsx)(k.Z,{tabIndex:-1,className:O}),(0,b.jsx)(K,{path:t,sidebar:n}),l&&(0,b.jsx)(g,{onClick:a})]})}const J=a.memo(q);var Q=n(3102),X=n(2961);const $=e=>{let{sidebar:t,path:n}=e;const a=(0,X.e)();return(0,b.jsx)("ul",{className:(0,o.Z)(s.k.docs.docSidebarMenu,"menu__list"),children:(0,b.jsx)(V,{items:t,activePath:n,onItemClick:e=>{"category"===e.type&&e.href&&a.toggle(),"link"===e.type&&a.toggle()},level:1})})};function ee(e){return(0,b.jsx)(Q.Zo,{component:$,props:e})}const te=a.memo(ee);function ne(e){const t=(0,f.i)(),n="desktop"===t||"ssr"===t,a="mobile"===t;return(0,b.jsxs)(b.Fragment,{children:[n&&(0,b.jsx)(J,{...e}),a&&(0,b.jsx)(te,{...e})]})}const ae={expandButton:"expandButton_TmdG",expandButtonIcon:"expandButtonIcon_i1dp"};function oe(e){let{toggleSidebar:t}=e;return(0,b.jsx)("div",{className:ae.expandButton,title:(0,c.I)({id:"theme.docs.sidebar.expandButtonTitle",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),"aria-label":(0,c.I)({id:"theme.docs.sidebar.expandButtonAriaLabel",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),tabIndex:0,role:"button",onKeyDown:t,onClick:t,children:(0,b.jsx)(_,{className:ae.expandButtonIcon})})}const ie={docSidebarContainer:"docSidebarContainer_YfHR",docSidebarContainerHidden:"docSidebarContainerHidden_DPk8",sidebarViewport:"sidebarViewport_aRkj"};function se(e){let{children:t}=e;const n=(0,r.V)();return(0,b.jsx)(a.Fragment,{children:t},n?.name??"noSidebar")}function le(e){let{sidebar:t,hiddenSidebarContainer:n,setHiddenSidebarContainer:i}=e;const{pathname:l}=(0,x.TH)(),[r,c]=(0,a.useState)(!1),d=(0,a.useCallback)((()=>{r&&c(!1),!r&&(0,p.n)()&&c(!0),i((e=>!e))}),[i,r]);return(0,b.jsx)("aside",{className:(0,o.Z)(s.k.docs.docSidebarContainer,ie.docSidebarContainer,n&&ie.docSidebarContainerHidden),onTransitionEnd:e=>{e.currentTarget.classList.contains(ie.docSidebarContainer)&&n&&c(!0)},children:(0,b.jsx)(se,{children:(0,b.jsxs)("div",{className:(0,o.Z)(ie.sidebarViewport,r&&ie.sidebarViewportHidden),children:[(0,b.jsx)(ne,{sidebar:t,path:l,onCollapse:d,isHidden:r}),r&&(0,b.jsx)(oe,{toggleSidebar:d})]})})})}const re={docMainContainer:"docMainContainer_TBSr",docMainContainerEnhanced:"docMainContainerEnhanced_lQrH",docItemWrapperEnhanced:"docItemWrapperEnhanced_JWYK"};function ce(e){let{hiddenSidebarContainer:t,children:n}=e;const a=(0,r.V)();return(0,b.jsx)("main",{className:(0,o.Z)(re.docMainContainer,(t||!a)&&re.docMainContainerEnhanced),children:(0,b.jsx)("div",{className:(0,o.Z)("container padding-top--md padding-bottom--lg",re.docItemWrapper,t&&re.docItemWrapperEnhanced),children:n})})}const de={docRoot:"docRoot_UBD9",docsWrapper:"docsWrapper_hBAB"};function ue(e){let{children:t}=e;const n=(0,r.V)(),[o,i]=(0,a.useState)(!1);return(0,b.jsxs)("div",{className:de.docsWrapper,children:[(0,b.jsx)(h,{}),(0,b.jsxs)("div",{className:de.docRoot,children:[n&&(0,b.jsx)(le,{sidebar:n.items,hiddenSidebarContainer:o,setHiddenSidebarContainer:i}),(0,b.jsx)(ce,{hiddenSidebarContainer:o,children:t})]})]})}var me=n(5658);function be(e){const t=(0,l.SN)(e);if(!t)return(0,b.jsx)(me.Z,{});const{docElement:n,sidebarName:a,sidebarItems:c}=t;return(0,b.jsx)(i.FG,{className:(0,o.Z)(s.k.page.docsDocPage),children:(0,b.jsx)(r.b,{name:a,items:c,children:(0,b.jsx)(ue,{children:n})})})}},5658:(e,t,n)=>{n.d(t,{Z:()=>l});n(7294);var a=n(512),o=n(5999),i=n(2503),s=n(5893);function l(e){let{className:t}=e;return(0,s.jsx)("main",{className:(0,a.Z)("container margin-vert--xl",t),children:(0,s.jsx)("div",{className:"row",children:(0,s.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,s.jsx)(i.Z,{as:"h1",className:"hero__title",children:(0,s.jsx)(o.Z,{id:"theme.NotFound.title",description:"The title of the 404 page",children:"Page Not Found"})}),(0,s.jsx)("p",{children:(0,s.jsx)(o.Z,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page",children:"We could not find what you were looking for."})}),(0,s.jsx)("p",{children:(0,s.jsx)(o.Z,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page",children:"Please contact the owner of the site that linked you to the original URL and let them know their link is broken."})})]})})})}}}]); \ No newline at end of file diff --git a/assets/js/a95292b9.5acfbcd2.js b/assets/js/a95292b9.5acfbcd2.js new file mode 100644 index 0000000000..492fa13b08 --- /dev/null +++ b/assets/js/a95292b9.5acfbcd2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5474],{3623:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>s,contentTitle:()=>c,default:()=>l,frontMatter:()=>a,metadata:()=>r,toc:()=>h});var i=o(5893),t=o(1151);const a={sidebar_position:1},c="Developing an ICS consumer chain",r={id:"consumer-development/app-integration",title:"Developing an ICS consumer chain",description:"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.",source:"@site/versioned_docs/version-v4.2.0-docs/consumer-development/app-integration.md",sourceDirName:"consumer-development",slug:"/consumer-development/app-integration",permalink:"/interchain-security/v4.2.0/consumer-development/app-integration",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Power Shaping",permalink:"/interchain-security/v4.2.0/features/power-shaping"},next:{title:"Consumer Chain Governance",permalink:"/interchain-security/v4.2.0/consumer-development/consumer-chain-governance"}},s={},h=[{value:"Basic consumer chain",id:"basic-consumer-chain",level:2},{value:"Democracy consumer chain",id:"democracy-consumer-chain",level:2},{value:"Standalone chain to consumer chain changeover",id:"standalone-chain-to-consumer-chain-changeover",level:2}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",...(0,t.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"developing-an-ics-consumer-chain",children:"Developing an ICS consumer chain"}),"\n",(0,i.jsx)(n.p,{children:"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.\nTo help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications."}),"\n",(0,i.jsx)(n.h2,{id:"basic-consumer-chain",children:"Basic consumer chain"}),"\n",(0,i.jsxs)(n.p,{children:["The source code for the example app can be found ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer",children:"here"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"Please note that consumer chains do not implement the staking module - the validator set is replicated from the provider, meaning that the provider and the consumer use the same validator set and their stake on the provider directly determines their stake on the consumer.\nAt present there is no opt-in mechanism available, so all validators of the provider must also validate on the provider chain."}),"\n",(0,i.jsxs)(n.p,{children:["Your chain should import the consumer module from ",(0,i.jsx)(n.code,{children:"x/consumer"})," and register it in the correct places in your ",(0,i.jsx)(n.code,{children:"app.go"}),".\nThe ",(0,i.jsx)(n.code,{children:"x/consumer"})," module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in.\nYou should not need to manage or override any code from the ",(0,i.jsx)(n.code,{children:"x/consumer"})," module."]}),"\n",(0,i.jsx)(n.h2,{id:"democracy-consumer-chain",children:"Democracy consumer chain"}),"\n",(0,i.jsxs)(n.p,{children:["The source code for the example app can be found ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy",children:"here"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["This type of consumer chain wraps the basic CosmosSDK ",(0,i.jsx)(n.code,{children:"x/distribution"}),", ",(0,i.jsx)(n.code,{children:"x/staking"})," and ",(0,i.jsx)(n.code,{children:"x/governance"})," modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system."]}),"\n",(0,i.jsxs)(n.p,{children:["This allows the consumer chain to leverage those modules while also using the ",(0,i.jsx)(n.code,{children:"x/consumer"})," module."]}),"\n",(0,i.jsx)(n.p,{children:'With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.'}),"\n",(0,i.jsx)(n.h2,{id:"standalone-chain-to-consumer-chain-changeover",children:"Standalone chain to consumer chain changeover"}),"\n",(0,i.jsxs)(n.p,{children:["See the ",(0,i.jsx)(n.a,{href:"/interchain-security/v4.2.0/consumer-development/changeover-procedure",children:"standalone chain to consumer chain changeover guide"})," for more information on how to transition your standalone chain to a consumer chain."]})]})}function l(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},1151:(e,n,o)=>{o.d(n,{Z:()=>r,a:()=>c});var i=o(7294);const t={},a=i.createContext(t);function c(e){const n=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:c(e.components),i.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/aa5e9d52.e1985f6a.js b/assets/js/aa5e9d52.e1985f6a.js new file mode 100644 index 0000000000..312af43e02 --- /dev/null +++ b/assets/js/aa5e9d52.e1985f6a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4244],{9950:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>d,frontMatter:()=>a,metadata:()=>i,toc:()=>h});var s=t(5893),o=t(1151);const a={sidebar_position:11,title:"Standalone to Consumer Changeover"},r=void 0,i={id:"adrs/adr-010-standalone-changeover",title:"Standalone to Consumer Changeover",description:"ADR 010: Standalone to Consumer Changeover",source:"@site/versioned_docs/version-v5.0.0/adrs/adr-010-standalone-changeover.md",sourceDirName:"adrs",slug:"/adrs/adr-010-standalone-changeover",permalink:"/interchain-security/v5.0.0/adrs/adr-010-standalone-changeover",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:11,frontMatter:{sidebar_position:11,title:"Standalone to Consumer Changeover"},sidebar:"tutorialSidebar",previous:{title:"Soft Opt-Out",permalink:"/interchain-security/v5.0.0/adrs/adr-009-soft-opt-out"},next:{title:"Improving testing and increasing confidence",permalink:"/interchain-security/v5.0.0/adrs/adr-011-improving-test-confidence"}},c={},h=[{value:"ADR 010: Standalone to Consumer Changeover",id:"adr-010-standalone-to-consumer-changeover",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Process",id:"process",level:3},{value:"Changes to CCV Protocol",id:"changes-to-ccv-protocol",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}];function l(e){const n={a:"a",code:"code",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,o.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h2,{id:"adr-010-standalone-to-consumer-changeover",children:"ADR 010: Standalone to Consumer Changeover"}),"\n",(0,s.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"6/30/23: Feature completed, first draft of ADR."}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,s.jsx)(n.p,{children:"Implemented"}),"\n",(0,s.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.a,{href:"https://github.com/Stride-Labs/stride",children:"Stride"}),' will be the first consumer to "changeover" from a standalone cosmos blockchain, to a consumer chain secured by the Cosmos Hub. This document will outline the changes made to the replicated security protocol to support this changeover process.']}),"\n",(0,s.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,s.jsx)(n.h3,{id:"process",children:"Process"}),"\n",(0,s.jsx)(n.p,{children:'Prior to the changeover, the consumer chain will have an existing staking keeper and validator set, these may be referred to as the "standalone staking keeper" and "standalone validator set" respectively.'}),"\n",(0,s.jsx)(n.p,{children:"The first step in the changeover process is to submit a ConsumerAdditionProposal. If the proposal passes, the provider will create a new IBC client for the consumer at spawn time, with the provider's validator set. A consumer genesis will also be constructed by the provider for validators to query. Within this consumer genesis contains the initial validator set for the consumer to apply after the changeover."}),"\n",(0,s.jsx)(n.p,{children:"Next, the standalone consumer chain runs an upgrade which adds the CCV module, and is properly setup to execute changeover logic."}),"\n",(0,s.jsx)(n.p,{children:"The consumer upgrade height must be reached after the provider has created the new IBC client. Any replicated security validators who will run the consumer, but are not a part of the sovereign validator set, must sync up a full node before the consumer upgrade height is reached. The disk state of said full node will be used to run the consumer chain after the changeover has completed."}),"\n",(0,s.jsxs)(n.p,{children:["The meat of the changeover logic is that the consumer chain validator set is updated to that which was specified by the provider via the queried consumer genesis. Validators which were a part of the old set, but not the new set, are given zero voting power. Once these validator updates are given to Comet, the set is committed, and in effect 2 blocks later (see ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/x/ccv/consumer/keeper/changeover.go#L19",children:"FirstConsumerHeight"}),")."]}),"\n",(0,s.jsx)(n.p,{children:"A relayer then establishes the new IBC connection between the provider and consumer. The CCV channel handshake is started on top of this connection. Once the CCV channel is established and VSC packets are being relayed, the consumer chain is secured by the provider."}),"\n",(0,s.jsx)(n.h3,{id:"changes-to-ccv-protocol",children:"Changes to CCV Protocol"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Consumer Genesis state is updated to include a ",(0,s.jsx)(n.code,{children:"PreCCV"})," boolean. When this boolean is set true in the consumer genesis JSON, ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/x/ccv/consumer/keeper/changeover.go",children:"special logic"})," is executed on InitGenesis to trigger the changeover process on the consumer's first endblocker after the upgrade which adds the CCV module. Note that InitGenesis is not automatically called during chain upgrades, so the consumer must manually call the consumer's InitGenesis method in an upgrade handler."]}),"\n",(0,s.jsxs)(n.li,{children:["The ",(0,s.jsx)(n.code,{children:"ConsumerAdditionProposal"})," type is updated to include a ",(0,s.jsx)(n.code,{children:"DistributionTransmissionChannel"})," field. This field allows the consumer to use an existing IBC transfer channel to send rewards as a part of the CCV protocol. Consumers that're not changing over from a standalone chain will leave this field blank, indicating that a new transfer channel should be created on top of the same connection as the CCV channel."]}),"\n",(0,s.jsx)(n.li,{children:"The CCV consumer keeper is updated to contain an optional reference to the standalone staking keeper. The standalone staking keeper is used to slash for infractions that happened before the changeover was completed. Ie. any infraction from a block height before the changeover, that is submitted after the changeover, will call the standalone staking keeper's slash method. Note that a changeover consumer's standalone staking keeper becomes a democracy module keeper, so it is possible for a governance token to be slashed."}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,s.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Existing cosmos chains are now able to onboard over to a consumer chain secured by a provider."}),"\n",(0,s.jsx)(n.li,{children:"The previous staking keepers for such chains can be transitioned to democracy staking module keepers."}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["The delineation between different types of consumers in this repo becomes less clear. Ie. there is code in the ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/app/consumer-democracy/app.go",children:"democracy consumer's app.go"})," that only applies to a previously standalone chain, but that file also serves as the base for a normal democracy consumer launched with RS from genesis."]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["EPIC: Standalone to Consumer Changeover ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/756",children:"#756"})]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt",children:"Changeover diagram from Stride"})}),"\n"]})]})}function d(e={}){const{wrapper:n}={...(0,o.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>i,a:()=>r});var s=t(7294);const o={},a=s.createContext(o);function r(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:r(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/ab367a53.c91aaa68.js b/assets/js/ab367a53.c91aaa68.js new file mode 100644 index 0000000000..8b58cb5500 --- /dev/null +++ b/assets/js/ab367a53.c91aaa68.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3784],{5003:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"v4.2.0-docs","label":"v4.2.0","banner":null,"badge":true,"noIndex":false,"className":"docs-version-v4.2.0-docs","isLast":true,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Interchain Security Docs","href":"/interchain-security/v4.2.0/","docId":"index","unlisted":false},{"type":"category","label":"Introduction","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/v4.2.0/introduction/overview","docId":"introduction/overview","unlisted":false},{"type":"link","label":"Terminology","href":"/interchain-security/v4.2.0/introduction/terminology","docId":"introduction/terminology","unlisted":false},{"type":"link","label":"Interchain Security Parameters","href":"/interchain-security/v4.2.0/introduction/params","docId":"introduction/params","unlisted":false},{"type":"link","label":"Technical Specification","href":"/interchain-security/v4.2.0/introduction/technical-specification","docId":"introduction/technical-specification","unlisted":false}]},{"type":"category","label":"Features","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Key Assignment","href":"/interchain-security/v4.2.0/features/key-assignment","docId":"features/key-assignment","unlisted":false},{"type":"link","label":"Reward Distribution","href":"/interchain-security/v4.2.0/features/reward-distribution","docId":"features/reward-distribution","unlisted":false},{"type":"link","label":"ICS Provider Proposals","href":"/interchain-security/v4.2.0/features/proposals","docId":"features/proposals","unlisted":false},{"type":"link","label":"Consumer Initiated Slashing","href":"/interchain-security/v4.2.0/features/slashing","docId":"features/slashing","unlisted":false},{"type":"link","label":"Partial Set Security","href":"/interchain-security/v4.2.0/features/partial-set-security","docId":"features/partial-set-security","unlisted":false},{"type":"link","label":"Power Shaping","href":"/interchain-security/v4.2.0/features/power-shaping","docId":"features/power-shaping","unlisted":false}]},{"type":"category","label":"Consumer Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Developing an ICS consumer chain","href":"/interchain-security/v4.2.0/consumer-development/app-integration","docId":"consumer-development/app-integration","unlisted":false},{"type":"link","label":"Consumer Chain Governance","href":"/interchain-security/v4.2.0/consumer-development/consumer-chain-governance","docId":"consumer-development/consumer-chain-governance","unlisted":false},{"type":"link","label":"Onboarding Checklist","href":"/interchain-security/v4.2.0/consumer-development/onboarding","docId":"consumer-development/onboarding","unlisted":false},{"type":"link","label":"Offboarding Checklist","href":"/interchain-security/v4.2.0/consumer-development/offboarding","docId":"consumer-development/offboarding","unlisted":false},{"type":"link","label":"Changeover Procedure","href":"/interchain-security/v4.2.0/consumer-development/changeover-procedure","docId":"consumer-development/changeover-procedure","unlisted":false},{"type":"link","label":"Consumer Genesis Transformation","href":"/interchain-security/v4.2.0/consumer-development/consumer-genesis-transformation","docId":"consumer-development/consumer-genesis-transformation","unlisted":false}]},{"type":"category","label":"Validators Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/v4.2.0/validators/overview","docId":"validators/overview","unlisted":false},{"type":"link","label":"Joining Interchain Security testnet","href":"/interchain-security/v4.2.0/validators/joining-testnet","docId":"validators/joining-testnet","unlisted":false},{"type":"link","label":"Withdrawing consumer chain validator rewards","href":"/interchain-security/v4.2.0/validators/withdraw_rewards","docId":"validators/withdraw_rewards","unlisted":false},{"type":"link","label":"Validator Instructions for Changeover Procedure","href":"/interchain-security/v4.2.0/validators/changeover-procedure","docId":"validators/changeover-procedure","unlisted":false},{"type":"link","label":"Joining Neutron","href":"/interchain-security/v4.2.0/validators/joining-neutron","docId":"validators/joining-neutron","unlisted":false},{"type":"link","label":"Joining Stride","href":"/interchain-security/v4.2.0/validators/joining-stride","docId":"validators/joining-stride","unlisted":false},{"type":"link","label":"Partial Set Security","href":"/interchain-security/v4.2.0/validators/partial-set-security-for-validators","docId":"validators/partial-set-security-for-validators","unlisted":false}]},{"type":"link","label":"Frequently Asked Questions","href":"/interchain-security/v4.2.0/faq","docId":"frequently-asked-questions","unlisted":false},{"type":"category","label":"ADRs","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"ADRs","href":"/interchain-security/v4.2.0/adrs/intro","docId":"adrs/intro","unlisted":false},{"type":"link","label":"ADR Template","href":"/interchain-security/v4.2.0/adrs/adr-004-denom-dos-fixes","docId":"adrs/adr-004-denom-dos-fixes","unlisted":false},{"type":"link","label":"ADR Template","href":"/interchain-security/v4.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop","docId":"adrs/adr-007-pause-unbonding-on-eqv-prop","unlisted":false},{"type":"link","label":"ADR Template","href":"/interchain-security/v4.2.0/adrs/adr-template","docId":"adrs/adr-template","unlisted":false},{"type":"link","label":"Key Assignment","href":"/interchain-security/v4.2.0/adrs/adr-001-key-assignment","docId":"adrs/adr-001-key-assignment","unlisted":false},{"type":"link","label":"Jail Throttling","href":"/interchain-security/v4.2.0/adrs/adr-002-throttle","docId":"adrs/adr-002-throttle","unlisted":false},{"type":"link","label":"Equivocation governance proposal","href":"/interchain-security/v4.2.0/adrs/adr-003-equivocation-gov-proposal","docId":"adrs/adr-003-equivocation-gov-proposal","unlisted":false},{"type":"link","label":"Cryptographic verification of equivocation evidence","href":"/interchain-security/v4.2.0/adrs/adr-005-cryptographic-equivocation-verification","docId":"adrs/adr-005-cryptographic-equivocation-verification","unlisted":false},{"type":"link","label":"Throttle with retries","href":"/interchain-security/v4.2.0/adrs/adr-008-throttle-retries","docId":"adrs/adr-008-throttle-retries","unlisted":false},{"type":"link","label":"Soft Opt-Out","href":"/interchain-security/v4.2.0/adrs/adr-009-soft-opt-out","docId":"adrs/adr-009-soft-opt-out","unlisted":false},{"type":"link","label":"Standalone to Consumer Changeover","href":"/interchain-security/v4.2.0/adrs/adr-010-standalone-changeover","docId":"adrs/adr-010-standalone-changeover","unlisted":false},{"type":"link","label":"Improving testing and increasing confidence","href":"/interchain-security/v4.2.0/adrs/adr-011-improving-test-confidence","docId":"adrs/adr-011-improving-test-confidence","unlisted":false},{"type":"link","label":"Separate Releasing","href":"/interchain-security/v4.2.0/adrs/adr-012-separate-releasing","docId":"adrs/adr-012-separate-releasing","unlisted":false},{"type":"link","label":"Slashing on the provider for consumer equivocation","href":"/interchain-security/v4.2.0/adrs/adr-013-equivocation-slashing","docId":"adrs/adr-013-equivocation-slashing","unlisted":false},{"type":"link","label":"Epochs","href":"/interchain-security/v4.2.0/adrs/adr-014-epochs","docId":"adrs/adr-014-epochs","unlisted":false},{"type":"link","label":"Partial Set Security","href":"/interchain-security/v4.2.0/adrs/adr-015-partial-set-security","docId":"adrs/adr-015-partial-set-security","unlisted":false}]}]},"docs":{"adrs/adr-001-key-assignment":{"id":"adrs/adr-001-key-assignment","title":"Key Assignment","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-002-throttle":{"id":"adrs/adr-002-throttle","title":"Jail Throttling","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-003-equivocation-gov-proposal":{"id":"adrs/adr-003-equivocation-gov-proposal","title":"Equivocation governance proposal","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-004-denom-dos-fixes":{"id":"adrs/adr-004-denom-dos-fixes","title":"ADR Template","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-005-cryptographic-equivocation-verification":{"id":"adrs/adr-005-cryptographic-equivocation-verification","title":"Cryptographic verification of equivocation evidence","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-007-pause-unbonding-on-eqv-prop":{"id":"adrs/adr-007-pause-unbonding-on-eqv-prop","title":"ADR Template","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-008-throttle-retries":{"id":"adrs/adr-008-throttle-retries","title":"Throttle with retries","description":"ADR 008: Throttle with retries","sidebar":"tutorialSidebar"},"adrs/adr-009-soft-opt-out":{"id":"adrs/adr-009-soft-opt-out","title":"Soft Opt-Out","description":"ADR 009: Soft Opt-Out","sidebar":"tutorialSidebar"},"adrs/adr-010-standalone-changeover":{"id":"adrs/adr-010-standalone-changeover","title":"Standalone to Consumer Changeover","description":"ADR 010: Standalone to Consumer Changeover","sidebar":"tutorialSidebar"},"adrs/adr-011-improving-test-confidence":{"id":"adrs/adr-011-improving-test-confidence","title":"Improving testing and increasing confidence","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-012-separate-releasing":{"id":"adrs/adr-012-separate-releasing","title":"Separate Releasing","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-013-equivocation-slashing":{"id":"adrs/adr-013-equivocation-slashing","title":"Slashing on the provider for consumer equivocation","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-014-epochs":{"id":"adrs/adr-014-epochs","title":"Epochs","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-015-partial-set-security":{"id":"adrs/adr-015-partial-set-security","title":"Partial Set Security","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-template":{"id":"adrs/adr-template","title":"ADR Template","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/intro":{"id":"adrs/intro","title":"ADRs","description":"This is a location to record all high-level architecture decisions in the Interchain Security project.","sidebar":"tutorialSidebar"},"consumer-development/app-integration":{"id":"consumer-development/app-integration","title":"Developing an ICS consumer chain","description":"When developing an ICS consumer chain, besides just focusing on your chain\'s logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.","sidebar":"tutorialSidebar"},"consumer-development/changeover-procedure":{"id":"consumer-development/changeover-procedure","title":"Changeover Procedure","description":"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.","sidebar":"tutorialSidebar"},"consumer-development/consumer-chain-governance":{"id":"consumer-development/consumer-chain-governance","title":"Consumer Chain Governance","description":"Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the \\"Whitelist\\" section below.","sidebar":"tutorialSidebar"},"consumer-development/consumer-genesis-transformation":{"id":"consumer-development/consumer-genesis-transformation","title":"Consumer Genesis Transformation","description":"Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentation on Onboarding and Changeover).","sidebar":"tutorialSidebar"},"consumer-development/offboarding":{"id":"consumer-development/offboarding","title":"Offboarding Checklist","description":"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).","sidebar":"tutorialSidebar"},"consumer-development/onboarding":{"id":"consumer-development/onboarding","title":"Onboarding Checklist","description":"The following checklists will aid in onboarding a new consumer chain to interchain security.","sidebar":"tutorialSidebar"},"features/key-assignment":{"id":"features/key-assignment","title":"Key Assignment","description":"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.","sidebar":"tutorialSidebar"},"features/partial-set-security":{"id":"features/partial-set-security","title":"Partial Set Security","description":"Partial Set Security (PSS) allows consumer chains to leverage only a subset of validators from the provider chain, which offers more flexibility than the traditional Replicated Security model. By introducing the top_N parameter, each consumer chain can choose the extent of security needed:","sidebar":"tutorialSidebar"},"features/power-shaping":{"id":"features/power-shaping","title":"Power Shaping","description":"To give consumer chains more flexibility in choosing their validator set, Interchain Security offers","sidebar":"tutorialSidebar"},"features/proposals":{"id":"features/proposals","title":"ICS Provider Proposals","description":"Interchain security module introduces 3 new proposal types to the provider.","sidebar":"tutorialSidebar"},"features/reward-distribution":{"id":"features/reward-distribution","title":"Reward Distribution","description":"Sending and distributing rewards from consumer chains to the provider chain is handled by the Reward Distribution sub-protocol.","sidebar":"tutorialSidebar"},"features/slashing":{"id":"features/slashing","title":"Consumer Initiated Slashing","description":"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the Interchain Security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.","sidebar":"tutorialSidebar"},"frequently-asked-questions":{"id":"frequently-asked-questions","title":"Frequently Asked Questions","description":"What is a consumer chain?","sidebar":"tutorialSidebar"},"index":{"id":"index","title":"Interchain Security Docs","description":"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.","sidebar":"tutorialSidebar"},"introduction/overview":{"id":"introduction/overview","title":"Overview","description":"Interchain Security is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.","sidebar":"tutorialSidebar"},"introduction/params":{"id":"introduction/params","title":"Interchain Security Parameters","description":"The parameters necessary for Interchain Security (ICS) are defined in","sidebar":"tutorialSidebar"},"introduction/technical-specification":{"id":"introduction/technical-specification","title":"Technical Specification","description":"For a technical deep dive into the replicated security protocol, see the specification.","sidebar":"tutorialSidebar"},"introduction/terminology":{"id":"introduction/terminology","title":"Terminology","description":"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.","sidebar":"tutorialSidebar"},"validators/changeover-procedure":{"id":"validators/changeover-procedure","title":"Validator Instructions for Changeover Procedure","description":"More details available in Changeover Procedure documentation.","sidebar":"tutorialSidebar"},"validators/joining-neutron":{"id":"validators/joining-neutron","title":"Joining Neutron","description":"Neutron is the first consumer chain to implement ICS.","sidebar":"tutorialSidebar"},"validators/joining-stride":{"id":"validators/joining-stride","title":"Joining Stride","description":"Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.","sidebar":"tutorialSidebar"},"validators/joining-testnet":{"id":"validators/joining-testnet","title":"Joining Interchain Security testnet","description":"Introduction","sidebar":"tutorialSidebar"},"validators/overview":{"id":"validators/overview","title":"Overview","description":"We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.","sidebar":"tutorialSidebar"},"validators/partial-set-security-for-validators":{"id":"validators/partial-set-security-for-validators","title":"Partial Set Security","description":"Partial Set Security allows consumer chains to join as Opt-In or Top N.","sidebar":"tutorialSidebar"},"validators/withdraw_rewards":{"id":"validators/withdraw_rewards","title":"Withdrawing consumer chain validator rewards","description":"Here are example steps for withdrawing rewards from consumer chains in the provider chain","sidebar":"tutorialSidebar"}}}')}}]); \ No newline at end of file diff --git a/assets/js/ac4ec955.d4051eb8.js b/assets/js/ac4ec955.d4051eb8.js new file mode 100644 index 0000000000..f819ba1855 --- /dev/null +++ b/assets/js/ac4ec955.d4051eb8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3297],{6114:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>a,contentTitle:()=>t,default:()=>h,frontMatter:()=>r,metadata:()=>d,toc:()=>l});var s=i(5893),o=i(1151);const r={sidebar_position:2,title:"Denom DOS fixes"},t="ADR 004: Denom DOS fixes",d={id:"adrs/adr-004-denom-dos-fixes",title:"Denom DOS fixes",description:"Changelog",source:"@site/docs/adrs/adr-004-denom-dos-fixes.md",sourceDirName:"adrs",slug:"/adrs/adr-004-denom-dos-fixes",permalink:"/interchain-security/adrs/adr-004-denom-dos-fixes",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"Denom DOS fixes"},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/adrs/intro"},next:{title:"Pause validator unbonding during equivocation proposal",permalink:"/interchain-security/adrs/adr-007-pause-unbonding-on-eqv-prop"}},a={},l=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Provider",id:"provider",level:3},{value:"Consumer",id:"consumer",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3}];function c(e){const n={h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,o.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"adr-004-denom-dos-fixes",children:"ADR 004: Denom DOS fixes"}),"\n",(0,s.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"5/9/2023: ADR created"}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,s.jsx)(n.p,{children:"Accepted"}),"\n",(0,s.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,s.jsx)(n.p,{children:"The provider and consumer modules are vulnerable to similar issues involving an attacker sending millions of denoms to certain addresses and causing the chain to halt. This ADR outlines both fixes since they are similar. Both fixes involve processing only denoms that are on a whitelist to avoid iterating over millions of junk denoms but have different requirements and are implemented in different ways."}),"\n",(0,s.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,s.jsx)(n.h3,{id:"provider",children:"Provider"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Put the distribution module's FeePoolAddress back on the blocklist so that it cannot receive funds from users."}),"\n",(0,s.jsx)(n.li,{children:"Create a new address called ConsumerRewardPool and unblock it, allowing funds to be sent to it."}),"\n",(0,s.jsx)(n.li,{children:"Create a set of strings in the store for allowed ConsumerRewardDenoms."}),"\n",(0,s.jsx)(n.li,{children:"Create an endpoint called RegisterConsumerRewardDenom which deducts a fee from the sender's account, sends it to the community pool and adds a string to the ConsumerRewardDenoms set."}),"\n",(0,s.jsx)(n.li,{children:"Create a parameter called ConsumerRewardDenomRegistrationFee which determines the fee which is charged to register a consumer reward denom in the step above."}),"\n",(0,s.jsxs)(n.li,{children:["Create a function called TransferRewardsToFeeCollector which gets the entire ConsumerRewardDenoms set from the store, iterates over it, and for each entry:","\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Gets the balance of this denom for the ConsumerRewardPool account"}),"\n",(0,s.jsx)(n.li,{children:"Sends the entire balance out to the FeePoolAddress using SendCoinsFromModuleToModule which is not affected by the blocklist."}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.li,{children:"Run TransferRewardsToFeeCollector in the endblock"}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"Now, nobody can send millions of junk denoms to the FeePoolAddress because it is on the block list. If they send millions of junk denoms to the ConsumerRewardPool, this does not matter because all balances are not iterated over, only those which are in the ConsumerRewardDenoms set."}),"\n",(0,s.jsx)(n.p,{children:"We also add a new tx: register-consumer-reward-denom, and a new query: registered-consumer-reward-denoms"}),"\n",(0,s.jsx)(n.h3,{id:"consumer",children:"Consumer"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Create a new param RewardDenoms with a list of strings"}),"\n",(0,s.jsx)(n.li,{children:"Create a new param ProviderRewardDenoms with a list of strings"}),"\n",(0,s.jsx)(n.li,{children:"Create a function AllowedRewardDenoms which iterates over ProviderRewardDenoms and converts each denom to its ibc-prefixed denom using the provider chain's ibc channel information, then concatenates the RewardDenoms list and returns the combined list of allowed denoms."}),"\n",(0,s.jsx)(n.li,{children:"In SendRewardsToProvider, instead of iterating over the balances of all denoms in the ToSendToProvider address, iterate over AllowedRewardDenoms"}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"Now, if somebody sends millions of junk denoms to ToSendToProvider, they will not be iterated over. Only the RewardDenoms and ProviderRewardDenoms will be iterated over. Since we do not require this feature to be permissionless on the consumer, the registration fee process is not needed."}),"\n",(0,s.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,s.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Denom DOS is no longer possible on either provider or consumer."}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Consumer chain teams must pay a fee to register a denom for distribution on the provider, and add some extra parameters in their genesis file."}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,o.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>d,a:()=>t});var s=i(7294);const o={},r=s.createContext(o);function t(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:t(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/ae015673.fbf9e71e.js b/assets/js/ae015673.fbf9e71e.js new file mode 100644 index 0000000000..4dbeab3a6f --- /dev/null +++ b/assets/js/ae015673.fbf9e71e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2108],{2165:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>h,frontMatter:()=>s,metadata:()=>a,toc:()=>d});var i=t(5893),r=t(1151);const s={sidebar_position:6},o="Joining Stride",a={id:"validators/joining-stride",title:"Joining Stride",description:"Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.",source:"@site/versioned_docs/version-v4.2.0-docs/validators/joining-stride.md",sourceDirName:"validators",slug:"/validators/joining-stride",permalink:"/interchain-security/v4.2.0/validators/joining-stride",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"tutorialSidebar",previous:{title:"Joining Neutron",permalink:"/interchain-security/v4.2.0/validators/joining-neutron"},next:{title:"Partial Set Security",permalink:"/interchain-security/v4.2.0/validators/partial-set-security-for-validators"}},c={},d=[{value:"Note",id:"note",level:2},{value:"Resources",id:"resources",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",ul:"ul",...(0,r.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"joining-stride",children:"Joining Stride"}),"\n",(0,i.jsxs)(n.p,{children:["Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using ",(0,i.jsx)(n.code,{children:"cosmoshub-4"})," validator set."]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"stride-1"})," network (mainnet) will perform a software upgrade and at height ",(0,i.jsx)(n.code,{children:"4616678"})," that will transition the network to using the Cosmos Hub's (",(0,i.jsx)(n.code,{children:"cosmoshub-4"}),") validator set."]}),"\n",(0,i.jsxs)(n.p,{children:["You can find instructions about the Stride consumer chain launch and joining the mainnet ",(0,i.jsx)(n.a,{href:"https://github.com/Stride-Labs/mainnet/tree/main/ics-instructions",children:"here"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["This ",(0,i.jsx)(n.a,{href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt",children:"Excalidraw graphic"})," explains the timeline of Stride's changeover procedure."]}),"\n",(0,i.jsx)(n.h2,{id:"note",children:"Note"}),"\n",(0,i.jsxs)(n.p,{children:["Stride re-uses an existing ",(0,i.jsx)(n.code,{children:"transfer"})," channel to send consumer rewards to the provider chain, in order to preserve existing transfer IBC denom between ",(0,i.jsx)(n.code,{children:"stride-1"})," and ",(0,i.jsx)(n.code,{children:"cosmoshub-4"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"resources",children:"Resources"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://docs.stride.zone/docs",children:"Stride docs"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt",children:"Changeover procedure timeline"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/Stride-Labs/mainnet/tree/main/ics-instructions",children:"Changeover upgrade docs"})}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,r.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>a,a:()=>o});var i=t(7294);const r={},s=i.createContext(r);function o(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/ae63551b.40097d02.js b/assets/js/ae63551b.40097d02.js new file mode 100644 index 0000000000..2fc88b5029 --- /dev/null +++ b/assets/js/ae63551b.40097d02.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5056],{6873:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>h,frontMatter:()=>s,metadata:()=>a,toc:()=>d});var i=t(5893),r=t(1151);const s={sidebar_position:6},o="Joining Stride",a={id:"validators/joining-stride",title:"Joining Stride",description:"Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.",source:"@site/docs/validators/joining-stride.md",sourceDirName:"validators",slug:"/validators/joining-stride",permalink:"/interchain-security/validators/joining-stride",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"tutorialSidebar",previous:{title:"Joining Neutron",permalink:"/interchain-security/validators/joining-neutron"},next:{title:"Partial Set Security",permalink:"/interchain-security/validators/partial-set-security-for-validators"}},c={},d=[{value:"Note",id:"note",level:2},{value:"Resources",id:"resources",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",ul:"ul",...(0,r.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"joining-stride",children:"Joining Stride"}),"\n",(0,i.jsxs)(n.p,{children:["Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using ",(0,i.jsx)(n.code,{children:"cosmoshub-4"})," validator set."]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"stride-1"})," network (mainnet) will perform a software upgrade and at height ",(0,i.jsx)(n.code,{children:"4616678"})," that will transition the network to using the Cosmos Hub's (",(0,i.jsx)(n.code,{children:"cosmoshub-4"}),") validator set."]}),"\n",(0,i.jsxs)(n.p,{children:["You can find instructions about the Stride consumer chain launch and joining the mainnet ",(0,i.jsx)(n.a,{href:"https://github.com/Stride-Labs/mainnet/tree/main/ics-instructions",children:"here"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["This ",(0,i.jsx)(n.a,{href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt",children:"Excalidraw graphic"})," explains the timeline of Stride's changeover procedure."]}),"\n",(0,i.jsx)(n.h2,{id:"note",children:"Note"}),"\n",(0,i.jsxs)(n.p,{children:["Stride re-uses an existing ",(0,i.jsx)(n.code,{children:"transfer"})," channel to send consumer rewards to the provider chain, in order to preserve existing transfer IBC denom between ",(0,i.jsx)(n.code,{children:"stride-1"})," and ",(0,i.jsx)(n.code,{children:"cosmoshub-4"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"resources",children:"Resources"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://docs.stride.zone/docs",children:"Stride docs"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt",children:"Changeover procedure timeline"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/Stride-Labs/mainnet/tree/main/ics-instructions",children:"Changeover upgrade docs"})}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,r.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>a,a:()=>o});var i=t(7294);const r={},s=i.createContext(r);function o(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/af3e09f2.5eacecf7.js b/assets/js/af3e09f2.5eacecf7.js new file mode 100644 index 0000000000..b9e249de3a --- /dev/null +++ b/assets/js/af3e09f2.5eacecf7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4440],{8501:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>l,contentTitle:()=>t,default:()=>h,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var i=s(5893),o=s(1151);const r={sidebar_position:13,title:"Separate Releasing"},t="ADR 012: Separate Releasing",a={id:"adrs/adr-012-separate-releasing",title:"Separate Releasing",description:"Changelog",source:"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-012-separate-releasing.md",sourceDirName:"adrs",slug:"/adrs/adr-012-separate-releasing",permalink:"/interchain-security/v4.2.0/adrs/adr-012-separate-releasing",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:13,frontMatter:{sidebar_position:13,title:"Separate Releasing"},sidebar:"tutorialSidebar",previous:{title:"Improving testing and increasing confidence",permalink:"/interchain-security/v4.2.0/adrs/adr-011-improving-test-confidence"},next:{title:"Slashing on the provider for consumer equivocation",permalink:"/interchain-security/v4.2.0/adrs/adr-013-equivocation-slashing"}},l={},d=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Spike results",id:"spike-results",level:3},{value:"Why go.mod split is not the way to go",id:"why-gomod-split-is-not-the-way-to-go",level:3},{value:"Why separate repos is cool but also not the way to go",id:"why-separate-repos-is-cool-but-also-not-the-way-to-go",level:3},{value:"Decision",id:"decision",level:2},{value:"Example release flow",id:"example-release-flow",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function c(e){const n={a:"a",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",strong:"strong",ul:"ul",...(0,o.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"adr-012-separate-releasing",children:"ADR 012: Separate Releasing"}),"\n",(0,i.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[8/18/22,": Initial draft of idea in ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/801",children:"#801"})]}),"\n",(0,i.jsxs)(n.li,{children:[8/22/22,": Put idea in this ADR"]}),"\n",(0,i.jsxs)(n.li,{children:[.05,": Reject this ADR"]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(n.p,{children:"Rejected"}),"\n",(0,i.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,i.jsx)(n.h3,{id:"spike-results",children:"Spike results"}),"\n",(0,i.jsxs)(n.p,{children:["I explored the idea of ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/801",children:"#801"})," with this ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/tree/shawn%2Fgo-mod-split-aug-spike",children:"spike branch"}),". Here's my conclusions:"]}),"\n",(0,i.jsxs)(n.p,{children:["Splitting this repo to have multiple go.mods is possible. However there are various intricacies involved in decoupling the package hierarchy to have ",(0,i.jsx)(n.code,{children:"x/ccv/types"})," as the lowest level dep, with ",(0,i.jsx)(n.code,{children:"x/ccv/consumer"})," and ",(0,i.jsx)(n.code,{children:"x/ccv/provider"})," being one dep layer above, with high-level tests depending on all three of the mentioned packages. I'd estimate this decoupling would take 2-5 workdays to finish, and require significant review effort."]}),"\n",(0,i.jsx)(n.h3,{id:"why-gomod-split-is-not-the-way-to-go",children:"Why go.mod split is not the way to go"}),"\n",(0,i.jsxs)(n.p,{children:["Let's take a step back and remember the issue we're trying to solve - ",(0,i.jsx)(n.strong,{children:"We need a clean way to decouple semver/releasing for the consumer and provider modules"}),". After more consideration, splitting up go.mods gives us little benefit in achieving this. Reasons:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["The ",(0,i.jsx)(n.code,{children:"go.mod"})," dependency system is tied to git tags for the entire repo (ex: ",(0,i.jsx)(n.code,{children:"require github.com/cometbft/cometbft v0.37.2"})," refers to a historical tag for the entire cometbft repo)."]}),"\n",(0,i.jsx)(n.li,{children:"It'd be an odd dev experience to allow modules to reference past releases of other modules in the same repo. When would we ever want the consumer module to reference a past release of the types module for example?"}),"\n",(0,i.jsxs)(n.li,{children:["If we allow for ",(0,i.jsx)(n.code,{children:"go.mod"})," replace statements to build from local source code, why split up the package deps at all?"]}),"\n",(0,i.jsxs)(n.li,{children:["Splitting go.mods adds a bunch of complexity with ",(0,i.jsx)(n.code,{children:"go.work"})," files and all that shiz. VSCode does not play well with multiple module repos either."]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"why-separate-repos-is-cool-but-also-not-the-way-to-go",children:"Why separate repos is cool but also not the way to go"}),"\n",(0,i.jsxs)(n.p,{children:["All this considered, the cleanest solution to decoupling semver/releasing for the consumer and provider modules would be to have multiple repos, each with their own go.mod (3-4 repos total including high level tests). With this scheme we could separately tag each repo as changes are merged, they could share some code from ",(0,i.jsx)(n.code,{children:"types"})," being an external dep, etc."]}),"\n",(0,i.jsx)(n.p,{children:"I don't think any of us want to split up the monorepo, that's a lot of work and seems like bikeshedding. There's another solution that's very simple.."}),"\n",(0,i.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,i.jsxs)(n.p,{children:["Slightly adapting ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/cca008d856e3ffc60ec1a486871d0faa702abe26/CONTRIBUTING.md#semantic-versioning",children:"the current semver ruleset"}),":"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"A library API breaking change to EITHER the provider or consumer module will result in an increase of the MAJOR version number for BOTH modules (X.y.z-provider AND X.y.z-consumer)."}),"\n",(0,i.jsx)(n.li,{children:"A state breaking change (change requiring coordinated upgrade and/or state migration) will result in an increase of the MINOR version number for the AFFECTED module(s) (x.Y.z-provider AND/OR x.Y.z-consumer)."}),"\n",(0,i.jsx)(n.li,{children:"Any other changes (including node API breaking changes) will result in an increase of the PATCH version number for the AFFECTED module(s) (x.y.Z-provider AND/OR x.y.Z-consumer)."}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"example-release-flow",children:"Example release flow"}),"\n",(0,i.jsxs)(n.p,{children:["We upgrade ",(0,i.jsx)(n.code,{children:"main"})," to use a new version of SDK. This is a major version bump, triggering a new release for both the provider and consumer modules, ",(0,i.jsx)(n.code,{children:"v5.0.0-provider"})," and ",(0,i.jsx)(n.code,{children:"v5.0.0-consumer"}),"."]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["A state breaking change is merged to ",(0,i.jsx)(n.code,{children:"main"})," for the provider module. We release only a ",(0,i.jsx)(n.code,{children:"v5.1.0-provider"})," off main."]}),"\n",(0,i.jsxs)(n.li,{children:["Another state breaking change is merged to ",(0,i.jsx)(n.code,{children:"main"})," for the provider module. We release only a ",(0,i.jsx)(n.code,{children:"v5.2.0-provider"})," off main."]}),"\n",(0,i.jsxs)(n.li,{children:["At this point, the latest consumer version is still ",(0,i.jsx)(n.code,{children:"v5.0.0-consumer"}),". We now merge a state breaking change for the consumer module to ",(0,i.jsx)(n.code,{children:"main"}),", and consequently release ",(0,i.jsx)(n.code,{children:"v5.1.0-consumer"}),". Note that ",(0,i.jsx)(n.code,{children:"v5.1.0-consumer"})," is tagged off a LATER commit from main than ",(0,i.jsx)(n.code,{children:"v5.2.0-provider"}),". This is fine, as the consumer module should not be affected by the provider module's state breaking changes."]}),"\n",(0,i.jsxs)(n.li,{children:["Once either module sees a library API breaking change, we bump the major version for both modules. For example, we merge a library API breaking change to ",(0,i.jsx)(n.code,{children:"main"})," for the provider module. We release ",(0,i.jsx)(n.code,{children:"v6.0.0-provider"})," and ",(0,i.jsx)(n.code,{children:"v6.0.0-consumer"})," off main. Note that most often, a library API breaking change will affect both modules simultaneously (example being bumping sdk version)."]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,i.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Consumer repos have clear communication of what tagged versions are relevant to them. Consumer devs should know to never reference an ICS version that starts with ",(0,i.jsx)(n.code,{children:"provider"}),", even if it'd technically build."]}),"\n",(0,i.jsx)(n.li,{children:"Consumer and provider modules do not deviate as long as we continually release off a shared main branch. Backporting remains relatively unchanged besides being explicit about what module(s) your changes should affect."}),"\n",(0,i.jsx)(n.li,{children:"No code changes, just changes in process. Very simple."}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"~~Slightly more complexity.~~Considerably more complex to manage the ICS library.\nThis is because ICS needs to support multiple versions of SDK (e.g., 0.45, 0.47, 0.50).\nIn addition, ICS needs to support a special fork of SDK (with LSM included) for the Cosmos Hub.\nThis means that instead of focusing on main the development team needs to manage multiple release\nbranches with different dependency trees."}),"\n",(0,i.jsx)(n.li,{children:"This solution does not allow having provider and consumer on separate versions of e.g. the Cosmos SDK."}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,i.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsx)(n.p,{children:"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!"}),"\n"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/801",children:"#801"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/801#issuecomment-1683349298",children:"#801 comment"})}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,o.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},1151:(e,n,s)=>{s.d(n,{Z:()=>a,a:()=>t});var i=s(7294);const o={},r=i.createContext(o);function t(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:t(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/b22483fb.fc7b3cc6.js b/assets/js/b22483fb.fc7b3cc6.js new file mode 100644 index 0000000000..bc40bf4e8a --- /dev/null +++ b/assets/js/b22483fb.fc7b3cc6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4533],{4875:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>a,contentTitle:()=>s,default:()=>u,frontMatter:()=>o,metadata:()=>r,toc:()=>p});var n=i(5893),c=i(1151);const o={sidebar_position:4},s="Technical Specification",r={id:"introduction/technical-specification",title:"Technical Specification",description:"For a technical deep dive into the replicated security protocol, see the specification.",source:"@site/versioned_docs/version-v4.2.0-docs/introduction/technical-specification.md",sourceDirName:"introduction",slug:"/introduction/technical-specification",permalink:"/interchain-security/v4.2.0/introduction/technical-specification",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Parameters",permalink:"/interchain-security/v4.2.0/introduction/params"},next:{title:"Key Assignment",permalink:"/interchain-security/v4.2.0/features/key-assignment"}},a={},p=[];function d(e){const t={a:"a",h1:"h1",p:"p",...(0,c.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"technical-specification",children:"Technical Specification"}),"\n",(0,n.jsxs)(t.p,{children:["For a technical deep dive into the replicated security protocol, see the ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/README.md",children:"specification"}),"."]})]})}function u(e={}){const{wrapper:t}={...(0,c.a)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},1151:(e,t,i)=>{i.d(t,{Z:()=>r,a:()=>s});var n=i(7294);const c={},o=n.createContext(c);function s(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(c):e.components||c:s(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/b2a29569.d74a382c.js b/assets/js/b2a29569.d74a382c.js new file mode 100644 index 0000000000..82ac346324 --- /dev/null +++ b/assets/js/b2a29569.d74a382c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8864],{3567:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>h,contentTitle:()=>a,default:()=>l,frontMatter:()=>t,metadata:()=>r,toc:()=>d});var i=o(5893),s=o(1151);const t={sidebar_position:14,title:"Slashing on the provider for consumer equivocation"},a="ADR 013: Slashing on the provider for consumer equivocation",r={id:"adrs/adr-013-equivocation-slashing",title:"Slashing on the provider for consumer equivocation",description:"Changelog",source:"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-013-equivocation-slashing.md",sourceDirName:"adrs",slug:"/adrs/adr-013-equivocation-slashing",permalink:"/interchain-security/v4.2.0/adrs/adr-013-equivocation-slashing",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:14,frontMatter:{sidebar_position:14,title:"Slashing on the provider for consumer equivocation"},sidebar:"tutorialSidebar",previous:{title:"Separate Releasing",permalink:"/interchain-security/v4.2.0/adrs/adr-012-separate-releasing"},next:{title:"Epochs",permalink:"/interchain-security/v4.2.0/adrs/adr-014-epochs"}},h={},d=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Single-chain slashing",id:"single-chain-slashing",level:3},{value:"Slashing undelegations and redelegations",id:"slashing-undelegations-and-redelegations",level:4},{value:"Slashing delegations",id:"slashing-delegations",level:4},{value:"Old evidence",id:"old-evidence",level:4},{value:"Slashing for equivocation on the consumer",id:"slashing-for-equivocation-on-the-consumer",level:3},{value:"Proposed solution",id:"proposed-solution",level:2},{value:"Implementation",id:"implementation",level:3},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}];function c(e){const n={a:"a",blockquote:"blockquote",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"adr-013-slashing-on-the-provider-for-consumer-equivocation",children:"ADR 013: Slashing on the provider for consumer equivocation"}),"\n",(0,i.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"1st Sept. 2023: Initial draft"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(n.p,{children:"Accepted"}),"\n",(0,i.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,i.jsxs)(n.p,{children:["This ADR presents some approaches on how to slash on the provider chain validators that performed equivocations on consumer chains.\nCurrently, the provider chain can ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/1232",children:"receive and verify evidence of equivocation"}),", but it cannot slash the misbehaving validator."]}),"\n",(0,i.jsx)(n.p,{children:"In the remainder of this section, we explain how slashing is performed on a single chain and show why slashing on the provider for equivocation on the consumer is challenging."}),"\n",(0,i.jsxs)(n.p,{children:["Note that future versions of the Cosmos SDK, CometBFT, and ibc-go could modify the way we slash, etc. Therefore, a future reader of this ADR, should note that when we refer to Cosmos SDK, CometBFT, and ibc-go we specifically refer to their ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/v0.47/intro/overview",children:"v0.47"}),", ",(0,i.jsx)(n.a,{href:"https://docs.cometbft.com/v0.37/",children:"v0.37"})," and ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/ibc-go/blob/v7.3.0",children:"v7.3.0"})," versions respectively."]}),"\n",(0,i.jsx)(n.h3,{id:"single-chain-slashing",children:"Single-chain slashing"}),"\n",(0,i.jsxs)(n.p,{children:["Slashing is implemented across the ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/v0.47/modules/slashing",children:"slashing"}),"\nand ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/v0.47/modules/staking",children:"staking"})," modules.\nThe slashing module's keeper calls the staking module's ",(0,i.jsx)(n.code,{children:"Slash()"})," method, passing among others, the ",(0,i.jsx)(n.code,{children:"infractionHeight"})," (i.e., the height when the equivocation occurred), the validator's ",(0,i.jsx)(n.code,{children:"power"})," at the infraction height, and the ",(0,i.jsx)(n.code,{children:"slashFactor"})," (currently set to ",(0,i.jsx)(n.code,{children:"5%"})," in case of equivocation on the Cosmos Hub)."]}),"\n",(0,i.jsx)(n.h4,{id:"slashing-undelegations-and-redelegations",children:"Slashing undelegations and redelegations"}),"\n",(0,i.jsxs)(n.p,{children:["To slash undelegations, ",(0,i.jsx)(n.code,{children:"Slash"})," goes through all undelegations and checks whether they started before or after the infraction occurred. If an undelegation started before the ",(0,i.jsx)(n.code,{children:"infractionHeight"}),", then it is ",(0,i.jsx)(n.strong,{children:"not"})," slashed, otherwise it is slashed by ",(0,i.jsx)(n.code,{children:"slashFactor"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["The slashing of redelegations happens in a similar way, meaning that ",(0,i.jsx)(n.code,{children:"Slash"})," goes through all redelegations and checks whether the redelegations started before or after the ",(0,i.jsx)(n.code,{children:"infractionHeight"}),"."]}),"\n",(0,i.jsx)(n.h4,{id:"slashing-delegations",children:"Slashing delegations"}),"\n",(0,i.jsxs)(n.p,{children:["Besides undelegations and redelegations, the validator's delegations need to also be slashed.\nThis is performed by deducting the appropriate amount of tokens from the validator. Note that this deduction is computed based on the voting ",(0,i.jsx)(n.code,{children:"power"})," the misbehaving validator had at the height of the equivocation. As a result of the tokens deduction,\nthe ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/v0.47/modules/staking#delegator-shares",children:"tokens per share"}),"\nreduce and hence later on, when delegators undelegate or redelegate, the delegators retrieve back less\ntokens, effectively having their tokens slashed. The rationale behind this slashing mechanism, as mentioned in the ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/v0.47/modules/staking#delegator-shares",children:"Cosmos SDK documentation"})]}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsx)(n.p,{children:"[...] is to simplify the accounting around slashing. Rather than iteratively slashing the tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, effectively reducing the value of each issued delegator share."}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["This approach of slashing delegations does not utilize the\n",(0,i.jsx)(n.code,{children:"infractionHeight"})," in any way and hence the following scenario could occur:"]}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["a validator ",(0,i.jsx)(n.code,{children:"V"})," performs an equivocation at a height ",(0,i.jsx)(n.code,{children:"Hi"})]}),"\n",(0,i.jsxs)(n.li,{children:["a new delegator ",(0,i.jsx)(n.code,{children:"D"})," delegates to ",(0,i.jsx)(n.code,{children:"V"})," after height ",(0,i.jsx)(n.code,{children:"Hi"})]}),"\n",(0,i.jsxs)(n.li,{children:["evidence of the equivocation by validator ",(0,i.jsx)(n.code,{children:"V"})," is received"]}),"\n",(0,i.jsxs)(n.li,{children:["the tokens of delegator ",(0,i.jsx)(n.code,{children:"D"})," are slashed"]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["In the above scenario, delegator ",(0,i.jsx)(n.code,{children:"D"})," is slashed, even though ",(0,i.jsx)(n.code,{children:"D"}),"'s voting power did not contribute to the infraction."]}),"\n",(0,i.jsx)(n.h4,{id:"old-evidence",children:"Old evidence"}),"\n",(0,i.jsxs)(n.p,{children:["In the single-chain case, old evidence (e.g., from 3 years ago) is ignored. This is achieved through\n",(0,i.jsx)(n.a,{href:"https://docs.cometbft.com/v0.37/spec/consensus/evidence",children:"CometBFT"})," that ignores old evidence based on the parameters ",(0,i.jsx)(n.code,{children:"MaxAgeNumBlocks"})," and ",(0,i.jsx)(n.code,{children:"MaxAgeDuration"})," (see ",(0,i.jsx)(n.a,{href:"https://github.com/cometbft/cometbft/blob/v0.37.0/evidence/pool.go#271",children:"here"}),").\nAdditionally, note that when the evidence is sent by CometBFT to the application, the evidence is rechecked in the ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L54",children:"evidence module"})," of Cosmos SDK and if it is old, the evidence is ignored.\nIn Cosmos Hub, the ",(0,i.jsx)(n.code,{children:"MaxAgeNumBlocks"})," is set to 1000000 (i.e., ~70 days if we assume we need ~6 sec per block) and ",(0,i.jsx)(n.code,{children:"MaxAgeDuration"})," is set to 172800000000000 ns (i.e., 2 days). Because of this check, we can easily exclude old evidence."]}),"\n",(0,i.jsx)(n.h3,{id:"slashing-for-equivocation-on-the-consumer",children:"Slashing for equivocation on the consumer"}),"\n",(0,i.jsxs)(n.p,{children:["In the single-chain case, slashing requires both the ",(0,i.jsx)(n.code,{children:"infractionHeight"})," and the voting ",(0,i.jsx)(n.code,{children:"power"}),".\nIn order to slash on the provider for an equivocation on a consumer, we need to have both the provider's ",(0,i.jsx)(n.code,{children:"infractionHeight"})," and voting ",(0,i.jsx)(n.code,{children:"power"}),".\nNote that the ",(0,i.jsx)(n.code,{children:"infractionHeight"})," on the consumer chain must be mapped to a height on the provider chain.\nUnless we have a way to find the corresponding ",(0,i.jsx)(n.code,{children:"infractionHeight"})," and ",(0,i.jsx)(n.code,{children:"power"})," on the provider chain, we cannot slash for equivocation on the consumer in the same way as we would slash in the single-chain case."]}),"\n",(0,i.jsxs)(n.p,{children:["The challenge of figuring out the corresponding ",(0,i.jsx)(n.code,{children:"infractionHeight"})," and ",(0,i.jsx)(n.code,{children:"power"})," values on the provider chain is due to the following trust assumption:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["We trust the consensus layer and validator set of the consumer chains, ",(0,i.jsx)(n.em,{children:"but we do not trust the application layer"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["As a result, we cannot trust anything that stems from the ",(0,i.jsx)(n.em,{children:"application state"})," of a consumer chain."]}),"\n",(0,i.jsxs)(n.p,{children:["Note that when a relayer or a user sends evidence through a ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/1232",children:"MsgSubmitConsumerDoubleVoting"})," message, the provider gets access to ",(0,i.jsx)(n.a,{href:"https://github.com/cometbft/cometbft/blob/v0.37.0/types/evidence.go#L35",children:"DuplicateVoteEvidence"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-protobuf",children:'type DuplicateVoteEvidence struct {\n\tVoteA *Vote `json:"vote_a"`\n\tVoteB *Vote `json:"vote_b"`\n\n\t// abci specific information\n\tTotalVotingPower int64\n\tValidatorPower int64\n\tTimestamp time.Time\n}\n'})}),"\n",(0,i.jsxs)(n.p,{children:['The "abci specific information" fields cannot be trusted because they are not signed. Therefore,\nwe can use neither ',(0,i.jsx)(n.code,{children:"ValidatorPower"})," for slashing on the provider chain, nor the ",(0,i.jsx)(n.code,{children:"Timestamp"})," to check the evidence age. We can get the ",(0,i.jsx)(n.code,{children:"infractionHeight"})," from the votes, but this ",(0,i.jsx)(n.code,{children:"infractionHeight"})," corresponds to the infraction height on the consumer and ",(0,i.jsx)(n.strong,{children:"not"})," on the provider chain.\nSimilarly, when a relayer or a user sends evidence through a ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/826",children:"MsgSubmitConsumerMisbehaviour"})," message, the provider gets access to ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/ibc-go/blob/v7.3.0/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79",children:"Misbehaviour"})," that we cannot use to extract the infraction height, power, or the time on the provider chain."]}),"\n",(0,i.jsx)(n.h2,{id:"proposed-solution",children:"Proposed solution"}),"\n",(0,i.jsx)(n.p,{children:"As a first iteration, we propose the following approach. At the moment the provider receives evidence of equivocation on a consumer:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["slash all the undelegations and redelegations using ",(0,i.jsx)(n.code,{children:"slashFactor"}),";"]}),"\n",(0,i.jsxs)(n.li,{children:["slash all delegations using as voting ",(0,i.jsx)(n.code,{children:"power"})," the sum of the voting power of the misbehaving validator and the power of all the ongoing undelegations and redelegations."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Evidence expiration:"})," Additionally, because we cannot infer the actual time of the evidence (i.e., the timestamp of the evidence cannot be trusted), we do not consider ",(0,i.jsx)(n.em,{children:"evidence expiration"})," and hence old evidence is never ignored (e.g., the provider would act on 3 year-old evidence of equivocation on a consumer).\nAdditionally, we do not need to store equivocation evidence to avoid slashing a validator more than once, because we ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L94",children:"do not slash"})," tombstoned validators and we ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L138",children:"tombstone"})," a validator when slashed."]}),"\n",(0,i.jsxs)(n.p,{children:["We do not act on evidence that was signed by a validator ",(0,i.jsx)(n.a,{href:"https://tutorials.cosmos.network/tutorials/9-path-to-prod/3-keys.html#what-validator-keys",children:"consensus key"})," that is ",(0,i.jsx)(n.em,{children:"pruned"})," when we receive the evidence. We prune a validator's consensus key if the validator has assigned a new consumer key (using ",(0,i.jsx)(n.code,{children:"MsgAssignConsumerKey"}),") and an unbonding period on the consumer chain has elapsed (see ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-001-key-assignment.md",children:"key assignment ADR"}),"). Note that the provider chain is informed that the unbonding period has elapsed on the consumer when the provider receives a ",(0,i.jsx)(n.code,{children:"VSCMaturedPacket"})," and because of this, if the consumer delays the sending of a ",(0,i.jsx)(n.code,{children:"VSCMaturedPacket"}),", we would delay the pruning of the key as well."]}),"\n",(0,i.jsx)(n.h3,{id:"implementation",children:"Implementation"}),"\n",(0,i.jsxs)(n.p,{children:["The following logic needs to be added to the ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/1232",children:"HandleConsumerDoubleVoting"})," and ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/826",children:"HandleConsumerMisbehaviour"})," methods:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-go",children:"undelegationsInTokens := sdk.NewInt(0)\nfor _, v := range k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validatorAddress) {\n for _, entry := range v.Entries {\n if entry.IsMature(now) && !entry.OnHold() {\n // undelegation no longer eligible for slashing, skip it\n continue\n }\n undelegationsInTokens = undelegationsInTokens.Add(entry.InitialBalance)\n }\n}\n\nredelegationsInTokens := sdk.NewInt(0)\nfor _, v := range k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validatorAddress) {\n for _, entry := range v.Entries {\n if entry.IsMature(now) && !entry.OnHold() {\n // redelegation no longer eligible for slashing, skip it\n continue\n }\n redelegationsInTokens = redelegationsInTokens.Add(entry.InitialBalance)\n }\n}\n\ninfractionHeight := 0\nundelegationsAndRedelegationsInPower = sdk.TokensToConsensusPower(undelegationsInTokens.Add(redelegationsInTokens))\ntotalPower := validator's voting power + undelegationsAndRedelegationsInPower\nslashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)\n\nk.stakingKeeper.Slash(ctx, validatorConsAddress, infractionHeight, totalPower, slashFraction, DoubleSign)\n"})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Infraction height:"})," We provide a zero ",(0,i.jsx)(n.code,{children:"infractionHeight"})," to the ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L33",children:"Slash"})," method in order to slash all ongoing undelegations and redelegations (see checks in ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L92",children:"Slash"}),", ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L195",children:"SlashUnbondingDelegation"}),", and ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L249",children:"SlashRedelegation"}),")."]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Power:"})," We pass the sum of the voting power of the misbehaving validator when the evidence was received (i.e., at evidence height) and the power of all the ongoing undelegations and redelegations.\nIf we assume that the ",(0,i.jsx)(n.code,{children:"slashFactor"})," is ",(0,i.jsx)(n.code,{children:"5%"}),", then the voting power we pass is ",(0,i.jsx)(n.code,{children:"power + totalPower(undelegations) + totalPower(redelegations)"}),".\nHence, when the ",(0,i.jsx)(n.code,{children:"Slash"})," method slashes all the undelegations and redelegations it would end up with ",(0,i.jsx)(n.code,{children:"0.05 * power + 0.05 * totalPower(undelegations) + 0.05 * totalPower(redelegations) - 0.05 * totalPower(undelegations) - 0.05 * totalPower(redelegations) = 0.05 * power"})," and hence it would slash ",(0,i.jsx)(n.code,{children:"5%"})," of the validator's power when the evidence is received."]}),"\n",(0,i.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsx)(n.p,{children:"With the proposed approach we can quickly implement slashing functionality on the provider chain for consumer chain equivocations.\nThis approach does not need to change the staking module and therefore does not change in any way how slashing is performed today for a single chain."}),"\n",(0,i.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["We ",(0,i.jsx)(n.em,{children:"definitely"})," slash more when it comes to undelegations and redelegations because we slash for all of them without considering an ",(0,i.jsx)(n.code,{children:"infractionHeight"}),"."]}),"\n",(0,i.jsxs)(n.li,{children:["We ",(0,i.jsx)(n.em,{children:"potentially"})," slash more than what we would have slashed if we knew the voting ",(0,i.jsx)(n.code,{children:"power"})," at the corresponding ",(0,i.jsx)(n.code,{children:"infractionHeight"})," in the provider chain."]}),"\n",(0,i.jsx)(n.li,{children:"We slash on old evidence of equivocation on a consumer."}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md",children:"ADR 005: Cryptographic verification of equivocation evidence"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/732",children:"EPIC tracking cryptographic equivocation feature"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://forum.cosmos.network/t/cryptographic-equivocation-slashing-design/11400",children:"Cosmos Hub Forum discussion on cryptographic equivocation slashing"})}),"\n"]})]})}function l(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},1151:(e,n,o)=>{o.d(n,{Z:()=>r,a:()=>a});var i=o(7294);const s={},t=i.createContext(s);function a(e){const n=i.useContext(t);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),i.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/b8d345cd.3f23582b.js b/assets/js/b8d345cd.3f23582b.js new file mode 100644 index 0000000000..4c688a65f5 --- /dev/null +++ b/assets/js/b8d345cd.3f23582b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4341],{186:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>o,default:()=>h,frontMatter:()=>r,metadata:()=>d,toc:()=>c});var i=t(5893),s=t(1151);const r={sidebar_position:12,title:"Improving testing and increasing confidence"},o="ADR 011: Improving testing and increasing confidence",d={id:"adrs/adr-011-improving-test-confidence",title:"Improving testing and increasing confidence",description:"Changelog",source:"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-011-improving-test-confidence.md",sourceDirName:"adrs",slug:"/adrs/adr-011-improving-test-confidence",permalink:"/interchain-security/v4.2.0/adrs/adr-011-improving-test-confidence",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:12,frontMatter:{sidebar_position:12,title:"Improving testing and increasing confidence"},sidebar:"tutorialSidebar",previous:{title:"Standalone to Consumer Changeover",permalink:"/interchain-security/v4.2.0/adrs/adr-010-standalone-changeover"},next:{title:"Separate Releasing",permalink:"/interchain-security/v4.2.0/adrs/adr-012-separate-releasing"}},a={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Current state of testing",id:"current-state-of-testing",level:4},{value:"Unit testing",id:"unit-testing",level:3},{value:"Integration testing",id:"integration-testing",level:3},{value:"End-to-end testing",id:"end-to-end-testing",level:3},{value:"Decision",id:"decision",level:2},{value:"1. Connect specifications to code and tooling",id:"1-connect-specifications-to-code-and-tooling",level:3},{value:"Decision context and hypothesis",id:"decision-context-and-hypothesis",level:4},{value:"Main benefit",id:"main-benefit",level:4},{value:"2. Improve e2e tooling",id:"2-improve-e2e-tooling",level:3},{value:"Matrix tests",id:"matrix-tests",level:4},{value:"Introducing e2e regression testing",id:"introducing-e2e-regression-testing",level:4},{value:"Introducing e2e CometMock tests",id:"introducing-e2e-cometmock-tests",level:4},{value:"3. Introduce innovative testing approaches",id:"3-introduce-innovative-testing-approaches",level:3},{value:"Model",id:"model",level:4},{value:"Driver",id:"driver",level:4},{value:"Harness",id:"harness",level:4},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function l(e){const n={a:"a",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",img:"img",li:"li",ol:"ol",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"adr-011-improving-testing-and-increasing-confidence",children:"ADR 011: Improving testing and increasing confidence"}),"\n",(0,i.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"2023-08-11: Proposed, first draft of ADR."}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(n.p,{children:"Proposed"}),"\n",(0,i.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,i.jsx)(n.p,{children:"Testing, QA, and maintenance of interchain-security libraries is an ever-evolving area of software engineering we have to keep incrementally improving. The purpose of the QA process is to catch bugs as early as possible. In an ideal development workflow a bug should never reach production. A bug found in the specification stage is a lot cheaper to resolve than a bug discovered in production (or even in testnet). Ideally, all bugs should be found during the CI execution, and we hope that no bugs will ever even reach the testnet (although nothing can replace actual system stress test under load interacting with users)."}),"\n",(0,i.jsx)(n.p,{children:"During development and testnet operation the following types of bugs were the most commonly found:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"improper iterator usage"}),"\n",(0,i.jsx)(n.li,{children:"unbounded array access/iteration"}),"\n",(0,i.jsx)(n.li,{children:"improper input handling and validation"}),"\n",(0,i.jsx)(n.li,{children:"improper cached context usage"}),"\n",(0,i.jsx)(n.li,{children:"non-determinism check (improper use of maps in go, relying on random values)"}),"\n",(0,i.jsx)(n.li,{children:"KV store management and/or how keys are defined"}),"\n",(0,i.jsx)(n.li,{children:"deserialization issues arising from consumer/provider versioning mismatch"}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Such bugs can be discovered earlier with better tooling. Some of these bugs can induce increases in block times, chain halts, state corruption, or introduce an attack surface which is difficult to remove if other systems have started depending on that behavior."}),"\n",(0,i.jsx)(n.h4,{id:"current-state-of-testing",children:"Current state of testing"}),"\n",(0,i.jsx)(n.p,{children:"Our testing suites consist of multiple parts, each with their own trade-offs and benefits with regards to code coverage, complexity and confidence they provide."}),"\n",(0,i.jsx)(n.h3,{id:"unit-testing",children:"Unit testing"}),"\n",(0,i.jsxs)(n.p,{children:["Unit testing is employed mostly for testing single-module functionality. It is the first step in testing and often the most practical. While highly important, unit tests often ",(0,i.jsx)(n.strong,{children:"test a single piece of code"})," and don't test relationships between different moving parts, this makes them less valuable when dealing with multi-module interactions."]}),"\n",(0,i.jsx)(n.p,{children:"Unit tests often employ mocks to abstract parts of the system that are not under test. Mocks are not equivalent to actual models and should not be treated as such."}),"\n",(0,i.jsx)(n.p,{children:"Out of all the approaches used, unit testing has the most tools available and the coverage can simply be displayed as % of code lines tested. Although this is a very nice and very easy to understand metric, it does not speak about the quality of the test coverage."}),"\n",(0,i.jsx)(n.p,{children:"Since distributed systems testing is a lot more involved, unit tests are oftentimes not sufficient to cover complex interactions. Unit tests are still necessary and helpful, but in cases where unit tests are not helpful e2e or integration tests should be favored."}),"\n",(0,i.jsx)(n.h3,{id:"integration-testing",children:"Integration testing"}),"\n",(0,i.jsxs)(n.p,{children:["With integration testing we ",(0,i.jsx)(n.strong,{children:"test the multi-module interactions"})," while isolating them from the remainder of the system.\nIntegration tests can uncover bugs that are often missed by unit tests."]}),"\n",(0,i.jsxs)(n.p,{children:["It is very difficult to gauge the actual test coverage imparted by integration tests and the available tooling is limited.\nIn interchain-security we employ the ",(0,i.jsx)(n.code,{children:"ibc-go/testing"})," framework to test interactions in-memory."]}),"\n",(0,i.jsx)(n.p,{children:"At present, integration testing does not involve the consensus layer - it is only concerned with application level state and logic."}),"\n",(0,i.jsx)(n.h3,{id:"end-to-end-testing",children:"End-to-end testing"}),"\n",(0,i.jsx)(n.p,{children:"In our context end-to-end testing comprises of tests that use the actual application binaries in an isolated environment (e.g. docker container). During test execution the inputs are meant to simulate actual user interaction, either by submitting transactions/queries using the command line or using gRPC/REST APIs and checking for state changes after an action has been performed. With this testing strategy we also include the consensus layer in all of our runs. This is the closest we can get to testing user interactions without starting a full testnet."}),"\n",(0,i.jsx)(n.p,{children:"End-to-end testing strategies vary between different teams and projects and we strive to unify our approach to the best of our ability (at least for ICS and gaia)."}),"\n",(0,i.jsx)(n.p,{children:"The available tooling does not give us significant (or relevant) line of code coverage information since most of the tools are geared towards analyzing unit tests and simple code branch evaluation."}),"\n",(0,i.jsx)(n.p,{children:"We aim to adapt our best practices by learning from other similar systems and projects such as cosmos-sdk, ibc-go and CometBFT."}),"\n",(0,i.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,i.jsx)(n.h3,{id:"1-connect-specifications-to-code-and-tooling",children:"1. Connect specifications to code and tooling"}),"\n",(0,i.jsx)(n.p,{children:"Oftentimes, specifications are disconnected from the development and QA processes. This gives rise to problems where the specification does not reflect the actual state of the system and vice-versa.\nUsually specifications are just text files that are rarely used and go unmaintained after a while, resulting in consistency issues and misleading instructions/expectations about system behavior."}),"\n",(0,i.jsx)(n.h4,{id:"decision-context-and-hypothesis",children:"Decision context and hypothesis"}),"\n",(0,i.jsx)(n.p,{children:"Specifications written in a dedicated and executable specification language are easier to maintain than the ones written entirely in text.\nAdditionally, we can create models based on the specification OR make the model equivalent to a specification."}),"\n",(0,i.jsxs)(n.p,{children:["Models do not care about the intricacies of implementation and neither do specifications. Since both models and specifications care about concisely and accurately describing a system (such as a finite state machine), we see a benefit of adding model based tools (such as ",(0,i.jsx)(n.a,{href:"https://github.com/informalsystems/quint",children:"quint"}),") to our testing and development workflows."]}),"\n",(0,i.jsx)(n.h4,{id:"main-benefit",children:"Main benefit"}),"\n",(0,i.jsx)(n.p,{children:"MBT tooling can be used to generate test traces that can be executed by multiple different testing setups."}),"\n",(0,i.jsx)(n.h3,{id:"2-improve-e2e-tooling",children:"2. Improve e2e tooling"}),"\n",(0,i.jsx)(n.h4,{id:"matrix-tests",children:"Matrix tests"}),"\n",(0,i.jsxs)(n.p,{children:["Instead of only running tests against current ",(0,i.jsx)(n.code,{children:"main"})," branch we should adopt an approach where we also:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"run regression tests against different released software versions"})," (",(0,i.jsx)(n.code,{children:"ICS v1 vs v2 vs v3"}),")"]}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.strong,{children:"run non-determinism tests to uncover issues quickly"})}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["Matrix tests can be implemented using ",(0,i.jsx)(n.a,{href:"https://github.com/informalsystems/CometMock",children:"CometMock"})," and refactoring our current e2e CI setup."]}),"\n",(0,i.jsx)(n.h4,{id:"introducing-e2e-regression-testing",children:"Introducing e2e regression testing"}),"\n",(0,i.jsx)(n.p,{children:"This e2e test suite would execute using a cronjob in our CI (nightly, multiple times a day etc.)"}),"\n",(0,i.jsxs)(n.p,{children:["Briefly, the same set of traces is run against different ",(0,i.jsx)(n.strong,{children:"maintained"})," versions of the software and the ",(0,i.jsx)(n.code,{children:"main"})," branch.\nThis would allow us to discover potential issues during development instead of in a testnet scenarios."]}),"\n",(0,i.jsxs)(n.p,{children:["The most valuable issues that can be discovered in this way are ",(0,i.jsx)(n.strong,{children:"state breaking changes"}),", ",(0,i.jsx)(n.strong,{children:"regressions"})," and ",(0,i.jsx)(n.strong,{children:"version incompatibilities"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["The setup is illustrated by the image below.\n",(0,i.jsx)(n.img,{alt:"e2e matrix tests",src:t(4023).Z+"",width:"2170",height:"1624"})]}),"\n",(0,i.jsx)(n.p,{children:"This table explains which versions are tested against each other for the same set of test traces:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"\u2705 marks a passing test"}),"\n",(0,i.jsx)(n.li,{children:"\u274c marks a failing test"}),"\n"]}),"\n",(0,i.jsxs)(n.table,{children:[(0,i.jsx)(n.thead,{children:(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"USES: ICS v1 PROVIDER"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"start chain"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"add key"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"delegate"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"undelegate"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"redelegate"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"downtime"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"equivocation"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"stop chain"})})]})}),(0,i.jsxs)(n.tbody,{children:[(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"v1 consumer (sdk45,ibc4.3)"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"v2 consumer (sdk45, ibc4.4)"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"v3 consumer (sdk47, ibc7)"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"main consumer"})}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"neutron"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u274c"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"stride"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u274c"})]})]})]}),"\n",(0,i.jsx)(n.h4,{id:"introducing-e2e-cometmock-tests",children:"Introducing e2e CometMock tests"}),"\n",(0,i.jsxs)(n.p,{children:["CometMock is a mock implementation of the ",(0,i.jsx)(n.a,{href:"https://github.com/cometbft/cometbft",children:"CometBFT"})," consensus engine. It supports most operations performed by CometBFT while also being lightweight and relatively easy to use."]}),"\n",(0,i.jsxs)(n.p,{children:['CometMock tests allow more nuanced control of test scenarios because CometMock can "fool" the blockchain app into thinking that a certain number of blocks had passed.\n',(0,i.jsx)(n.strong,{children:"This allows us to test very nuanced scenarios, difficult edge cases and long-running operations (such as unbonding operations)."})]}),"\n",(0,i.jsx)(n.p,{children:"Examples of tests made easier with CometMock are listed below:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"regression tests"}),"\n",(0,i.jsx)(n.li,{children:"non-determinism tests"}),"\n",(0,i.jsx)(n.li,{children:"upgrade tests"}),"\n",(0,i.jsx)(n.li,{children:"state-breaking changes"}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["With CometMock, the ",(0,i.jsx)(n.strong,{children:"matrix test"})," approach can also be used. The image below illustrates a CometMock setup that can be used to discover non-deterministic behavior and state-breaking changes.\n",(0,i.jsx)(n.img,{alt:"e2e matrix tests",src:t(3146).Z+"",width:"3714",height:"2082"})]}),"\n",(0,i.jsx)(n.p,{children:"This table explains which versions are tested against each other for the same set of test traces:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"\u2705 marks a passing test"}),"\n",(0,i.jsx)(n.li,{children:"\u274c marks a failing test"}),"\n"]}),"\n",(0,i.jsxs)(n.table,{children:[(0,i.jsx)(n.thead,{children:(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"SCENARIO"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"start chain"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"add key"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"delegate"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"undelegate"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"redelegate"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"downtime"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"equivocation"})}),(0,i.jsx)(n.th,{children:(0,i.jsx)(n.strong,{children:"stop chain"})})]})}),(0,i.jsxs)(n.tbody,{children:[(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"v3 provi + v3 consu"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"main provi + main consu"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"commit provi + commit consu"})}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u2705"}),(0,i.jsx)(n.td,{children:"\u274c"}),(0,i.jsx)(n.td,{children:"\u274c"})]})]})]}),"\n",(0,i.jsxs)(n.p,{children:["Briefly; multiple versions of the application are run against the same CometMock instance and any deviations in app behavior would result in ",(0,i.jsx)(n.code,{children:"app hash"})," errors (the apps would be in different states after performing the same set of actions)."]}),"\n",(0,i.jsx)(n.h3,{id:"3-introduce-innovative-testing-approaches",children:"3. Introduce innovative testing approaches"}),"\n",(0,i.jsx)(n.p,{children:"When discussing e2e testing, some very important patterns emerge - especially if test traces are used instead of ad-hoc tests written by hand."}),"\n",(0,i.jsx)(n.p,{children:"We see a unique opportunity to clearly identify concerns and modularize the testing architecture."}),"\n",(0,i.jsxs)(n.p,{children:["The e2e testing frameworks can be split into a ",(0,i.jsx)(n.strong,{children:"pipeline consisting of 3 parts: model, driver and harness"}),"."]}),"\n",(0,i.jsx)(n.h4,{id:"model",children:"Model"}),"\n",(0,i.jsx)(n.p,{children:"Model is the part of the system that can emulate the behavior of the system under test.\nIdeally, it is very close to the specification and is written in a specification language such as quint, TLA+ or similar.\nOne of the purposes of the model is that it can be used to generate test traces."}),"\n",(0,i.jsx)(n.h4,{id:"driver",children:"Driver"}),"\n",(0,i.jsx)(n.p,{children:"The purpose of the driver is to accept test traces (generated by the model or written by hand), process them and provide inputs to the next part of the pipeline."}),"\n",(0,i.jsx)(n.p,{children:"Basically, the driver sits between the model and the actual infrastructure on which the test traces are being executed on."}),"\n",(0,i.jsx)(n.h4,{id:"harness",children:"Harness"}),"\n",(0,i.jsx)(n.p,{children:"Harness is the infrastructure layer of the pipeline that accepts inputs from the driver."}),"\n",(0,i.jsx)(n.p,{children:"There can be multiple harnesses as long as they can perform four things:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"bootstrap a test execution environment (local, docker, k8s\u2026)"}),"\n",(0,i.jsx)(n.li,{children:"accept inputs from drivers"}),"\n",(0,i.jsx)(n.li,{children:"perform the action specified by the driver"}),"\n",(0,i.jsx)(n.li,{children:"report results after performing actions"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,i.jsx)(n.p,{children:"The procedure outlined in this ADR is not an all-or-nothing approach. Concepts introduced here do not rely on each other, so this ADR may only be applied partially without negative impact on test coverage and code confidence."}),"\n",(0,i.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsx)(n.li,{children:"introduction of maintainable MBT solutions"}),"\n"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:'improvement over the current "difftest" setup that relies on an opinionated typescript model and go driver'}),"\n"]}),"\n",(0,i.jsxs)(n.ol,{start:"2",children:["\n",(0,i.jsx)(n.li,{children:"increased code coverage and confidence"}),"\n"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"using CometMock allows us to run more tests in less time"}),"\n",(0,i.jsx)(n.li,{children:"adding matrix e2e tests allows us to quickly pinpoint differences between code versions"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsx)(n.p,{children:"It might be easier to forgo the MBT tooling and instead focus on pure property based testing"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/667",children:"PBT proof of concept"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/flyingmutant/rapid",children:"property based testing in go"})}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:'The solutions are potentially expensive if we increase usage of the CI pipeline - this is fixed by running "expensive" tests using a cronjob, instead of running them on every commit.'}),"\n",(0,i.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,i.jsx)(n.p,{children:"The process of changing development and testing process is not something that can be thought of and delivered quickly. Luckily, the changes can be rolled out incrementally without impacting existing workflows."}),"\n",(0,i.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsx)(n.p,{children:"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!"}),"\n"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/gaia/issues/2427",children:"https://github.com/cosmos/gaia/issues/2427"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/gaia/issues/2420",children:"https://github.com/cosmos/gaia/issues/2420"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/ibc-go/tree/main/e2e",children:"ibc-go e2e tests"})}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},3146:(e,n,t)=>{t.d(n,{Z:()=>i});const i=t.p+"assets/images/cometmock_matrix_test-714f36252aff9df4214823e3145d0ef5.png"},4023:(e,n,t)=>{t.d(n,{Z:()=>i});const i=t.p+"assets/images/matrix_e2e_tests-30681305077301daaf3097e1952b54bb.png"},1151:(e,n,t)=>{t.d(n,{Z:()=>d,a:()=>o});var i=t(7294);const s={},r=i.createContext(s);function o(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/b8e16dc5.a2560616.js b/assets/js/b8e16dc5.a2560616.js new file mode 100644 index 0000000000..bbefab6d34 --- /dev/null +++ b/assets/js/b8e16dc5.a2560616.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6705],{1528:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>d,frontMatter:()=>a,metadata:()=>i,toc:()=>h});var s=t(5893),o=t(1151);const a={sidebar_position:11,title:"Standalone to Consumer Changeover"},r=void 0,i={id:"adrs/adr-010-standalone-changeover",title:"Standalone to Consumer Changeover",description:"ADR 010: Standalone to Consumer Changeover",source:"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-010-standalone-changeover.md",sourceDirName:"adrs",slug:"/adrs/adr-010-standalone-changeover",permalink:"/interchain-security/v4.2.0/adrs/adr-010-standalone-changeover",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:11,frontMatter:{sidebar_position:11,title:"Standalone to Consumer Changeover"},sidebar:"tutorialSidebar",previous:{title:"Soft Opt-Out",permalink:"/interchain-security/v4.2.0/adrs/adr-009-soft-opt-out"},next:{title:"Improving testing and increasing confidence",permalink:"/interchain-security/v4.2.0/adrs/adr-011-improving-test-confidence"}},c={},h=[{value:"ADR 010: Standalone to Consumer Changeover",id:"adr-010-standalone-to-consumer-changeover",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Process",id:"process",level:3},{value:"Changes to CCV Protocol",id:"changes-to-ccv-protocol",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}];function l(e){const n={a:"a",code:"code",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,o.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h2,{id:"adr-010-standalone-to-consumer-changeover",children:"ADR 010: Standalone to Consumer Changeover"}),"\n",(0,s.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"6/30/23: Feature completed, first draft of ADR."}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,s.jsx)(n.p,{children:"Implemented"}),"\n",(0,s.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.a,{href:"https://github.com/Stride-Labs/stride",children:"Stride"}),' will be the first consumer to "changeover" from a standalone cosmos blockchain, to a consumer chain secured by the Cosmos Hub. This document will outline the changes made to the replicated security protocol to support this changeover process.']}),"\n",(0,s.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,s.jsx)(n.h3,{id:"process",children:"Process"}),"\n",(0,s.jsx)(n.p,{children:'Prior to the changeover, the consumer chain will have an existing staking keeper and validator set, these may be referred to as the "standalone staking keeper" and "standalone validator set" respectively.'}),"\n",(0,s.jsx)(n.p,{children:"The first step in the changeover process is to submit a ConsumerAdditionProposal. If the proposal passes, the provider will create a new IBC client for the consumer at spawn time, with the provider's validator set. A consumer genesis will also be constructed by the provider for validators to query. Within this consumer genesis contains the initial validator set for the consumer to apply after the changeover."}),"\n",(0,s.jsx)(n.p,{children:"Next, the standalone consumer chain runs an upgrade which adds the CCV module, and is properly setup to execute changeover logic."}),"\n",(0,s.jsx)(n.p,{children:"The consumer upgrade height must be reached after the provider has created the new IBC client. Any replicated security validators who will run the consumer, but are not a part of the sovereign validator set, must sync up a full node before the consumer upgrade height is reached. The disk state of said full node will be used to run the consumer chain after the changeover has completed."}),"\n",(0,s.jsxs)(n.p,{children:["The meat of the changeover logic is that the consumer chain validator set is updated to that which was specified by the provider via the queried consumer genesis. Validators which were a part of the old set, but not the new set, are given zero voting power. Once these validator updates are given to Comet, the set is committed, and in effect 2 blocks later (see ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/x/ccv/consumer/keeper/changeover.go#L19",children:"FirstConsumerHeight"}),")."]}),"\n",(0,s.jsx)(n.p,{children:"A relayer then establishes the new IBC connection between the provider and consumer. The CCV channel handshake is started on top of this connection. Once the CCV channel is established and VSC packets are being relayed, the consumer chain is secured by the provider."}),"\n",(0,s.jsx)(n.h3,{id:"changes-to-ccv-protocol",children:"Changes to CCV Protocol"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Consumer Genesis state is updated to include a ",(0,s.jsx)(n.code,{children:"PreCCV"})," boolean. When this boolean is set true in the consumer genesis JSON, ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/x/ccv/consumer/keeper/changeover.go",children:"special logic"})," is executed on InitGenesis to trigger the changeover process on the consumer's first endblocker after the upgrade which adds the CCV module. Note that InitGenesis is not automatically called during chain upgrades, so the consumer must manually call the consumer's InitGenesis method in an upgrade handler."]}),"\n",(0,s.jsxs)(n.li,{children:["The ",(0,s.jsx)(n.code,{children:"ConsumerAdditionProposal"})," type is updated to include a ",(0,s.jsx)(n.code,{children:"DistributionTransmissionChannel"})," field. This field allows the consumer to use an existing IBC transfer channel to send rewards as a part of the CCV protocol. Consumers that're not changing over from a standalone chain will leave this field blank, indicating that a new transfer channel should be created on top of the same connection as the CCV channel."]}),"\n",(0,s.jsx)(n.li,{children:"The CCV consumer keeper is updated to contain an optional reference to the standalone staking keeper. The standalone staking keeper is used to slash for infractions that happened before the changeover was completed. Ie. any infraction from a block height before the changeover, that is submitted after the changeover, will call the standalone staking keeper's slash method. Note that a changeover consumer's standalone staking keeper becomes a democracy module keeper, so it is possible for a governance token to be slashed."}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,s.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Existing cosmos chains are now able to onboard over to a consumer chain secured by a provider."}),"\n",(0,s.jsx)(n.li,{children:"The previous staking keepers for such chains can be transitioned to democracy staking module keepers."}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["The delineation between different types of consumers in this repo becomes less clear. Ie. there is code in the ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/app/consumer-democracy/app.go",children:"democracy consumer's app.go"})," that only applies to a previously standalone chain, but that file also serves as the base for a normal democracy consumer launched with RS from genesis."]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["EPIC: Standalone to Consumer Changeover ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/756",children:"#756"})]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt",children:"Changeover diagram from Stride"})}),"\n"]})]})}function d(e={}){const{wrapper:n}={...(0,o.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>i,a:()=>r});var s=t(7294);const o={},a=s.createContext(o);function r(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:r(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/b93225b7.6c538bb2.js b/assets/js/b93225b7.6c538bb2.js new file mode 100644 index 0000000000..e646d8e18e --- /dev/null +++ b/assets/js/b93225b7.6c538bb2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7144],{8304:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>d,contentTitle:()=>a,default:()=>l,frontMatter:()=>s,metadata:()=>r,toc:()=>c});var n=o(5893),i=o(1151);const s={sidebar_position:16,title:"Partial Set Security"},a="ADR 015: Partial Set Security",r={id:"adrs/adr-015-partial-set-security",title:"Partial Set Security",description:"Changelog",source:"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-015-partial-set-security.md",sourceDirName:"adrs",slug:"/adrs/adr-015-partial-set-security",permalink:"/interchain-security/v4.2.0/adrs/adr-015-partial-set-security",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:16,frontMatter:{sidebar_position:16,title:"Partial Set Security"},sidebar:"tutorialSidebar",previous:{title:"Epochs",permalink:"/interchain-security/v4.2.0/adrs/adr-014-epochs"}},d={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"How do consumer chains join?",id:"how-do-consumer-chains-join",level:3},{value:"State & Query",id:"state--query",level:4},{value:"How do validators opt in?",id:"how-do-validators-opt-in",level:3},{value:"State & Query",id:"state--query-1",level:4},{value:"When do validators opt in?",id:"when-do-validators-opt-in",level:4},{value:"How do validators opt out?",id:"how-do-validators-opt-out",level:3},{value:"State & Query",id:"state--query-2",level:4},{value:"When does a consumer chain start?",id:"when-does-a-consumer-chain-start",level:3},{value:"How do we send the partial validator sets to the consumer chains?",id:"how-do-we-send-the-partial-validator-sets-to-the-consumer-chains",level:3},{value:"How do we distribute rewards?",id:"how-do-we-distribute-rewards",level:3},{value:"Misbehaviour",id:"misbehaviour",level:3},{value:"Fraud votes",id:"fraud-votes",level:4},{value:"Double signing",id:"double-signing",level:4},{value:"Downtime",id:"downtime",level:4},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}];function h(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",pre:"pre",ul:"ul",...(0,i.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"adr-015-partial-set-security",children:"ADR 015: Partial Set Security"}),"\n",(0,n.jsx)(t.h2,{id:"changelog",children:"Changelog"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"2024-01-22: Proposed, first draft of ADR."}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"status",children:"Status"}),"\n",(0,n.jsx)(t.p,{children:"Proposed"}),"\n",(0,n.jsx)(t.h2,{id:"context",children:"Context"}),"\n",(0,n.jsxs)(t.p,{children:["Currently, in ",(0,n.jsx)(t.em,{children:"Replicated Security"}),", the entire validator set of the provider chain is used to secure consumer chains. There are at least three concerns with this approach.\nFirst, a large number of validators might be forced to validate consumer chains they are not interested in securing.\nSecond, it is costly for small validators to secure additional chains. This concern is only partially addressed through ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-009-soft-opt-out.md",children:"soft opt-out"})," that allows small validators to opt out from validating consumer chains.\nThird and for the above reasons, it is challenging for a new consumer chain to join Replicated Security."]}),"\n",(0,n.jsxs)(t.p,{children:["As a solution, we present ",(0,n.jsx)(t.em,{children:"Partial Set Security"})," (PSS). As the name suggests, PSS allows for every consumer chain to be secured by only a subset of the provider validator set.\nIn what follows we propose the exact steps we need to take to implement PSS. This is a first iteration of PSS, and therefore we present the most minimal solution that make PSS possible."]}),"\n",(0,n.jsx)(t.h2,{id:"decision",children:"Decision"}),"\n",(0,n.jsxs)(t.p,{children:["In Replicated Security, all the provider validators have to secure every consumer chain (with the exception of those validators allowed to opt out through the ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-009-soft-opt-out.md",children:"soft opt-out"})," feature)."]}),"\n",(0,n.jsxs)(t.p,{children:["In PSS, we allow validators to opt in and out of validating any given consumer chain.\nThis has one exception: we introduce a parameter ",(0,n.jsx)(t.code,{children:"N"})," for each consumer chain and require that the validators in top ",(0,n.jsx)(t.code,{children:"N%"})," of the provider's voting power have to secure the consumer chain.\nValidators outside of the top ",(0,n.jsx)(t.code,{children:"N%"})," can dynamically opt in if they want to validate on the consumer chain."]}),"\n",(0,n.jsxs)(t.p,{children:["For example, if a consumer chain has ",(0,n.jsx)(t.code,{children:"N = 95%"}),", then it ultimately receives the same security it receives today with Replicated Security (with a default ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-009-soft-opt-out.md",children:"SoftOptOutThreshold"})," of 5%).\nOn the other hand, if a consumer chain has ",(0,n.jsx)(t.code,{children:"N = 0%"}),", then no validator is forced to validate the chain, but validators can opt in to do so instead."]}),"\n",(0,n.jsxs)(t.p,{children:["For the remainder of this ADR, we call a consumer chain ",(0,n.jsx)(t.em,{children:"Top N"})," if it has joined as a Top N chain with ",(0,n.jsx)(t.code,{children:"N > 0"})," and ",(0,n.jsx)(t.em,{children:"Opt In"})," chain otherwise. An Opt In consumer chain is secured only by the validators that have opted in to secure that chain."]}),"\n",(0,n.jsxs)(t.p,{children:["We intend to implement PSS using a feature branch off ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/tree/v4.0.0",children:"v4.0.0 interchain security"}),"."]}),"\n",(0,n.jsx)(t.h3,{id:"how-do-consumer-chains-join",children:"How do consumer chains join?"}),"\n",(0,n.jsxs)(t.p,{children:["As a simplification and to avoid ",(0,n.jsx)(t.a,{href:"https://forum.cosmos.network/t/pss-permissionless-vs-premissioned-lite-opt-in-consumer-chains/12984/17",children:"chain id squatting"}),", a consumer chain can only join PSS through a governance proposal and not in a permissionless way."]}),"\n",(0,n.jsx)(t.p,{children:'However, this proposal type will be modified so that it requires a lower quorum percentage than normal proposal, and every validator who voted "YES" on the proposal will form the consumer chain\'s initial validator set.'}),"\n",(0,n.jsxs)(t.p,{children:["Consumer chains join PSS the same way chains now join Replicated Security, namely through a ",(0,n.jsx)(t.code,{children:"ConsumerAdditionProposal"})," proposal.\nWe extend ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/proto/interchain_security/ccv/provider/v1/provider.proto#L27",children:(0,n.jsx)(t.code,{children:"ConsumerAdditionProposal"})})," with one optional field:"]}),"\n",(0,n.jsxs)(t.p,{children:[(0,n.jsx)(t.code,{children:"uint32 top_N"}),": Corresponds to the percentage of validators that join under the Top N case.\nFor example, ",(0,n.jsx)(t.code,{children:"53"})," corresponds to a Top 53% chain, meaning that the top ",(0,n.jsx)(t.code,{children:"53%"})," provider validators have to validate the proposed consumer chain.\n",(0,n.jsx)(t.code,{children:"top_N"})," can be ",(0,n.jsx)(t.code,{children:"0"})," or include any value in ",(0,n.jsx)(t.code,{children:"[50, 100]"}),". A chain can join with ",(0,n.jsx)(t.code,{children:"top_N == 0"})," as an Opt In, or with ",(0,n.jsx)(t.code,{children:"top_N \u2208 [50, 100]"})," as a Top N chain."]}),"\n",(0,n.jsxs)(t.p,{children:["In case of a Top N chain, we restrict the possible values of ",(0,n.jsx)(t.code,{children:"top_N"})," from ",(0,n.jsx)(t.code,{children:"(0, 100]"})," to ",(0,n.jsx)(t.code,{children:"[50, 100]"}),".\nBy having ",(0,n.jsx)(t.code,{children:"top_N >= 50"})," we can guarantee that we cannot have a successful attack, assuming that at most ",(0,n.jsx)(t.code,{children:"1/3"})," of provider validators can be malicious.\nThis is because, a Top N chain with ",(0,n.jsx)(t.code,{children:"N >= 50%"})," would have at least ",(0,n.jsx)(t.code,{children:"1/3"})," honest validators, which is sufficient to stop attacks.\nAdditionally, by having ",(0,n.jsx)(t.code,{children:"N >= 50%"})," (and hence ",(0,n.jsx)(t.code,{children:"N > (VetoThreshold = 33.4%)"}),") we enable the top N validators to ",(0,n.jsx)(t.code,{children:"Veto"})," any ",(0,n.jsx)(t.code,{children:"ConsumerAdditionProposal"})," for consumer chains they do not want to validate."]}),"\n",(0,n.jsxs)(t.p,{children:["If a proposal has the ",(0,n.jsx)(t.code,{children:"top_N"})," argument wrongly set, it should get rejected in [ValidateBasic] (",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/types/proposal.go#L86",children:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/types/proposal.go#L86"}),")."]}),"\n",(0,n.jsxs)(t.p,{children:["In the code, we distinguish whether a chain is ",(0,n.jsx)(t.em,{children:"Top N"})," or ",(0,n.jsx)(t.em,{children:"Opt In"})," by checking whether ",(0,n.jsx)(t.code,{children:"top_N"})," is zero or not."]}),"\n",(0,n.jsxs)(t.p,{children:["In a future version of PSS, we intend to introduce a ",(0,n.jsx)(t.code,{children:"ConsumerModificationProposal"})," so that we can modify the parameters of a consumer chain, e.g, a chain that is ",(0,n.jsx)(t.em,{children:"Opt In"})," to become ",(0,n.jsx)(t.em,{children:"Top N"}),", etc."]}),"\n",(0,n.jsx)(t.h4,{id:"state--query",children:"State & Query"}),"\n",(0,n.jsxs)(t.p,{children:["We augment the provider module\u2019s state to keep track of the ",(0,n.jsx)(t.code,{children:"top_N"})," value for each consumer chain. The key to store this information would be:"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{children:"topNBytePrefix | len(chainID) | chainID\n"})}),"\n",(0,n.jsxs)(t.p,{children:["To create the above key, we can use ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/types/keys.go#L418",children:(0,n.jsx)(t.code,{children:"ChainIdWithLenKey"})}),"."]}),"\n",(0,n.jsxs)(t.p,{children:["Then in the ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/keeper/keeper.go",children:"keeper"})," we introduce methods as follows:"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-golang",children:"func (k Keeper) SetTopN(ctx sdk.Context, chainID string, topN uint32)\nfunc (k Keeper) IsTopN(ctx sdk.Context, chainID string) bool\nfunc (k Keeper) IsOptIn(ctx sdk.Context, chainID string) bool\n\n// returns the N if Top N chain, otherwise an error\nfunc (k Keeper) GetTopN(ctx sdk.Context, chainID string) (uint32, error)\n"})}),"\n",(0,n.jsxs)(t.p,{children:["We also extend the ",(0,n.jsx)(t.code,{children:"interchain-security-pd query provider list-consumer-chains"}),' query to return information on whether a consumer chain is an Opt In or a Top N chain and with what N.\nThis way, block explorers can present informative messages such as "This chain is secured by N% of the provider chain" for consumer chains.']}),"\n",(0,n.jsx)(t.h3,{id:"how-do-validators-opt-in",children:"How do validators opt in?"}),"\n",(0,n.jsxs)(t.p,{children:["A validator can opt in by sending a new type of message that we introduce in ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/proto/interchain_security/ccv/provider/v1/tx.proto#L1",children:"tx.proto"}),"."]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-protobuf",children:"message MsgOptIn {\n // the chain id of the consumer chain to opt in to\n string chainID = 1;\n // the provider address of the validator\n string providerAddr = 2;\n // (optional) the consensus public key to use on the consumer\n optional string consumerKey = 3;\n}\n"})}),"\n",(0,n.jsxs)(t.p,{children:["Note that in a Top N consumer chain, the top ",(0,n.jsx)(t.code,{children:"N%"})," provider validators have to validate the consumer chain.\nNevertheless, validators in the bottom ",(0,n.jsx)(t.code,{children:"(100 - N)%"})," can opt in to validate as well.\nProvider validators that belong or enter the top ",(0,n.jsx)(t.code,{children:"N%"})," validators are ",(0,n.jsx)(t.em,{children:"automatically"})," opted in to validate a Top N consumer chain.\nThis means that if a validator ",(0,n.jsx)(t.code,{children:"V"})," belongs to the top ",(0,n.jsx)(t.code,{children:"N%"})," validators but later falls (e.g., due to undelegations) to the bottom ",(0,n.jsx)(t.code,{children:"(100 - N)%"}),", ",(0,n.jsx)(t.code,{children:"V"})," is still considered opted in and has to validate unless ",(0,n.jsx)(t.code,{children:"V"})," sends a ",(0,n.jsx)(t.code,{children:"MsgOptOut"})," message (see below).\nBy automatically opting in validators when they enter the top ",(0,n.jsx)(t.code,{children:"N%"})," validators and by forcing top ",(0,n.jsx)(t.code,{children:"N%"})," validators to explicitly opt out in case they fall to the ",(0,n.jsx)(t.code,{children:"(100 - N)%"})," bottom validators we simplify the design of PSS."]}),"\n",(0,n.jsxs)(t.p,{children:["Note that a validator can send a ",(0,n.jsx)(t.code,{children:"MsgOptIn"})," message even if the consumer chain is not yet running. To do this we reuse the ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/keeper/key_assignment.go#L644",children:(0,n.jsx)(t.code,{children:"IsConsumerProposedOrRegistered"})}),". If the ",(0,n.jsx)(t.code,{children:"chainID"})," does not exist, the ",(0,n.jsx)(t.code,{children:"MsgOptIn"})," should fail, as well as if the provider address does not exist."]}),"\n",(0,n.jsxs)(t.p,{children:["Optionally, a validator that opts in can provide a ",(0,n.jsx)(t.code,{children:"consumerKey"})," so that it assigns a different consumer key (from the provider) to the consumer chain.\nNaturally, a validator can always change the consumer key on a consumer chain by sending a ",(0,n.jsx)(t.code,{children:"MsgAssignConsumerKey"})," message at a later point in time, as is done in Replicated Security."]}),"\n",(0,n.jsx)(t.h4,{id:"state--query-1",children:"State & Query"}),"\n",(0,n.jsxs)(t.p,{children:["For each validator, we store a pair ",(0,n.jsx)(t.code,{children:"(blockHeight, isOptedIn)"})," that contains the block height the validator opted in and whether the validator is currently opted in or not, under the key:"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{children:"optedInBytePrefix | len(chainID) | chainID | addr\n"})}),"\n",(0,n.jsxs)(t.p,{children:["By using a prefix iterator on ",(0,n.jsx)(t.code,{children:"optedInBytePrefix | len(chainID) | chainID"})," we retrieve all the opted in validators."]}),"\n",(0,n.jsxs)(t.p,{children:["We introduce the following ",(0,n.jsx)(t.code,{children:"Keeper"})," methods."]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-golang",children:"// returns all the validators that have opted in on chain `chainID`\nfunc (k Keeper) GetOptedInValidators(ctx sdk.Context, chainID string) []Validators\n\nfunc (k Keeper) IsValidatorOptedIn(ctx sdk.Context, chainID string, val Validator) bool\n"})}),"\n",(0,n.jsx)(t.p,{children:"We introduce the following two queries:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-bash",children:"interchain-security-pd query provider optedInValidators $chainID\ninterchain-security-pd query provider hasToValidate $providerAddr\n"})}),"\n",(0,n.jsx)(t.p,{children:"One query to retrieve the validators that are opted in and hence the validators that need to validate the consumer chain and one query that given a validator's address returns all the chains this validator has to validate."}),"\n",(0,n.jsx)(t.h4,{id:"when-do-validators-opt-in",children:"When do validators opt in?"}),"\n",(0,n.jsxs)(t.p,{children:["As described earlier, validators can manually opt in by sending a ",(0,n.jsx)(t.code,{children:"MsgOptIn"})," message.\nAdditionally, in a Top N chain, a validator is automatically opted in when it moves from the bottom ",(0,n.jsx)(t.code,{children:"(100 - N)%"})," to the top ",(0,n.jsx)(t.code,{children:"N%"})," validators."]}),"\n",(0,n.jsxs)(t.p,{children:["Lastly, validators can also opt in if they vote ",(0,n.jsx)(t.code,{children:"Yes"})," during the ",(0,n.jsx)(t.code,{children:"ConsumerAdditionProposal"})," that introduces a consumer chain.\nThis simplifies validators operations because they do not have to send an additional message to opt in."]}),"\n",(0,n.jsxs)(t.p,{children:["Because the ",(0,n.jsx)(t.code,{children:"Tally"})," method ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.7/x/gov/keeper/tally.go#L71",children:"deletes the votes"})," after reading them, we cannot check the votes of the validators after the votes have been tallied.\nTo circumvent this, we introduce a hook for ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.7/x/gov/keeper/vote.go#L35",children:(0,n.jsx)(t.code,{children:"AfterProposalVote"})})," and keep track of all the votes cast by a validator.\nIf a validator casts more than one vote, we only consider the latest vote.\nFinally, we only consider a validator has opted in if it casts a 100% ",(0,n.jsx)(t.code,{children:"Yes"})," vote in case of a ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-037-gov-split-vote.md",children:"weighted vote"}),"."]}),"\n",(0,n.jsx)(t.h3,{id:"how-do-validators-opt-out",children:"How do validators opt out?"}),"\n",(0,n.jsx)(t.p,{children:"Validators that have opted in on a chain can opt out by sending the following message:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-protobuf",children:"message MsgOptOut {\n // the chain id of the consumer chain to opt out from\n string chainID = 1;\n // the provider address of the validator\n string providerAddr = 2;\n}\n"})}),"\n",(0,n.jsxs)(t.p,{children:["Validators can only opt out after a consumer chain has started and hence the above message returns an error if the chain with ",(0,n.jsx)(t.code,{children:"chainID"})," is not running.\nAdditionally, a validator that belongs to the top ",(0,n.jsx)(t.code,{children:"N%"})," validators cannot opt out from a Top N chain and hence a ",(0,n.jsx)(t.code,{children:"MsgOptOut"})," would error in such a case."]}),"\n",(0,n.jsx)(t.h4,{id:"state--query-2",children:"State & Query"}),"\n",(0,n.jsx)(t.p,{children:"We also update the state of the opted-in validators when a validator has opted out by removing the opted-out validator."}),"\n",(0,n.jsxs)(t.p,{children:["Note that only opted-in validators can be punished for downtime on a consumer chain.\nFor this, we use historical info of all the validators that have opted in; We can examine the ",(0,n.jsx)(t.code,{children:"blockHeight"})," stored under the key ",(0,n.jsx)(t.code,{children:"optedInBytePrefix | len(chainID) | chainID | addr"})," to see if a validator was opted in.\nThis way we can jail validators for downtime knowing that indeed the validators have opted in at some point in the past.\nOtherwise, we can think of a scenario where a validator ",(0,n.jsx)(t.code,{children:"V"})," is down for a period of time, but before ",(0,n.jsx)(t.code,{children:"V"})," gets punished for downtime, validator ",(0,n.jsx)(t.code,{children:"V"})," opts out, and then we do not know whether ",(0,n.jsx)(t.code,{children:"V"})," should be punished or not."]}),"\n",(0,n.jsx)(t.h3,{id:"when-does-a-consumer-chain-start",children:"When does a consumer chain start?"}),"\n",(0,n.jsxs)(t.p,{children:["A Top N consumer chain always starts at the specified date (",(0,n.jsx)(t.code,{children:"spawn_time"}),") if the ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/proto/interchain_security/ccv/provider/v1/provider.proto#L27",children:(0,n.jsx)(t.code,{children:"ConsumerAdditionProposal"})})," has passed.\nAn Opt In consumer chain only starts if at least one validator has opted in. We check this in ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/keeper/proposal.go#L357",children:"BeginBlockInit"}),":"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-golang",children:'func (k Keeper) BeginBlockInit(ctx sdk.Context) {\n propsToExecute := k.GetConsumerAdditionPropsToExecute(ctx)\n\n for _, prop := range propsToExecute {\n chainID := prop.ChainId\n if !k.IsTopN(ctx, chainID) && len(k.GetOptedInValidators(ctx, chainID)) == 0 {\n // drop the proposal\n ctx.Logger().Info("could not start chain because no validator has opted in")\n continue\n } \n ...\n'})}),"\n",(0,n.jsx)(t.h3,{id:"how-do-we-send-the-partial-validator-sets-to-the-consumer-chains",children:"How do we send the partial validator sets to the consumer chains?"}),"\n",(0,n.jsxs)(t.p,{children:["A consumer chain should only be validated by opted in validators.\nWe introduce logic to do this when we ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/keeper/relay.go#L213",children:"queue"})," the ",(0,n.jsx)(t.code,{children:"VSCPacket"}),"s.\nThe logic behind this, is not as straightforward as it seems because CometBFT does not receive the validator set that has to validate a chain, but rather a delta of ",(0,n.jsx)(t.a,{href:"https://docs.cometbft.com/v0.37/spec/abci/abci++_methods#validatorupdate",children:"validator updates"}),".\nFor example, to remove an opted-out validator from a consumer chain, we have to send a validator update with a ",(0,n.jsx)(t.code,{children:"power"})," of ",(0,n.jsx)(t.code,{children:"0"}),", similarly to what is done in the ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/keeper/key_assignment.go#L525",children:"assignment of consumer keys"}),".\nWe intend to update this ADR at a later stage on how exactly we intend to implement this logic."]}),"\n",(0,n.jsx)(t.h3,{id:"how-do-we-distribute-rewards",children:"How do we distribute rewards?"}),"\n",(0,n.jsxs)(t.p,{children:["Currently, rewards are distributed as follows: The consumer ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/consumer/keeper/distribution.go#L148",children:"periodically sends rewards"})," on the provider ",(0,n.jsx)(t.code,{children:"ConsumerRewardsPool"})," address.\nThe provider then ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/keeper/distribution.go#L77",children:"transfers those rewards to the fee collector address"})," and those transferred rewards are distributed to validators and delegators."]}),"\n",(0,n.jsx)(t.p,{children:"In PSS, we distribute rewards only to validators that actually validate the consumer chain.\nTo do this, we have a pool associated with each consumer chain and consumers IBC transfer the rewards to this pool.\nWe then extract the rewards from each consumer pool and distribute them to the opted in validators."}),"\n",(0,n.jsx)(t.p,{children:"Note that we only distribute rewards to validators that have been opted in for some time (e.g., 10000 blocks) to avoid cases where validators opt in just to receive rewards and then opt out immediately afterward."}),"\n",(0,n.jsx)(t.h3,{id:"misbehaviour",children:"Misbehaviour"}),"\n",(0,n.jsx)(t.h4,{id:"fraud-votes",children:"Fraud votes"}),"\n",(0,n.jsxs)(t.p,{children:["In an Opt In chain, a set of validators might attempt to perform an attack. To deter such potential attacks, PSS allows for the use of fraud votes.\nA ",(0,n.jsx)(t.em,{children:"fraud vote"})," is a governance proposal that enables the slashing of validators that performed an attack.\nDue to their inherent complexity, we intend to introduce fraud votes in a different ADR and at a future iteration of PSS."]}),"\n",(0,n.jsx)(t.h4,{id:"double-signing",children:"Double signing"}),"\n",(0,n.jsx)(t.p,{children:"We do not change the way slashing for double signing and light client attacks functions.\nIf a validator misbehaves on a consumer, then we slash that validator on the provider."}),"\n",(0,n.jsx)(t.h4,{id:"downtime",children:"Downtime"}),"\n",(0,n.jsx)(t.p,{children:"We do not change the way downtime jailing functions.\nIf a validator is down on a consumer chain for an adequate amount of time, we jail this validator on the provider but only if the validator was opted in on this consumer chain in the recent past."}),"\n",(0,n.jsx)(t.h2,{id:"consequences",children:"Consequences"}),"\n",(0,n.jsx)(t.h3,{id:"positive",children:"Positive"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsx)(t.p,{children:"Easier for new consumer chains to consume the provider's chain economic security because proposals are more likely to pass if not everyone is forced to validate."}),"\n"]}),"\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsx)(t.p,{children:"Smaller validators are not forced to validate chains anymore if they do not want to."}),"\n"]}),"\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsx)(t.p,{children:"We can deprecate the soft opt-out implementation."}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(t.h3,{id:"negative",children:"Negative"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["A consumer chain does not receive the same economic security as with Replicated Security (assuming the value of ",(0,n.jsx)(t.code,{children:"SoftOptOutThreshold"})," is ",(0,n.jsx)(t.code,{children:"5%"}),"), unless it is a Top N chain with ",(0,n.jsx)(t.code,{children:"N >= 95%"}),"."]}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"references",children:"References"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:(0,n.jsx)(t.a,{href:"https://forum.cosmos.network/t/pss-permissionless-vs-premissioned-lite-opt-in-consumer-chains/12984",children:"PSS: Permissionless vs premissioned-lite opt-in consumer chains"})}),"\n",(0,n.jsx)(t.li,{children:(0,n.jsx)(t.a,{href:"https://forum.cosmos.network/t/chips-discussion-phase-partial-set-security-updated/11775",children:"CHIPs discussion phase: Partial Set Security (updated)"})}),"\n",(0,n.jsx)(t.li,{children:(0,n.jsx)(t.a,{href:"https://forum.cosmos.network/t/pss-exclusive-vs-inclusive-top-n/13058",children:"PSS: Exclusive vs Inclusive Top-N"})}),"\n",(0,n.jsx)(t.li,{children:(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/pull/1518",children:"Initial PSS ADR and notes #1518"})}),"\n",(0,n.jsx)(t.li,{children:(0,n.jsx)(t.a,{href:"https://informal.systems/blog/replicated-vs-mesh-security",children:"Replicated vs. Mesh Security"})}),"\n"]})]})}function l(e={}){const{wrapper:t}={...(0,i.a)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(h,{...e})}):h(e)}},1151:(e,t,o)=>{o.d(t,{Z:()=>r,a:()=>a});var n=o(7294);const i={},s=n.createContext(i);function a(e){const t=n.useContext(s);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),n.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/bbea31d2.43863e88.js b/assets/js/bbea31d2.43863e88.js new file mode 100644 index 0000000000..640b9d87de --- /dev/null +++ b/assets/js/bbea31d2.43863e88.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[109],{662:(s,e,a)=>{a.r(e),a.d(e,{assets:()=>h,contentTitle:()=>l,default:()=>d,frontMatter:()=>t,metadata:()=>r,toc:()=>c});var i=a(5893),n=a(1151);const t={sidebar_position:3,title:"Jail Throttling"},l="ADR 002: Jail Throttling",r={id:"adrs/adr-002-throttle",title:"Jail Throttling",description:"Changelog",source:"@site/docs/adrs/adr-002-throttle.md",sourceDirName:"adrs",slug:"/adrs/adr-002-throttle",permalink:"/interchain-security/adrs/adr-002-throttle",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Jail Throttling"},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/adrs/adr-001-key-assignment"},next:{title:"Equivocation governance proposal",permalink:"/interchain-security/adrs/adr-003-equivocation-gov-proposal"}},h={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Required State",id:"required-state",level:3},{value:"Params",id:"params",level:3},{value:"Protocol Overview",id:"protocol-overview",level:3},{value:"OnRecvSlashPacket",id:"onrecvslashpacket",level:4},{value:"OnRecvVSCMaturedPacket",id:"onrecvvscmaturedpacket",level:4},{value:"Endblocker",id:"endblocker",level:4},{value:"Slash Meter Replenishment",id:"slash-meter-replenishment",level:5},{value:"Handle Leading VSCMaturedPackets",id:"handle-leading-vscmaturedpackets",level:5},{value:"Handle Throttle Queues",id:"handle-throttle-queues",level:5},{value:"System Properties",id:"system-properties",level:3},{value:"Main Throttling Property",id:"main-throttling-property",level:3},{value:"How Unjailing Affects the Main Throttling Property",id:"how-unjailing-affects-the-main-throttling-property",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function m(s){const e={a:"a",annotation:"annotation",blockquote:"blockquote",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",li:"li",math:"math",mfrac:"mfrac",mi:"mi",mn:"mn",mo:"mo",mrow:"mrow",msub:"msub",ol:"ol",p:"p",pre:"pre",semantics:"semantics",span:"span",strong:"strong",ul:"ul",...(0,n.a)(),...s.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"adr-002-jail-throttling",children:"ADR 002: Jail Throttling"}),"\n",(0,i.jsx)(e.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:"2023-01-26: Initial Draft"}),"\n",(0,i.jsx)(e.li,{children:"2023-02-07: Property refined, ADR ready to review/merge"}),"\n",(0,i.jsx)(e.li,{children:"2023-11-22: Refactor for better understanding"}),"\n"]}),"\n",(0,i.jsx)(e.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(e.p,{children:"Accepted"}),"\n",(0,i.jsx)(e.h2,{id:"context",children:"Context"}),"\n",(0,i.jsx)(e.p,{children:"The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols.\nIn practice, this assumption may not hold.\nA malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider."}),"\n",(0,i.jsx)(e.p,{children:"Before the throttling feature was implemented, the following attack was possible.\nAttacker(s) would create provider validators just below the provider's active set.\nUsing a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once.\nControl of the provider would then pass over to the attackers' validators.\nThis enables the attacker(s) to halt the provider.\nOr even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC."}),"\n",(0,i.jsx)(e.h2,{id:"decision",children:"Decision"}),"\n",(0,i.jsx)(e.p,{children:"The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack,\ni.e., this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time."}),"\n",(0,i.jsx)(e.h3,{id:"required-state",children:"Required State"}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:"Slash meter:"})," There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time.\nThis meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params."]}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:"Global entry queue:"}),' There exists a single queue which stores "global slash entries".\nThese entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering.\nThis queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.']}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:"Per-chain data queue:"}),' For each established consumer, there exists a queue which stores "throttled packet data",\ni.e.,pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering.\nOrder is enforced by IBC sequence number.\nThese "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.']}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.em,{children:"Note:"})," The reason for a multiple-queue design is the ",(0,i.jsx)(e.em,{children:"VSC Maturity and Slashing Order"})," property (see ",(0,i.jsx)(e.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing",children:"spec"}),").\nThere are other ways to ensure such a property (like a queue of linked lists, etc.), but the proposed approach seemed to be the most understandable and easiest to implement with a KV store."]}),"\n",(0,i.jsx)(e.h3,{id:"params",children:"Params"}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:"SlashMeterReplenishPeriod"})," -- the period after which the slash meter is replenished."]}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," -- the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs. This param also serves as a maximum fraction of total voting power that the slash meter can hold."]}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:"MaxThrottledPackets"})," -- the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value.\nThis param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness."]}),"\n",(0,i.jsx)(e.h3,{id:"protocol-overview",children:"Protocol Overview"}),"\n",(0,i.jsx)(e.h4,{id:"onrecvslashpacket",children:"OnRecvSlashPacket"}),"\n",(0,i.jsx)(e.p,{children:"Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:"}),"\n",(0,i.jsxs)(e.ol,{children:["\n",(0,i.jsx)(e.li,{children:"A global slash entry is queued."}),"\n",(0,i.jsx)(e.li,{children:"The data of such a packet is added to the per-chain queue."}),"\n"]}),"\n",(0,i.jsx)(e.h4,{id:"onrecvvscmaturedpacket",children:"OnRecvVSCMaturedPacket"}),"\n",(0,i.jsx)(e.p,{children:"Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue."}),"\n",(0,i.jsx)(e.h4,{id:"endblocker",children:"Endblocker"}),"\n",(0,i.jsxs)(e.p,{children:["In the ",(0,i.jsx)(e.code,{children:"EndBlock"})," of the provider CCV module, there are three actions performed:"]}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:"replenish the slash meter;"}),"\n",(0,i.jsxs)(e.li,{children:["handle the leading ",(0,i.jsx)(e.code,{children:"VSCMaturedPackets"}),";"]}),"\n",(0,i.jsx)(e.li,{children:"and handle the throttle queues."}),"\n"]}),"\n",(0,i.jsx)(e.h5,{id:"slash-meter-replenishment",children:"Slash Meter Replenishment"}),"\n",(0,i.jsxs)(e.p,{children:["Once the slash meter becomes not full, it'll be replenished after ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishPeriod"})," by incrementing the meter with its allowance for the replenishment block, where ",(0,i.jsx)(e.code,{children:"allowance"})," = ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," * ",(0,i.jsx)(e.code,{children:"currentTotalVotingPower"}),".\nThe slash meter will never exceed its current allowance (function of the total voting power for the block) in value."]}),"\n",(0,i.jsx)(e.p,{children:"Note a few things:"}),"\n",(0,i.jsxs)(e.ol,{children:["\n",(0,i.jsx)(e.li,{children:"The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power.\nIn such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods."}),"\n",(0,i.jsx)(e.li,{children:"Total voting power of a chain changes over time, especially as validators are jailed.\nAs validators are jailed, total voting power decreases, and so does the jailing allowance.\nSee below for more detailed throttling property discussion."}),"\n",(0,i.jsxs)(e.li,{children:["The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1.\nIf the ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," is set too low, integer rounding will put this minimum value into effect.\nThat is, if ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," * ",(0,i.jsx)(e.code,{children:"currentTotalVotingPower"})," < 1, then the effective allowance would be 1.\nThis min value of allowance ensures that there's some packets handled over time, even if that is a very long time.\nIt's a crude solution to an edge case caused by too small of a replenishment fraction."]}),"\n"]}),"\n",(0,i.jsxs)(e.p,{children:["The behavior described above is achieved by executing ",(0,i.jsx)(e.code,{children:"CheckForSlashMeterReplenishment()"})," every ",(0,i.jsx)(e.code,{children:"EndBlock"}),", BEFORE ",(0,i.jsx)(e.code,{children:"HandleThrottleQueues()"})," is executed."]}),"\n",(0,i.jsx)(e.h5,{id:"handle-leading-vscmaturedpackets",children:"Handle Leading VSCMaturedPackets"}),"\n",(0,i.jsxs)(e.p,{children:["In every block, it is possible that ",(0,i.jsx)(e.code,{children:"VSCMaturedPacket"}),' data was queued before any slash packet data.\nSince this "leading" VSCMatured packet data does not have to be throttled (see ',(0,i.jsx)(e.em,{children:"VSC Maturity and Slashing Order"}),"), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes."]}),"\n",(0,i.jsx)(e.h5,{id:"handle-throttle-queues",children:"Handle Throttle Queues"}),"\n",(0,i.jsxs)(e.p,{children:["In every ",(0,i.jsx)(e.code,{children:"EndBlock"}),", the following logic is executed to handle data from the throttle queues."]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-typescript",children:"meter := getSlashMeter()\n\n// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist \nwhile meter.IsPositiveOrZero() && entriesExist() {\n // Get next entry in queue\n entry := getNextGlobalSlashEntry()\n // Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet\n valPower := entry.getValPower()\n meter = meter - valPower\n // Using the per-chain queue, handle the single slash packet using its queued data,\n // then handle all trailing VSCMatured packets for this consumer\n handleSlashPacketAndTrailingVSCMaturedPackets(entry)\n // Delete entry in global queue, delete handled data\n entry.Delete()\n deleteThrottledSlashPacketData()\n deleteTrailingVSCMaturedPacketData()\n}\n"})}),"\n",(0,i.jsx)(e.h3,{id:"system-properties",children:"System Properties"}),"\n",(0,i.jsxs)(e.p,{children:["All CCV system properties should be maintained by implementing this feature, see ",(0,i.jsx)(e.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing",children:"CCV spec - Consumer Initiated Slashing"}),"."]}),"\n",(0,i.jsxs)(e.p,{children:["One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than ",(0,i.jsx)(e.code,{children:"MaxThrottledPackets"}),", then the provider binary will panic, and the provider chain will halt.\nTherefore this param should be set carefully. See ",(0,i.jsx)(e.code,{children:"SetThrottledPacketDataSize"}),".\nThis behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators."]}),"\n",(0,i.jsx)(e.h3,{id:"main-throttling-property",children:"Main Throttling Property"}),"\n",(0,i.jsx)(e.p,{children:"Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions."}),"\n",(0,i.jsx)(e.p,{children:"First, we introduce the following definitions:"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:'A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.'}),"\n",(0,i.jsx)(e.li,{children:'The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.'}),"\n",(0,i.jsxs)(e.li,{children:["There is a list of honest validators such that if they are jailed, ",(0,i.jsx)(e.code,{children:"X"}),"% of the initial validator set will be jailed."]}),"\n"]}),"\n",(0,i.jsx)(e.p,{children:"For the Throttling Property to hold, the following assumptions must be true:"}),"\n",(0,i.jsxs)(e.ol,{children:["\n",(0,i.jsx)(e.li,{children:"We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack."}),"\n",(0,i.jsxs)(e.li,{children:["No validator has more than ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," of total voting power on the provider."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," is large enough that ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," * ",(0,i.jsx)(e.code,{children:"currentTotalVotingPower"})," > 1,\ni.e., the replenish fraction is set high enough that we can ignore the effects of rounding."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:"SlashMeterReplenishPeriod"})," is sufficiently longer than the time it takes to produce a block."]}),"\n"]}),"\n",(0,i.jsx)(e.p,{children:(0,i.jsx)(e.em,{children:"Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined."})}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:"Throttling Property"}),": The time it takes to jail/tombstone ",(0,i.jsx)(e.code,{children:"X"}),"% of the initial validator set will be greater than or equal to\n",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"S"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"M"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"R"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"p"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"n"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"P"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"o"}),(0,i.jsx)(e.mi,{children:"d"})]}),(0,i.jsx)(e.mo,{children:"\u22c5"}),(0,i.jsxs)(e.mfrac,{children:[(0,i.jsx)(e.mi,{children:"X"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"S"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"M"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"R"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"p"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"n"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"F"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"c"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"o"}),(0,i.jsx)(e.mi,{children:"n"})]})]}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mn,{children:"2"}),(0,i.jsx)(e.mo,{children:"\u22c5"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"S"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"M"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"R"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"p"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"n"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"P"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"o"}),(0,i.jsx)(e.mi,{children:"d"})]})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\mathit{SlashMeterReplenishPeriod} \\cdot \\frac{X}{\\mathit{SlashMeterReplenishFraction}} - 2 \\cdot \\mathit{SlashMeterReplenishPeriod}"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,i.jsx)(e.span,{className:"mord",children:(0,i.jsx)(e.span,{className:"mord mathit",children:"SlashMeterReplenishPeriod"})}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u22c5"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"1.3534em",verticalAlign:"-0.4811em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,i.jsx)(e.span,{className:"mfrac",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsxs)(e.span,{className:"vlist",style:{height:"0.8723em"},children:[(0,i.jsxs)(e.span,{style:{top:"-2.655em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"SlashMeterReplenishFraction"})})})})]}),(0,i.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,i.jsxs)(e.span,{style:{top:"-3.394em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.07847em"},children:"X"})})})]})]}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.4811em"},children:(0,i.jsx)(e.span,{})})})]})}),(0,i.jsx)(e.span,{className:"mclose nulldelimiter"})]}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6444em"}}),(0,i.jsx)(e.span,{className:"mord",children:"2"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u22c5"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,i.jsx)(e.span,{className:"mord",children:(0,i.jsx)(e.span,{className:"mord mathit",children:"SlashMeterReplenishPeriod"})})]})]})]}),"."]}),"\n",(0,i.jsxs)(e.blockquote,{children:["\n",(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:"Intuition"})}),"\n",(0,i.jsx)(e.p,{children:"Let's use the following notation:"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:[(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"C"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"})]})})]}),": Number of replenishment cycles"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"P"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"P"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"P"})]})})]}),": ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"S"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"M"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"R"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"p"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"n"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"P"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"o"}),(0,i.jsx)(e.mi,{children:"d"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\mathit{SlashMeterReplenishPeriod}"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,i.jsx)(e.span,{className:"mord",children:(0,i.jsx)(e.span,{className:"mord mathit",children:"SlashMeterReplenishPeriod"})})]})})]})]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"F"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"F"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"})]})})]}),": ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"S"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"M"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"R"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"p"}),(0,i.jsx)(e.mi,{children:"l"}),(0,i.jsx)(e.mi,{children:"e"}),(0,i.jsx)(e.mi,{children:"n"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"s"}),(0,i.jsx)(e.mi,{children:"h"}),(0,i.jsx)(e.mi,{children:"F"}),(0,i.jsx)(e.mi,{children:"r"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"c"}),(0,i.jsx)(e.mi,{children:"t"}),(0,i.jsx)(e.mi,{children:"i"}),(0,i.jsx)(e.mi,{children:"o"}),(0,i.jsx)(e.mi,{children:"n"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\mathit{SlashMeterReplenishFraction}"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,i.jsx)(e.span,{className:"mord",children:(0,i.jsx)(e.span,{className:"mord mathit",children:"SlashMeterReplenishFraction"})})]})})]})]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsxs)(e.msub,{children:[(0,i.jsx)(e.mi,{children:"V"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"m"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"x"})]})]})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"V_{\\mathit{max}}"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.22222em"},children:"V"}),(0,i.jsx)(e.span,{className:"msupsub",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.1514em"},children:(0,i.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.2222em",marginRight:"0.05em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"max"})})})})]})}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,i.jsx)(e.span,{})})})]})})]})]})})]}),": Max power of a validator as a fraction of total voting power"]}),"\n"]}),"\n",(0,i.jsxs)(e.p,{children:["In ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"C"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"})]})})]})," number of replenishment cycles, the fraction of total voting power that can be removed, ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"a"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"a"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.4306em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",children:"a"})]})})]}),", is ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mo,{children:"\u2264"}),(0,i.jsx)(e.mi,{children:"F"}),(0,i.jsx)(e.mo,{children:"\u22c5"}),(0,i.jsx)(e.mi,{children:"C"}),(0,i.jsx)(e.mo,{children:"+"}),(0,i.jsxs)(e.msub,{children:[(0,i.jsx)(e.mi,{children:"V"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"m"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"x"})]})]})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"a \\leq F \\cdot C + V_{\\mathit{max}}"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.7719em",verticalAlign:"-0.136em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",children:"a"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,i.jsx)(e.span,{className:"mrel",children:"\u2264"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u22c5"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.7667em",verticalAlign:"-0.0833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"+"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.22222em"},children:"V"}),(0,i.jsx)(e.span,{className:"msupsub",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.1514em"},children:(0,i.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.2222em",marginRight:"0.05em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"max"})})})})]})}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,i.jsx)(e.span,{})})})]})})]})]})]})]})," (where ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsxs)(e.msub,{children:[(0,i.jsx)(e.mi,{children:"V"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"m"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"x"})]})]})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"V_{\\mathit{max}}"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.22222em"},children:"V"}),(0,i.jsx)(e.span,{className:"msupsub",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.1514em"},children:(0,i.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.2222em",marginRight:"0.05em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"max"})})})})]})}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,i.jsx)(e.span,{})})})]})})]})]})})]})," is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value)."]}),"\n",(0,i.jsxs)(e.p,{children:["So, we need at least ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"C"}),(0,i.jsx)(e.mo,{children:"\u2265"}),(0,i.jsxs)(e.mfrac,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsxs)(e.msub,{children:[(0,i.jsx)(e.mi,{children:"V"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"m"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"x"})]})]})]}),(0,i.jsx)(e.mi,{children:"F"})]})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C \\geq \\frac{a - V_{\\mathit{max}}}{F}"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8193em",verticalAlign:"-0.136em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,i.jsx)(e.span,{className:"mrel",children:"\u2265"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"1.2334em",verticalAlign:"-0.345em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,i.jsx)(e.span,{className:"mfrac",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsxs)(e.span,{className:"vlist",style:{height:"0.8884em"},children:[(0,i.jsxs)(e.span,{style:{top:"-2.655em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"})})})]}),(0,i.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,i.jsxs)(e.span,{style:{top:"-3.4101em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mord mathnormal mtight",children:"a"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u2212"}),(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.22222em"},children:"V"}),(0,i.jsx)(e.span,{className:"msupsub",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.1645em"},children:(0,i.jsxs)(e.span,{style:{top:"-2.357em",marginLeft:"-0.2222em",marginRight:"0.0714em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"2.5em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size3 size1 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"max"})})})})]})}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.143em"},children:(0,i.jsx)(e.span,{})})})]})})]})]})})]})]}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.345em"},children:(0,i.jsx)(e.span,{})})})]})}),(0,i.jsx)(e.span,{className:"mclose nulldelimiter"})]})]})]})]})," cycles to remove ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"a"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"a"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.4306em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",children:"a"})]})})]})," fraction of the total voting power."]}),"\n",(0,i.jsxs)(e.p,{children:["Since we defined the start of the attack to be the moment when the first slash request arrives, then ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"F"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"F"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"})]})})]})," fraction of the initial validator set can be jailed immediately. For the remaining ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"X"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mi,{children:"F"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"X - F"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.7667em",verticalAlign:"-0.0833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07847em"},children:"X"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"})]})]})]})," fraction of the initial validator set to be jailed, it takes at least ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"C"}),(0,i.jsx)(e.mo,{children:"\u2265"}),(0,i.jsxs)(e.mfrac,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mo,{stretchy:"false",children:"("}),(0,i.jsx)(e.mi,{children:"X"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mi,{children:"F"}),(0,i.jsx)(e.mo,{stretchy:"false",children:")"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsxs)(e.msub,{children:[(0,i.jsx)(e.mi,{children:"V"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"m"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"x"})]})]})]}),(0,i.jsx)(e.mi,{children:"F"})]})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C \\geq \\frac{(X - F) - V_{\\mathit{max}}}{F}"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8193em",verticalAlign:"-0.136em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,i.jsx)(e.span,{className:"mrel",children:"\u2265"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"1.355em",verticalAlign:"-0.345em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,i.jsx)(e.span,{className:"mfrac",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsxs)(e.span,{className:"vlist",style:{height:"1.01em"},children:[(0,i.jsxs)(e.span,{style:{top:"-2.655em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"})})})]}),(0,i.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,i.jsxs)(e.span,{style:{top:"-3.485em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mopen mtight",children:"("}),(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.07847em"},children:"X"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"}),(0,i.jsx)(e.span,{className:"mclose mtight",children:")"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u2212"}),(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.22222em"},children:"V"}),(0,i.jsx)(e.span,{className:"msupsub",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.1645em"},children:(0,i.jsxs)(e.span,{style:{top:"-2.357em",marginLeft:"-0.2222em",marginRight:"0.0714em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"2.5em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size3 size1 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"max"})})})})]})}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.143em"},children:(0,i.jsx)(e.span,{})})})]})})]})]})})]})]}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.345em"},children:(0,i.jsx)(e.span,{})})})]})}),(0,i.jsx)(e.span,{className:"mclose nulldelimiter"})]})]})]})]})," cycles. Using the assumption that ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsxs)(e.msub,{children:[(0,i.jsx)(e.mi,{children:"V"}),(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"m"}),(0,i.jsx)(e.mi,{children:"a"}),(0,i.jsx)(e.mi,{children:"x"})]})]}),(0,i.jsx)(e.mo,{children:"\u2264"}),(0,i.jsx)(e.mi,{children:"F"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"V_{\\mathit{max}} \\leq F"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.22222em"},children:"V"}),(0,i.jsx)(e.span,{className:"msupsub",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.1514em"},children:(0,i.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.2222em",marginRight:"0.05em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathit mtight",children:"max"})})})})]})}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,i.jsx)(e.span,{})})})]})})]}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,i.jsx)(e.span,{className:"mrel",children:"\u2264"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"})]})]})]})," (assumption 2), we get ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"C"}),(0,i.jsx)(e.mo,{children:"\u2265"}),(0,i.jsxs)(e.mfrac,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"X"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mn,{children:"2"}),(0,i.jsx)(e.mi,{children:"F"})]}),(0,i.jsx)(e.mi,{children:"F"})]})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C \\geq \\frac{X - 2F}{F}"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.8193em",verticalAlign:"-0.136em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,i.jsx)(e.span,{className:"mrel",children:"\u2265"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"1.2173em",verticalAlign:"-0.345em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,i.jsx)(e.span,{className:"mfrac",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsxs)(e.span,{className:"vlist",style:{height:"0.8723em"},children:[(0,i.jsxs)(e.span,{style:{top:"-2.655em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"})})})]}),(0,i.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,i.jsxs)(e.span,{style:{top:"-3.394em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.07847em"},children:"X"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mord mtight",children:"2"}),(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"})]})})]})]}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.345em"},children:(0,i.jsx)(e.span,{})})})]})}),(0,i.jsx)(e.span,{className:"mclose nulldelimiter"})]})]})]})]})," cycles."]}),"\n",(0,i.jsxs)(e.p,{children:["In order to execute ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"C"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"})]})})]})," cycles, we need ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"C"}),(0,i.jsx)(e.mo,{children:"\u22c5"}),(0,i.jsx)(e.mi,{children:"P"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"C \\cdot P"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07153em"},children:"C"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u22c5"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"P"})]})]})]})," time."]}),"\n",(0,i.jsxs)(e.p,{children:["Thus, jailing the remaining ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"X"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mi,{children:"F"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"X - F"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.7667em",verticalAlign:"-0.0833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.07847em"},children:"X"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"})]})]})]})," fraction of the initial validator set corresponds to ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsxs)(e.mfrac,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"P"}),(0,i.jsx)(e.mo,{children:"\u22c5"}),(0,i.jsx)(e.mo,{stretchy:"false",children:"("}),(0,i.jsx)(e.mi,{children:"X"}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mn,{children:"2"}),(0,i.jsx)(e.mi,{children:"F"}),(0,i.jsx)(e.mo,{stretchy:"false",children:")"})]}),(0,i.jsx)(e.mi,{children:"F"})]})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\frac{P \\cdot (X - 2F)}{F}"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"1.355em",verticalAlign:"-0.345em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,i.jsx)(e.span,{className:"mfrac",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsxs)(e.span,{className:"vlist",style:{height:"1.01em"},children:[(0,i.jsxs)(e.span,{style:{top:"-2.655em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"})})})]}),(0,i.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,i.jsxs)(e.span,{style:{top:"-3.485em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"P"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u22c5"}),(0,i.jsx)(e.span,{className:"mopen mtight",children:"("}),(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.07847em"},children:"X"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mord mtight",children:"2"}),(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"}),(0,i.jsx)(e.span,{className:"mclose mtight",children:")"})]})})]})]}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.345em"},children:(0,i.jsx)(e.span,{})})})]})}),(0,i.jsx)(e.span,{className:"mclose nulldelimiter"})]})]})})]})," time."]}),"\n",(0,i.jsxs)(e.p,{children:["In other words, the attack must take at least ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsxs)(e.mfrac,{children:[(0,i.jsxs)(e.mrow,{children:[(0,i.jsx)(e.mi,{children:"P"}),(0,i.jsx)(e.mo,{children:"\u22c5"}),(0,i.jsx)(e.mi,{children:"X"})]}),(0,i.jsx)(e.mi,{children:"F"})]}),(0,i.jsx)(e.mo,{children:"\u2212"}),(0,i.jsx)(e.mn,{children:"2"}),(0,i.jsx)(e.mi,{children:"P"})]}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\frac{P \\cdot X}{F} - 2P"})]})})}),(0,i.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"1.2173em",verticalAlign:"-0.345em"}}),(0,i.jsxs)(e.span,{className:"mord",children:[(0,i.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,i.jsx)(e.span,{className:"mfrac",children:(0,i.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,i.jsxs)(e.span,{className:"vlist-r",children:[(0,i.jsxs)(e.span,{className:"vlist",style:{height:"0.8723em"},children:[(0,i.jsxs)(e.span,{style:{top:"-2.655em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsx)(e.span,{className:"mord mtight",children:(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"F"})})})]}),(0,i.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,i.jsxs)(e.span,{style:{top:"-3.394em"},children:[(0,i.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,i.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,i.jsxs)(e.span,{className:"mord mtight",children:[(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.13889em"},children:"P"}),(0,i.jsx)(e.span,{className:"mbin mtight",children:"\u22c5"}),(0,i.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.07847em"},children:"X"})]})})]})]}),(0,i.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,i.jsx)(e.span,{className:"vlist-r",children:(0,i.jsx)(e.span,{className:"vlist",style:{height:"0.345em"},children:(0,i.jsx)(e.span,{})})})]})}),(0,i.jsx)(e.span,{className:"mclose nulldelimiter"})]}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,i.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,i.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord",children:"2"}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"P"})]})]})]})," time (in the units of replenish period ",(0,i.jsxs)(e.span,{className:"katex",children:[(0,i.jsx)(e.span,{className:"katex-mathml",children:(0,i.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,i.jsxs)(e.semantics,{children:[(0,i.jsx)(e.mrow,{children:(0,i.jsx)(e.mi,{children:"P"})}),(0,i.jsx)(e.annotation,{encoding:"application/x-tex",children:"P"})]})})}),(0,i.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,i.jsxs)(e.span,{className:"base",children:[(0,i.jsx)(e.span,{className:"strut",style:{height:"0.6833em"}}),(0,i.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"P"})]})})]}),")."]}),"\n"]}),"\n",(0,i.jsxs)(e.p,{children:["This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests.\nFor example, if ",(0,i.jsx)(e.code,{children:"SlashMeterReplenishFraction"})," is set to ",(0,i.jsx)(e.code,{children:"0.06"}),", then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub.\nNote that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power."]}),"\n",(0,i.jsx)(e.p,{children:"Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings."}),"\n",(0,i.jsx)(e.h3,{id:"how-unjailing-affects-the-main-throttling-property",children:"How Unjailing Affects the Main Throttling Property"}),"\n",(0,i.jsx)(e.p,{children:"Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained."}),"\n",(0,i.jsx)(e.p,{children:"If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider."}),"\n",(0,i.jsx)(e.p,{children:"In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack."}),"\n",(0,i.jsx)(e.h2,{id:"consequences",children:"Consequences"}),"\n",(0,i.jsx)(e.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:"The described attack is slowed down in seemingly all cases."}),"\n",(0,i.jsx)(e.li,{children:"If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded."}),"\n"]}),"\n",(0,i.jsx)(e.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:["Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below.\nHowever, this is sacrificing liveness in a edge case scenario for the sake of security.\nAs an improvement, ",(0,i.jsx)(e.a,{href:"https://github.com/cosmos/interchain-security/issues/713",children:"using retries"})," would fully prevent this attack vector."]}),"\n"]}),"\n",(0,i.jsx)(e.h3,{id:"neutral",children:"Neutral"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:"Additional state is introduced to the provider chain."}),"\n",(0,i.jsx)(e.li,{children:"VSCMatured and slash packet data is not always handled in the same block that it is received."}),"\n"]}),"\n",(0,i.jsx)(e.h2,{id:"references",children:"References"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:"https://github.com/cosmos/interchain-security/issues/404",children:"Original issue inspiring throttling feature"})}),"\n",(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:"https://github.com/cosmos/interchain-security/issues/594",children:"Issue on DOS vector"})}),"\n",(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:"https://github.com/cosmos/interchain-security/issues/685",children:"Consideration of another attack vector"})}),"\n"]})]})}function d(s={}){const{wrapper:e}={...(0,n.a)(),...s.components};return e?(0,i.jsx)(e,{...s,children:(0,i.jsx)(m,{...s})}):m(s)}},1151:(s,e,a)=>{a.d(e,{Z:()=>r,a:()=>l});var i=a(7294);const n={},t=i.createContext(n);function l(s){const e=i.useContext(t);return i.useMemo((function(){return"function"==typeof s?s(e):{...e,...s}}),[e,s])}function r(s){let e;return e=s.disableParentContext?"function"==typeof s.components?s.components(n):s.components||n:l(s.components),i.createElement(t.Provider,{value:e},s.children)}}}]); \ No newline at end of file diff --git a/assets/js/bc8b8418.63027b8e.js b/assets/js/bc8b8418.63027b8e.js new file mode 100644 index 0000000000..705622721f --- /dev/null +++ b/assets/js/bc8b8418.63027b8e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4704],{1824:(e,i,t)=>{t.r(i),t.d(i,{assets:()=>c,contentTitle:()=>o,default:()=>d,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var n=t(5893),r=t(1151);const a={sidebar_position:2},o="Terminology",s={id:"introduction/terminology",title:"Terminology",description:"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.",source:"@site/docs/introduction/terminology.md",sourceDirName:"introduction",slug:"/introduction/terminology",permalink:"/interchain-security/introduction/terminology",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/introduction/overview"},next:{title:"Interchain Security Parameters",permalink:"/interchain-security/introduction/params"}},c={},l=[{value:"Shared Security",id:"shared-security",level:2},{value:"Interchain Security",id:"interchain-security",level:2},{value:"Replicated Security",id:"replicated-security",level:2},{value:"Partial Set Security",id:"partial-set-security",level:2},{value:"Mesh security",id:"mesh-security",level:2},{value:"Consumer Chain",id:"consumer-chain",level:2},{value:"Standalone Chain",id:"standalone-chain",level:2},{value:"Changeover Procedure",id:"changeover-procedure",level:2}];function h(e){const i={a:"a",h1:"h1",h2:"h2",p:"p",strong:"strong",...(0,r.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(i.h1,{id:"terminology",children:"Terminology"}),"\n",(0,n.jsx)(i.p,{children:"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions."}),"\n",(0,n.jsx)(i.h2,{id:"shared-security",children:"Shared Security"}),"\n",(0,n.jsx)(i.p,{children:"Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share its proof-of-stake security with another blockchain or off-chain process."}),"\n",(0,n.jsx)(i.h2,{id:"interchain-security",children:"Interchain Security"}),"\n",(0,n.jsx)(i.p,{children:"Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC."}),"\n",(0,n.jsx)(i.h2,{id:"replicated-security",children:"Replicated Security"}),"\n",(0,n.jsx)(i.p,{children:'A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC.'}),"\n",(0,n.jsx)(i.h2,{id:"partial-set-security",children:"Partial Set Security"}),"\n",(0,n.jsx)(i.p,{children:'A major iteration of Interchain Security, also known as "Interchain Security V2". Partial Set Security allows a provider chain to share only a subset of its validator set with a consumer chain. This subset can be determined by the top N% validators by voting power, or by validators opting in to validate the consumer chain. Partial Set Security allows for more flexible security tradeoffs than Replicated Security.'}),"\n",(0,n.jsx)(i.h2,{id:"mesh-security",children:"Mesh security"}),"\n",(0,n.jsxs)(i.p,{children:["A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see ",(0,n.jsx)(i.a,{href:"https://informal.systems/blog/replicated-vs-mesh-security",children:"Replicated vs. Mesh Security on the Informal Blog"}),"."]}),"\n",(0,n.jsx)(i.h2,{id:"consumer-chain",children:"Consumer Chain"}),"\n",(0,n.jsx)(i.p,{children:"Chain that is secured by the validator set of the provider, instead of its own.\nInterchain Security allows a subset of the provider chain's validator set to validate blocks on the consumer chain."}),"\n",(0,n.jsx)(i.h2,{id:"standalone-chain",children:"Standalone Chain"}),"\n",(0,n.jsx)(i.p,{children:"Chain that is secured by its own validator set. This chain does not participate in Interchain Security."}),"\n",(0,n.jsx)(i.p,{children:'Standalone chains may sometimes be called "sovereign" - the terms are synonymous.'}),"\n",(0,n.jsx)(i.h2,{id:"changeover-procedure",children:"Changeover Procedure"}),"\n",(0,n.jsxs)(i.p,{children:["Chains that were not initially launched as consumers of Interchain Security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the ",(0,n.jsx)(i.strong,{children:"changeover procedure"})," and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain."]})]})}function d(e={}){const{wrapper:i}={...(0,r.a)(),...e.components};return i?(0,n.jsx)(i,{...e,children:(0,n.jsx)(h,{...e})}):h(e)}},1151:(e,i,t)=>{t.d(i,{Z:()=>s,a:()=>o});var n=t(7294);const r={},a=n.createContext(r);function o(e){const i=n.useContext(a);return n.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function s(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),n.createElement(a.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/bdf2101f.feae5bf3.js b/assets/js/bdf2101f.feae5bf3.js new file mode 100644 index 0000000000..ca8253038b --- /dev/null +++ b/assets/js/bdf2101f.feae5bf3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7943],{3644:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>d,contentTitle:()=>t,default:()=>h,frontMatter:()=>s,metadata:()=>a,toc:()=>c});var r=o(5893),i=o(1151);const s={sidebar_position:3},t="ICS Provider Proposals",a={id:"features/proposals",title:"ICS Provider Proposals",description:"Interchain security module introduces 3 new proposal types to the provider.",source:"@site/versioned_docs/version-v5.0.0/features/proposals.md",sourceDirName:"features",slug:"/features/proposals",permalink:"/interchain-security/v5.0.0/features/proposals",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Reward Distribution",permalink:"/interchain-security/v5.0.0/features/reward-distribution"},next:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/v5.0.0/features/slashing"}},d={},c=[{value:"<code>ConsumerAdditionProposal</code>",id:"consumeradditionproposal",level:2},{value:"<code>ConsumerRemovalProposal</code>",id:"consumerremovalproposal",level:2},{value:"ChangeRewardDenomProposal",id:"changerewarddenomproposal",level:2}];function l(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"ics-provider-proposals",children:"ICS Provider Proposals"}),"\n",(0,r.jsx)(n.p,{children:"Interchain security module introduces 3 new proposal types to the provider."}),"\n",(0,r.jsx)(n.p,{children:"The proposals are used to propose upcoming interchain security events through governance."}),"\n",(0,r.jsx)(n.h2,{id:"consumeradditionproposal",children:(0,r.jsx)(n.code,{children:"ConsumerAdditionProposal"})}),"\n",(0,r.jsx)(n.admonition,{type:"info",children:(0,r.jsxs)(n.p,{children:["If you are preparing a ",(0,r.jsx)(n.code,{children:"ConsumerAdditionProposal"})," you can find more information in the ",(0,r.jsx)(n.a,{href:"/interchain-security/v5.0.0/consumer-development/onboarding",children:"consumer onboarding checklist"}),"."]})}),"\n",(0,r.jsx)(n.p,{children:"Proposal type used to suggest adding a new consumer chain."}),"\n",(0,r.jsxs)(n.p,{children:["When proposals of this type are passed and the ",(0,r.jsx)(n.code,{children:"spawn_time"})," specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain."]}),"\n",(0,r.jsx)(n.p,{children:"Minimal example:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",children:'{\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n "title": "Add consumer chain",\n "description": ".md description of your chain and all other relevant information",\n "chain_id": "newchain-1",\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Unbonding period for the consumer chain.\n // It should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n "transfer_timeout_period": 1800000000000,\n "consumer_redistribution_fraction": "0.75",\n "blocks_per_distribution_transmission": 1000,\n "historical_entries": 10000,\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1"\n // relevant for chains performing a standalone to consumer changeover\n // in order to maintain the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123"\n}\n'})}),"\n",(0,r.jsxs)(n.p,{children:["More examples can be found in the interchain security testnet repository ",(0,r.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/stopped/baryon-1/proposal-baryon-1.json",children:"here"})," and ",(0,r.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/stopped/noble-1/start-proposal-noble-1.json",children:"here"}),"."]}),"\n",(0,r.jsx)(n.h2,{id:"consumerremovalproposal",children:(0,r.jsx)(n.code,{children:"ConsumerRemovalProposal"})}),"\n",(0,r.jsx)(n.p,{children:"Proposal type used to suggest removing an existing consumer chain."}),"\n",(0,r.jsx)(n.p,{children:"When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain.\nAfter the consumer chain removal, the chain in question will no longer be secured by the provider's validator set."}),"\n",(0,r.jsx)(n.admonition,{type:"info",children:(0,r.jsxs)(n.p,{children:["The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain.\nAdditional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set.\nMore information will be made available in the ",(0,r.jsx)(n.a,{href:"/interchain-security/v5.0.0/consumer-development/offboarding",children:"Consumer Offboarding Checklist"}),"."]})}),"\n",(0,r.jsx)(n.p,{children:"Minimal example:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",children:'{\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details"\n}\n'})}),"\n",(0,r.jsx)(n.h2,{id:"changerewarddenomproposal",children:"ChangeRewardDenomProposal"}),"\n",(0,r.jsx)(n.p,{children:"Proposal type used to mutate the set of denoms accepted by the provider as rewards."}),"\n",(0,r.jsx)(n.admonition,{type:"tip",children:(0,r.jsxs)(n.p,{children:["A ",(0,r.jsx)(n.code,{children:"ChangeRewardDenomProposal"})," will only be accepted on the provider chain if at least one of the ",(0,r.jsx)(n.code,{children:"denomsToAdd"})," or ",(0,r.jsx)(n.code,{children:"denomsToRemove"})," fields is populated with at least one denom. Also, a denom cannot be repeated in both sets."]})}),"\n",(0,r.jsx)(n.p,{children:"Minimal example:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",children:'{\n "title": "Add uatom as a reward denom",\n "description": "Here is more information about the proposal",\n "denomsToAdd": ["uatom"],\n "denomsToRemove": []\n}\n'})}),"\n",(0,r.jsxs)(n.admonition,{type:"tip",children:[(0,r.jsxs)(n.p,{children:["Besides native provider denoms (e.g., ",(0,r.jsx)(n.code,{children:"uatom"})," for the Cosmos Hub), please use the ",(0,r.jsx)(n.code,{children:"ibc/*"})," denom trace format.\nFor example, for ",(0,r.jsx)(n.code,{children:"untrn"})," transferred over the path ",(0,r.jsx)(n.code,{children:"transfer/channel-569"}),", the denom trace\ncan be queried using the following command:"]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"> gaiad query ibc-transfer denom-hash transfer/channel-569/untrn\nhash: 0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5\n"})}),(0,r.jsxs)(n.p,{children:["Then use the resulting hash in the ",(0,r.jsx)(n.code,{children:"ChangeRewardDenomProposal"}),", e.g.,"]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",children:'{\n "title": "Add untrn as a reward denom",\n "description": "Here is more information about the proposal",\n "denomsToAdd": ["ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5"],\n "denomsToRemove": []\n}\n'})})]})]})}function h(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},1151:(e,n,o)=>{o.d(n,{Z:()=>a,a:()=>t});var r=o(7294);const i={},s=r.createContext(i);function t(e){const n=r.useContext(s);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:t(e.components),r.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/bfc97f30.ec5561cc.js b/assets/js/bfc97f30.ec5561cc.js new file mode 100644 index 0000000000..dd3cc68fec --- /dev/null +++ b/assets/js/bfc97f30.ec5561cc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9253],{3473:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>h});var n=i(5893),a=i(1151);const o={sidebar_position:6},r="Partial Set Security",s={id:"features/partial-set-security",title:"Partial Set Security",description:"Partial Set Security (PSS) allows consumer chains to leverage only a subset of validators from the provider chain, which offers more flexibility than the traditional Replicated Security model. By introducing the top_N parameter, each consumer chain can choose the extent of security needed:",source:"@site/docs/features/partial-set-security.md",sourceDirName:"features",slug:"/features/partial-set-security",permalink:"/interchain-security/features/partial-set-security",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"tutorialSidebar",previous:{title:"Democracy modules",permalink:"/interchain-security/features/democracy-modules"},next:{title:"Power Shaping",permalink:"/interchain-security/features/power-shaping"}},c={},h=[];function l(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",li:"li",p:"p",ul:"ul",...(0,a.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"partial-set-security",children:"Partial Set Security"}),"\n",(0,n.jsx)(t.p,{children:"Partial Set Security (PSS) allows consumer chains to leverage only a subset of validators from the provider chain, which offers more flexibility than the traditional Replicated Security model. By introducing the top_N parameter, each consumer chain can choose the extent of security needed:"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsx)(t.p,{children:"Top N: Requires the top N% validators from the provider chain to secure the consumer chain. This guarantees that the validators with the most power on the provider will validate the consumer chain, while others can voluntarily opt in."}),"\n"]}),"\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsxs)(t.p,{children:["Opt-In: If the ",(0,n.jsx)(t.code,{children:"top_N"})," parameter is set to zero, no validator is mandated to secure the consumer chain. Instead, any validator from the provider chain can opt in using a dedicated transaction."]}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(t.p,{children:"An advantage of a Top N chain is that the consumer chain is guaranteed to receive at least a certain fraction of the market cap of the provider chain in security. In turn, this chain needs to be approved by governance, since validators will be forced to run the chain. Thus, Top N chains should typically expect to need to provide a strong case for why they should be added to the provider chain, and they should make sure they offer enough rewards to incentivize validators and delegators to vote for their proposal."}),"\n",(0,n.jsx)(t.p,{children:"Opt-In chains, on the other hand, are more flexible. While for technical reasons, they are also currently added via governance proposals, since validators are never forced to validate these chains and simply opt in if they want to, they should typically expect to get their proposals approved much more easily compared to Top N chains, since validators that do not want to validate the chain can simply choose not to opt in.\nHowever, opt in chains do not get a fixed amount of security as a relation of the market cap of the provider as top N chains do, so opt in chains might want to keep an eye on how many validators have opted in to validate their chain and adjust their reward emissions accordingly to incentivize validators."}),"\n",(0,n.jsx)(t.admonition,{type:"tip",children:(0,n.jsx)(t.p,{children:"Partial Set Security is handled only by the provider chain - the consumer chains are simply sent validator sets, and they are not aware that this represents only a subset of the provider chain's validator set."})}),"\n",(0,n.jsxs)(t.admonition,{type:"caution",children:[(0,n.jsx)(t.p,{children:"Both Opt In and Top N chains currently require a governance proposal to be added to the provider chain."}),(0,n.jsx)(t.p,{children:"For Top N chains, this is also the long term vision for how they are launched."}),(0,n.jsx)(t.p,{children:"For Opt In chains, this is a temporary measure to prevent issues around chain ID squatting, i.e. someone could spuriously register many desirable chain IDs of upcoming consumer chain and simply deny legitimate consumer chains from using them. Eventually, the plan is to allow launching Opt In chains permissionlessly without going through governance, with quality control being handled by the market of validators deciding which chains they would like to validate on."})]}),"\n",(0,n.jsx)(t.admonition,{type:"tip",children:(0,n.jsxs)(t.p,{children:["A running Top N consumer chain might want to become an Opt-In chain or vice versa. This can be achieved by issuing\na ",(0,n.jsx)(t.a,{href:"/interchain-security/features/proposals#consumermodificationproposal",children:(0,n.jsx)(t.code,{children:"ConsumerModificationProposal"})}),"."]})})]})}function d(e={}){const{wrapper:t}={...(0,a.a)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},1151:(e,t,i)=>{i.d(t,{Z:()=>s,a:()=>r});var n=i(7294);const a={},o=n.createContext(a);function r(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function s(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:r(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c1444bce.54c826a6.js b/assets/js/c1444bce.54c826a6.js new file mode 100644 index 0000000000..f85c821b01 --- /dev/null +++ b/assets/js/c1444bce.54c826a6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5776],{7258:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>d,contentTitle:()=>a,default:()=>l,frontMatter:()=>s,metadata:()=>r,toc:()=>c});var n=o(5893),i=o(1151);const s={sidebar_position:16,title:"Partial Set Security"},a="ADR 015: Partial Set Security",r={id:"adrs/adr-015-partial-set-security",title:"Partial Set Security",description:"Changelog",source:"@site/versioned_docs/version-v5.0.0/adrs/adr-015-partial-set-security.md",sourceDirName:"adrs",slug:"/adrs/adr-015-partial-set-security",permalink:"/interchain-security/v5.0.0/adrs/adr-015-partial-set-security",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:16,frontMatter:{sidebar_position:16,title:"Partial Set Security"},sidebar:"tutorialSidebar",previous:{title:"Epochs",permalink:"/interchain-security/v5.0.0/adrs/adr-014-epochs"}},d={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"How do consumer chains join?",id:"how-do-consumer-chains-join",level:3},{value:"State & Query",id:"state--query",level:4},{value:"How do validators opt in?",id:"how-do-validators-opt-in",level:3},{value:"State & Query",id:"state--query-1",level:4},{value:"When do validators opt in?",id:"when-do-validators-opt-in",level:4},{value:"How do validators opt out?",id:"how-do-validators-opt-out",level:3},{value:"State & Query",id:"state--query-2",level:4},{value:"When does a consumer chain start?",id:"when-does-a-consumer-chain-start",level:3},{value:"How do we send the partial validator sets to the consumer chains?",id:"how-do-we-send-the-partial-validator-sets-to-the-consumer-chains",level:3},{value:"How do we distribute rewards?",id:"how-do-we-distribute-rewards",level:3},{value:"Misbehaviour",id:"misbehaviour",level:3},{value:"Fraud votes",id:"fraud-votes",level:4},{value:"Double signing",id:"double-signing",level:4},{value:"Downtime",id:"downtime",level:4},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}];function h(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",pre:"pre",ul:"ul",...(0,i.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"adr-015-partial-set-security",children:"ADR 015: Partial Set Security"}),"\n",(0,n.jsx)(t.h2,{id:"changelog",children:"Changelog"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"2024-01-22: Proposed, first draft of ADR."}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"status",children:"Status"}),"\n",(0,n.jsx)(t.p,{children:"Proposed"}),"\n",(0,n.jsx)(t.h2,{id:"context",children:"Context"}),"\n",(0,n.jsxs)(t.p,{children:["Currently, in ",(0,n.jsx)(t.em,{children:"Replicated Security"}),", the entire validator set of the provider chain is used to secure consumer chains. There are at least three concerns with this approach.\nFirst, a large number of validators might be forced to validate consumer chains they are not interested in securing.\nSecond, it is costly for small validators to secure additional chains. This concern is only partially addressed through ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-009-soft-opt-out.md",children:"soft opt-out"})," that allows small validators to opt out from validating consumer chains.\nThird and for the above reasons, it is challenging for a new consumer chain to join Replicated Security."]}),"\n",(0,n.jsxs)(t.p,{children:["As a solution, we present ",(0,n.jsx)(t.em,{children:"Partial Set Security"})," (PSS). As the name suggests, PSS allows for every consumer chain to be secured by only a subset of the provider validator set.\nIn what follows we propose the exact steps we need to take to implement PSS. This is a first iteration of PSS, and therefore we present the most minimal solution that make PSS possible."]}),"\n",(0,n.jsx)(t.h2,{id:"decision",children:"Decision"}),"\n",(0,n.jsxs)(t.p,{children:["In Replicated Security, all the provider validators have to secure every consumer chain (with the exception of those validators allowed to opt out through the ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-009-soft-opt-out.md",children:"soft opt-out"})," feature)."]}),"\n",(0,n.jsxs)(t.p,{children:["In PSS, we allow validators to opt in and out of validating any given consumer chain.\nThis has one exception: we introduce a parameter ",(0,n.jsx)(t.code,{children:"N"})," for each consumer chain and require that the validators in top ",(0,n.jsx)(t.code,{children:"N%"})," of the provider's voting power have to secure the consumer chain.\nValidators outside of the top ",(0,n.jsx)(t.code,{children:"N%"})," can dynamically opt in if they want to validate on the consumer chain."]}),"\n",(0,n.jsxs)(t.p,{children:["For example, if a consumer chain has ",(0,n.jsx)(t.code,{children:"N = 95%"}),", then it ultimately receives the same security it receives today with Replicated Security (with a default ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-009-soft-opt-out.md",children:"SoftOptOutThreshold"})," of 5%).\nOn the other hand, if a consumer chain has ",(0,n.jsx)(t.code,{children:"N = 0%"}),", then no validator is forced to validate the chain, but validators can opt in to do so instead."]}),"\n",(0,n.jsxs)(t.p,{children:["For the remainder of this ADR, we call a consumer chain ",(0,n.jsx)(t.em,{children:"Top N"})," if it has joined as a Top N chain with ",(0,n.jsx)(t.code,{children:"N > 0"})," and ",(0,n.jsx)(t.em,{children:"Opt In"})," chain otherwise. An Opt In consumer chain is secured only by the validators that have opted in to secure that chain."]}),"\n",(0,n.jsxs)(t.p,{children:["We intend to implement PSS using a feature branch off ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/tree/v4.0.0",children:"v4.0.0 interchain security"}),"."]}),"\n",(0,n.jsx)(t.h3,{id:"how-do-consumer-chains-join",children:"How do consumer chains join?"}),"\n",(0,n.jsxs)(t.p,{children:["As a simplification and to avoid ",(0,n.jsx)(t.a,{href:"https://forum.cosmos.network/t/pss-permissionless-vs-premissioned-lite-opt-in-consumer-chains/12984/17",children:"chain id squatting"}),", a consumer chain can only join PSS through a governance proposal and not in a permissionless way."]}),"\n",(0,n.jsx)(t.p,{children:'However, this proposal type will be modified so that it requires a lower quorum percentage than normal proposal, and every validator who voted "YES" on the proposal will form the consumer chain\'s initial validator set.'}),"\n",(0,n.jsxs)(t.p,{children:["Consumer chains join PSS the same way chains now join Replicated Security, namely through a ",(0,n.jsx)(t.code,{children:"ConsumerAdditionProposal"})," proposal.\nWe extend ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/proto/interchain_security/ccv/provider/v1/provider.proto#L27",children:(0,n.jsx)(t.code,{children:"ConsumerAdditionProposal"})})," with one optional field:"]}),"\n",(0,n.jsxs)(t.p,{children:[(0,n.jsx)(t.code,{children:"uint32 top_N"}),": Corresponds to the percentage of validators that join under the Top N case.\nFor example, ",(0,n.jsx)(t.code,{children:"53"})," corresponds to a Top 53% chain, meaning that the top ",(0,n.jsx)(t.code,{children:"53%"})," provider validators have to validate the proposed consumer chain.\n",(0,n.jsx)(t.code,{children:"top_N"})," can be ",(0,n.jsx)(t.code,{children:"0"})," or include any value in ",(0,n.jsx)(t.code,{children:"[50, 100]"}),". A chain can join with ",(0,n.jsx)(t.code,{children:"top_N == 0"})," as an Opt In, or with ",(0,n.jsx)(t.code,{children:"top_N \u2208 [50, 100]"})," as a Top N chain."]}),"\n",(0,n.jsxs)(t.p,{children:["In case of a Top N chain, we restrict the possible values of ",(0,n.jsx)(t.code,{children:"top_N"})," from ",(0,n.jsx)(t.code,{children:"(0, 100]"})," to ",(0,n.jsx)(t.code,{children:"[50, 100]"}),".\nBy having ",(0,n.jsx)(t.code,{children:"top_N >= 50"})," we can guarantee that we cannot have a successful attack, assuming that at most ",(0,n.jsx)(t.code,{children:"1/3"})," of provider validators can be malicious.\nThis is because, a Top N chain with ",(0,n.jsx)(t.code,{children:"N >= 50%"})," would have at least ",(0,n.jsx)(t.code,{children:"1/3"})," honest validators, which is sufficient to stop attacks.\nAdditionally, by having ",(0,n.jsx)(t.code,{children:"N >= 50%"})," (and hence ",(0,n.jsx)(t.code,{children:"N > (VetoThreshold = 33.4%)"}),") we enable the top N validators to ",(0,n.jsx)(t.code,{children:"Veto"})," any ",(0,n.jsx)(t.code,{children:"ConsumerAdditionProposal"})," for consumer chains they do not want to validate."]}),"\n",(0,n.jsxs)(t.p,{children:["If a proposal has the ",(0,n.jsx)(t.code,{children:"top_N"})," argument wrongly set, it should get rejected in [ValidateBasic] (",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/types/proposal.go#L86",children:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/types/proposal.go#L86"}),")."]}),"\n",(0,n.jsxs)(t.p,{children:["In the code, we distinguish whether a chain is ",(0,n.jsx)(t.em,{children:"Top N"})," or ",(0,n.jsx)(t.em,{children:"Opt In"})," by checking whether ",(0,n.jsx)(t.code,{children:"top_N"})," is zero or not."]}),"\n",(0,n.jsxs)(t.p,{children:["In a future version of PSS, we intend to introduce a ",(0,n.jsx)(t.code,{children:"ConsumerModificationProposal"})," so that we can modify the parameters of a consumer chain, e.g, a chain that is ",(0,n.jsx)(t.em,{children:"Opt In"})," to become ",(0,n.jsx)(t.em,{children:"Top N"}),", etc."]}),"\n",(0,n.jsx)(t.h4,{id:"state--query",children:"State & Query"}),"\n",(0,n.jsxs)(t.p,{children:["We augment the provider module\u2019s state to keep track of the ",(0,n.jsx)(t.code,{children:"top_N"})," value for each consumer chain. The key to store this information would be:"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{children:"topNBytePrefix | len(chainID) | chainID\n"})}),"\n",(0,n.jsxs)(t.p,{children:["To create the above key, we can use ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/types/keys.go#L418",children:(0,n.jsx)(t.code,{children:"ChainIdWithLenKey"})}),"."]}),"\n",(0,n.jsxs)(t.p,{children:["Then in the ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/keeper/keeper.go",children:"keeper"})," we introduce methods as follows:"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-golang",children:"func (k Keeper) SetTopN(ctx sdk.Context, chainID string, topN uint32)\nfunc (k Keeper) IsTopN(ctx sdk.Context, chainID string) bool\nfunc (k Keeper) IsOptIn(ctx sdk.Context, chainID string) bool\n\n// returns the N if Top N chain, otherwise an error\nfunc (k Keeper) GetTopN(ctx sdk.Context, chainID string) (uint32, error)\n"})}),"\n",(0,n.jsxs)(t.p,{children:["We also extend the ",(0,n.jsx)(t.code,{children:"interchain-security-pd query provider list-consumer-chains"}),' query to return information on whether a consumer chain is an Opt In or a Top N chain and with what N.\nThis way, block explorers can present informative messages such as "This chain is secured by N% of the provider chain" for consumer chains.']}),"\n",(0,n.jsx)(t.h3,{id:"how-do-validators-opt-in",children:"How do validators opt in?"}),"\n",(0,n.jsxs)(t.p,{children:["A validator can opt in by sending a new type of message that we introduce in ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/proto/interchain_security/ccv/provider/v1/tx.proto#L1",children:"tx.proto"}),"."]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-protobuf",children:"message MsgOptIn {\n // the chain id of the consumer chain to opt in to\n string chainID = 1;\n // the provider address of the validator\n string providerAddr = 2;\n // (optional) the consensus public key to use on the consumer\n optional string consumerKey = 3;\n}\n"})}),"\n",(0,n.jsxs)(t.p,{children:["Note that in a Top N consumer chain, the top ",(0,n.jsx)(t.code,{children:"N%"})," provider validators have to validate the consumer chain.\nNevertheless, validators in the bottom ",(0,n.jsx)(t.code,{children:"(100 - N)%"})," can opt in to validate as well.\nProvider validators that belong or enter the top ",(0,n.jsx)(t.code,{children:"N%"})," validators are ",(0,n.jsx)(t.em,{children:"automatically"})," opted in to validate a Top N consumer chain.\nThis means that if a validator ",(0,n.jsx)(t.code,{children:"V"})," belongs to the top ",(0,n.jsx)(t.code,{children:"N%"})," validators but later falls (e.g., due to undelegations) to the bottom ",(0,n.jsx)(t.code,{children:"(100 - N)%"}),", ",(0,n.jsx)(t.code,{children:"V"})," is still considered opted in and has to validate unless ",(0,n.jsx)(t.code,{children:"V"})," sends a ",(0,n.jsx)(t.code,{children:"MsgOptOut"})," message (see below).\nBy automatically opting in validators when they enter the top ",(0,n.jsx)(t.code,{children:"N%"})," validators and by forcing top ",(0,n.jsx)(t.code,{children:"N%"})," validators to explicitly opt out in case they fall to the ",(0,n.jsx)(t.code,{children:"(100 - N)%"})," bottom validators we simplify the design of PSS."]}),"\n",(0,n.jsxs)(t.p,{children:["Note that a validator can send a ",(0,n.jsx)(t.code,{children:"MsgOptIn"})," message even if the consumer chain is not yet running. To do this we reuse the ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/keeper/key_assignment.go#L644",children:(0,n.jsx)(t.code,{children:"IsConsumerProposedOrRegistered"})}),". If the ",(0,n.jsx)(t.code,{children:"chainID"})," does not exist, the ",(0,n.jsx)(t.code,{children:"MsgOptIn"})," should fail, as well as if the provider address does not exist."]}),"\n",(0,n.jsxs)(t.p,{children:["Optionally, a validator that opts in can provide a ",(0,n.jsx)(t.code,{children:"consumerKey"})," so that it assigns a different consumer key (from the provider) to the consumer chain.\nNaturally, a validator can always change the consumer key on a consumer chain by sending a ",(0,n.jsx)(t.code,{children:"MsgAssignConsumerKey"})," message at a later point in time, as is done in Replicated Security."]}),"\n",(0,n.jsx)(t.h4,{id:"state--query-1",children:"State & Query"}),"\n",(0,n.jsxs)(t.p,{children:["For each validator, we store a pair ",(0,n.jsx)(t.code,{children:"(blockHeight, isOptedIn)"})," that contains the block height the validator opted in and whether the validator is currently opted in or not, under the key:"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{children:"optedInBytePrefix | len(chainID) | chainID | addr\n"})}),"\n",(0,n.jsxs)(t.p,{children:["By using a prefix iterator on ",(0,n.jsx)(t.code,{children:"optedInBytePrefix | len(chainID) | chainID"})," we retrieve all the opted in validators."]}),"\n",(0,n.jsxs)(t.p,{children:["We introduce the following ",(0,n.jsx)(t.code,{children:"Keeper"})," methods."]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-golang",children:"// returns all the validators that have opted in on chain `chainID`\nfunc (k Keeper) GetOptedInValidators(ctx sdk.Context, chainID string) []Validators\n\nfunc (k Keeper) IsValidatorOptedIn(ctx sdk.Context, chainID string, val Validator) bool\n"})}),"\n",(0,n.jsx)(t.p,{children:"We introduce the following two queries:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-bash",children:"interchain-security-pd query provider optedInValidators $chainID\ninterchain-security-pd query provider hasToValidate $providerAddr\n"})}),"\n",(0,n.jsx)(t.p,{children:"One query to retrieve the validators that are opted in and hence the validators that need to validate the consumer chain and one query that given a validator's address returns all the chains this validator has to validate."}),"\n",(0,n.jsx)(t.h4,{id:"when-do-validators-opt-in",children:"When do validators opt in?"}),"\n",(0,n.jsxs)(t.p,{children:["As described earlier, validators can manually opt in by sending a ",(0,n.jsx)(t.code,{children:"MsgOptIn"})," message.\nAdditionally, in a Top N chain, a validator is automatically opted in when it moves from the bottom ",(0,n.jsx)(t.code,{children:"(100 - N)%"})," to the top ",(0,n.jsx)(t.code,{children:"N%"})," validators."]}),"\n",(0,n.jsxs)(t.p,{children:["Lastly, validators can also opt in if they vote ",(0,n.jsx)(t.code,{children:"Yes"})," during the ",(0,n.jsx)(t.code,{children:"ConsumerAdditionProposal"})," that introduces a consumer chain.\nThis simplifies validators operations because they do not have to send an additional message to opt in."]}),"\n",(0,n.jsxs)(t.p,{children:["Because the ",(0,n.jsx)(t.code,{children:"Tally"})," method ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.7/x/gov/keeper/tally.go#L71",children:"deletes the votes"})," after reading them, we cannot check the votes of the validators after the votes have been tallied.\nTo circumvent this, we introduce a hook for ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.7/x/gov/keeper/vote.go#L35",children:(0,n.jsx)(t.code,{children:"AfterProposalVote"})})," and keep track of all the votes cast by a validator.\nIf a validator casts more than one vote, we only consider the latest vote.\nFinally, we only consider a validator has opted in if it casts a 100% ",(0,n.jsx)(t.code,{children:"Yes"})," vote in case of a ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-037-gov-split-vote.md",children:"weighted vote"}),"."]}),"\n",(0,n.jsx)(t.h3,{id:"how-do-validators-opt-out",children:"How do validators opt out?"}),"\n",(0,n.jsx)(t.p,{children:"Validators that have opted in on a chain can opt out by sending the following message:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-protobuf",children:"message MsgOptOut {\n // the chain id of the consumer chain to opt out from\n string chainID = 1;\n // the provider address of the validator\n string providerAddr = 2;\n}\n"})}),"\n",(0,n.jsxs)(t.p,{children:["Validators can only opt out after a consumer chain has started and hence the above message returns an error if the chain with ",(0,n.jsx)(t.code,{children:"chainID"})," is not running.\nAdditionally, a validator that belongs to the top ",(0,n.jsx)(t.code,{children:"N%"})," validators cannot opt out from a Top N chain and hence a ",(0,n.jsx)(t.code,{children:"MsgOptOut"})," would error in such a case."]}),"\n",(0,n.jsx)(t.h4,{id:"state--query-2",children:"State & Query"}),"\n",(0,n.jsx)(t.p,{children:"We also update the state of the opted-in validators when a validator has opted out by removing the opted-out validator."}),"\n",(0,n.jsxs)(t.p,{children:["Note that only opted-in validators can be punished for downtime on a consumer chain.\nFor this, we use historical info of all the validators that have opted in; We can examine the ",(0,n.jsx)(t.code,{children:"blockHeight"})," stored under the key ",(0,n.jsx)(t.code,{children:"optedInBytePrefix | len(chainID) | chainID | addr"})," to see if a validator was opted in.\nThis way we can jail validators for downtime knowing that indeed the validators have opted in at some point in the past.\nOtherwise, we can think of a scenario where a validator ",(0,n.jsx)(t.code,{children:"V"})," is down for a period of time, but before ",(0,n.jsx)(t.code,{children:"V"})," gets punished for downtime, validator ",(0,n.jsx)(t.code,{children:"V"})," opts out, and then we do not know whether ",(0,n.jsx)(t.code,{children:"V"})," should be punished or not."]}),"\n",(0,n.jsx)(t.h3,{id:"when-does-a-consumer-chain-start",children:"When does a consumer chain start?"}),"\n",(0,n.jsxs)(t.p,{children:["A Top N consumer chain always starts at the specified date (",(0,n.jsx)(t.code,{children:"spawn_time"}),") if the ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/proto/interchain_security/ccv/provider/v1/provider.proto#L27",children:(0,n.jsx)(t.code,{children:"ConsumerAdditionProposal"})})," has passed.\nAn Opt In consumer chain only starts if at least one validator has opted in. We check this in ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/keeper/proposal.go#L357",children:"BeginBlockInit"}),":"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-golang",children:'func (k Keeper) BeginBlockInit(ctx sdk.Context) {\n propsToExecute := k.GetConsumerAdditionPropsToExecute(ctx)\n\n for _, prop := range propsToExecute {\n chainID := prop.ChainId\n if !k.IsTopN(ctx, chainID) && len(k.GetOptedInValidators(ctx, chainID)) == 0 {\n // drop the proposal\n ctx.Logger().Info("could not start chain because no validator has opted in")\n continue\n } \n ...\n'})}),"\n",(0,n.jsx)(t.h3,{id:"how-do-we-send-the-partial-validator-sets-to-the-consumer-chains",children:"How do we send the partial validator sets to the consumer chains?"}),"\n",(0,n.jsxs)(t.p,{children:["A consumer chain should only be validated by opted in validators.\nWe introduce logic to do this when we ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/keeper/relay.go#L213",children:"queue"})," the ",(0,n.jsx)(t.code,{children:"VSCPacket"}),"s.\nThe logic behind this, is not as straightforward as it seems because CometBFT does not receive the validator set that has to validate a chain, but rather a delta of ",(0,n.jsx)(t.a,{href:"https://docs.cometbft.com/v0.37/spec/abci/abci++_methods#validatorupdate",children:"validator updates"}),".\nFor example, to remove an opted-out validator from a consumer chain, we have to send a validator update with a ",(0,n.jsx)(t.code,{children:"power"})," of ",(0,n.jsx)(t.code,{children:"0"}),", similarly to what is done in the ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/keeper/key_assignment.go#L525",children:"assignment of consumer keys"}),".\nWe intend to update this ADR at a later stage on how exactly we intend to implement this logic."]}),"\n",(0,n.jsx)(t.h3,{id:"how-do-we-distribute-rewards",children:"How do we distribute rewards?"}),"\n",(0,n.jsxs)(t.p,{children:["Currently, rewards are distributed as follows: The consumer ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/consumer/keeper/distribution.go#L148",children:"periodically sends rewards"})," on the provider ",(0,n.jsx)(t.code,{children:"ConsumerRewardsPool"})," address.\nThe provider then ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/keeper/distribution.go#L77",children:"transfers those rewards to the fee collector address"})," and those transferred rewards are distributed to validators and delegators."]}),"\n",(0,n.jsx)(t.p,{children:"In PSS, we distribute rewards only to validators that actually validate the consumer chain.\nTo do this, we have a pool associated with each consumer chain and consumers IBC transfer the rewards to this pool.\nWe then extract the rewards from each consumer pool and distribute them to the opted in validators."}),"\n",(0,n.jsx)(t.p,{children:"Note that we only distribute rewards to validators that have been opted in for some time (e.g., 10000 blocks) to avoid cases where validators opt in just to receive rewards and then opt out immediately afterward."}),"\n",(0,n.jsx)(t.h3,{id:"misbehaviour",children:"Misbehaviour"}),"\n",(0,n.jsx)(t.h4,{id:"fraud-votes",children:"Fraud votes"}),"\n",(0,n.jsxs)(t.p,{children:["In an Opt In chain, a set of validators might attempt to perform an attack. To deter such potential attacks, PSS allows for the use of fraud votes.\nA ",(0,n.jsx)(t.em,{children:"fraud vote"})," is a governance proposal that enables the slashing of validators that performed an attack.\nDue to their inherent complexity, we intend to introduce fraud votes in a different ADR and at a future iteration of PSS."]}),"\n",(0,n.jsx)(t.h4,{id:"double-signing",children:"Double signing"}),"\n",(0,n.jsx)(t.p,{children:"We do not change the way slashing for double signing and light client attacks functions.\nIf a validator misbehaves on a consumer, then we slash that validator on the provider."}),"\n",(0,n.jsx)(t.h4,{id:"downtime",children:"Downtime"}),"\n",(0,n.jsx)(t.p,{children:"We do not change the way downtime jailing functions.\nIf a validator is down on a consumer chain for an adequate amount of time, we jail this validator on the provider but only if the validator was opted in on this consumer chain in the recent past."}),"\n",(0,n.jsx)(t.h2,{id:"consequences",children:"Consequences"}),"\n",(0,n.jsx)(t.h3,{id:"positive",children:"Positive"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsx)(t.p,{children:"Easier for new consumer chains to consume the provider's chain economic security because proposals are more likely to pass if not everyone is forced to validate."}),"\n"]}),"\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsx)(t.p,{children:"Smaller validators are not forced to validate chains anymore if they do not want to."}),"\n"]}),"\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsx)(t.p,{children:"We can deprecate the soft opt-out implementation."}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(t.h3,{id:"negative",children:"Negative"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["A consumer chain does not receive the same economic security as with Replicated Security (assuming the value of ",(0,n.jsx)(t.code,{children:"SoftOptOutThreshold"})," is ",(0,n.jsx)(t.code,{children:"5%"}),"), unless it is a Top N chain with ",(0,n.jsx)(t.code,{children:"N >= 95%"}),"."]}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"references",children:"References"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:(0,n.jsx)(t.a,{href:"https://forum.cosmos.network/t/pss-permissionless-vs-premissioned-lite-opt-in-consumer-chains/12984",children:"PSS: Permissionless vs premissioned-lite opt-in consumer chains"})}),"\n",(0,n.jsx)(t.li,{children:(0,n.jsx)(t.a,{href:"https://forum.cosmos.network/t/chips-discussion-phase-partial-set-security-updated/11775",children:"CHIPs discussion phase: Partial Set Security (updated)"})}),"\n",(0,n.jsx)(t.li,{children:(0,n.jsx)(t.a,{href:"https://forum.cosmos.network/t/pss-exclusive-vs-inclusive-top-n/13058",children:"PSS: Exclusive vs Inclusive Top-N"})}),"\n",(0,n.jsx)(t.li,{children:(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/pull/1518",children:"Initial PSS ADR and notes #1518"})}),"\n",(0,n.jsx)(t.li,{children:(0,n.jsx)(t.a,{href:"https://informal.systems/blog/replicated-vs-mesh-security",children:"Replicated vs. Mesh Security"})}),"\n"]})]})}function l(e={}){const{wrapper:t}={...(0,i.a)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(h,{...e})}):h(e)}},1151:(e,t,o)=>{o.d(t,{Z:()=>r,a:()=>a});var n=o(7294);const i={},s=n.createContext(i);function a(e){const t=n.useContext(s);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),n.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c2cfb320.3bf8a73b.js b/assets/js/c2cfb320.3bf8a73b.js new file mode 100644 index 0000000000..a1efd25076 --- /dev/null +++ b/assets/js/c2cfb320.3bf8a73b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1429],{6639:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>l,frontMatter:()=>s,metadata:()=>r,toc:()=>c});var i=a(5893),t=a(1151);const s={sidebar_position:4},o="Validator Instructions for Changeover Procedure",r={id:"validators/changeover-procedure",title:"Validator Instructions for Changeover Procedure",description:"More details available in Changeover Procedure documentation.",source:"@site/docs/validators/changeover-procedure.md",sourceDirName:"validators",slug:"/validators/changeover-procedure",permalink:"/interchain-security/validators/changeover-procedure",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Consumer chain validator rewards",permalink:"/interchain-security/validators/withdraw_rewards"},next:{title:"Joining Neutron",permalink:"/interchain-security/validators/joining-neutron"}},d={},c=[{value:"Timeline",id:"timeline",level:2},{value:"1. <code>ConsumerAdditionProposal</code> on provider chain",id:"1-consumeradditionproposal-on-provider-chain",level:3},{value:"2. <code>SoftwareUpgradeProposal</code> on the standalone/consumer chain",id:"2-softwareupgradeproposal-on-the-standaloneconsumer-chain",level:3},{value:"3. Assigning a consumer key",id:"3-assigning-a-consumer-key",level:3},{value:"4. Perform the software upgrade on standalone chain",id:"4-perform-the-software-upgrade-on-standalone-chain",level:3},{value:"FAQ",id:"faq",level:2},{value:"Can I reuse the same validator key for the <code>consumer</code> chain that I am already using on the <code>standalone</code> chain? Will I need to perform a <code>AssignConsumerKey</code> tx with this key before spawn time?",id:"can-i-reuse-the-same-validator-key-for-the-consumer-chain-that-i-am-already-using-on-the-standalone-chain-will-i-need-to-perform-a-assignconsumerkey-tx-with-this-key-before-spawn-time",level:3},{value:"Can I continue using the same node that was validating the <code>standalone</code> chain?",id:"can-i-continue-using-the-same-node-that-was-validating-the-standalone-chain",level:3},{value:"Can I set up a new node to validate the <code>standalone/consumer</code> chain after it transitions to Interchain Security?",id:"can-i-set-up-a-new-node-to-validate-the-standaloneconsumer-chain-after-it-transitions-to-interchain-security",level:3},{value:"What happens to the <code>standalone</code> validator set after it transitions to Interchain Security?",id:"what-happens-to-the-standalone-validator-set-after-it-transitions-to-interchain-security",level:3},{value:"Credits",id:"credits",level:2}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"validator-instructions-for-changeover-procedure",children:"Validator Instructions for Changeover Procedure"}),"\n",(0,i.jsxs)(n.p,{children:["More details available in ",(0,i.jsx)(n.a,{href:"/interchain-security/consumer-development/changeover-procedure",children:"Changeover Procedure documentation"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"A major difference between launching a new consumer chain vs. onboarding a standalone chain to ICS is that there is no consumer genesis available for the standalone chain. Since a standalone chain already exists, its state must be preserved once it transitions to being a consumer chain."}),"\n",(0,i.jsx)(n.h2,{id:"timeline",children:"Timeline"}),"\n",(0,i.jsxs)(n.p,{children:["Upgrading standalone chains can be best visualised using a timeline, such as the one available ",(0,i.jsx)(n.a,{href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt",children:"Excalidraw graphic by Stride"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"There is some flexibility with regards to how the changeover procedure is executed, so please make sure to follow the guides provided by the team doing the changeover."}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Standalone to consumer transition timeline",src:a(6038).Z+"",width:"5307",height:"2157"})}),"\n",(0,i.jsxs)(n.h3,{id:"1-consumeradditionproposal-on-provider-chain",children:["1. ",(0,i.jsx)(n.code,{children:"ConsumerAdditionProposal"})," on provider chain"]}),"\n",(0,i.jsxs)(n.p,{children:["This step will add the standalone chain to the list of consumer chains secured by the provider.\nThis step dictates the ",(0,i.jsx)(n.code,{children:"spawn_time"}),". After ",(0,i.jsx)(n.code,{children:"spawn_time"})," the CCV state (initial validator set of the provider) will be available to the consumer."]}),"\n",(0,i.jsx)(n.p,{children:"To obtain it from the provider use:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad q provider consumer-genesis stride-1 -o json > ccv-state.json\njq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' genesis.json ccv-state.json > ccv.json\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Transformation of the exported consumer genesis state to the target version of the consumer might be needed in case the provider and consumer formats are incompatible.\nRefer to the compatibility notes ",(0,i.jsx)(n.a,{href:"../../../RELEASES.md#backwards-compatibility",children:"here"})," to check if data transformation is needed for your case.\nInstructions on how to transform the exported CCV genesis state (",(0,i.jsx)(n.code,{children:"ccv-state.json"})," in the example above) to the required target version can be found ",(0,i.jsx)(n.a,{href:"/interchain-security/consumer-development/consumer-genesis-transformation",children:"here"})]}),"\n",(0,i.jsxs)(n.h3,{id:"2-softwareupgradeproposal-on-the-standaloneconsumer-chain",children:["2. ",(0,i.jsx)(n.code,{children:"SoftwareUpgradeProposal"})," on the standalone/consumer chain"]}),"\n",(0,i.jsx)(n.p,{children:"This upgrade proposal will introduce ICS to the standalone chain, making it a consumer."}),"\n",(0,i.jsx)(n.h3,{id:"3-assigning-a-consumer-key",children:"3. Assigning a consumer key"}),"\n",(0,i.jsxs)(n.p,{children:["After ",(0,i.jsx)(n.code,{children:"spawn_time"}),", make sure to assign a consumer key if you intend to use one."]}),"\n",(0,i.jsxs)(n.p,{children:["Instructions are available ",(0,i.jsx)(n.a,{href:"/interchain-security/features/key-assignment",children:"here"})]}),"\n",(0,i.jsx)(n.h3,{id:"4-perform-the-software-upgrade-on-standalone-chain",children:"4. Perform the software upgrade on standalone chain"}),"\n",(0,i.jsx)(n.p,{children:"Please use instructions provided by the standalone chain team and make sure to reach out if you are facing issues.\nThe upgrade preparation depends on your setup, so please make sure you prepare ahead of time."}),"\n",(0,i.jsxs)(n.admonition,{type:"danger",children:[(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"ccv.json"})," from step 1. must be made available on the machine running the standalone/consumer chain at standalone chain ",(0,i.jsx)(n.code,{children:"upgrade_height"}),". This file contains the initial validator set and parameters required for normal ICS operation."]}),(0,i.jsxs)(n.p,{children:["Usually, the file is placed in ",(0,i.jsx)(n.code,{children:"$NODE_HOME/config"})," but this is not a strict requirement. The exact details are available in the upgrade code of the standalone/consumer chain."]})]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Performing this upgrade will transition the standalone chain to be a consumer chain."})}),"\n",(0,i.jsxs)(n.p,{children:['After 3 blocks, the standalone chain will stop using the "old" validator set and begin using the ',(0,i.jsx)(n.code,{children:"provider"})," validator set."]}),"\n",(0,i.jsx)(n.h2,{id:"faq",children:"FAQ"}),"\n",(0,i.jsxs)(n.h3,{id:"can-i-reuse-the-same-validator-key-for-the-consumer-chain-that-i-am-already-using-on-the-standalone-chain-will-i-need-to-perform-a-assignconsumerkey-tx-with-this-key-before-spawn-time",children:["Can I reuse the same validator key for the ",(0,i.jsx)(n.code,{children:"consumer"})," chain that I am already using on the ",(0,i.jsx)(n.code,{children:"standalone"})," chain? Will I need to perform a ",(0,i.jsx)(n.code,{children:"AssignConsumerKey"})," tx with this key before spawn time?"]}),"\n",(0,i.jsxs)(n.p,{children:["Validators must either assign a key or use the same key as on the ",(0,i.jsx)(n.code,{children:"provider"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["If you are validating both the ",(0,i.jsx)(n.code,{children:"standalone"})," and the ",(0,i.jsx)(n.code,{children:"provider"}),", you ",(0,i.jsx)(n.strong,{children:"can"})," use your current ",(0,i.jsx)(n.code,{children:"standalone"})," key with some caveats:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["you must submit an ",(0,i.jsx)(n.code,{children:"AssignConsumerKey"})," tx with your current ",(0,i.jsx)(n.code,{children:"standalone"})," validator key"]}),"\n",(0,i.jsxs)(n.li,{children:["it is best to submit ",(0,i.jsx)(n.code,{children:"AssignConsumerKey"})," tx before ",(0,i.jsx)(n.code,{children:"spawn_time"})]}),"\n",(0,i.jsxs)(n.li,{children:["if you do not submit the Tx, it is assumed that you will be re-using your ",(0,i.jsx)(n.code,{children:"provider"})," key to validate the ",(0,i.jsx)(n.code,{children:"standalone/consumer"})," chain"]}),"\n"]}),"\n",(0,i.jsxs)(n.h3,{id:"can-i-continue-using-the-same-node-that-was-validating-the-standalone-chain",children:["Can I continue using the same node that was validating the ",(0,i.jsx)(n.code,{children:"standalone"})," chain?"]}),"\n",(0,i.jsx)(n.p,{children:"Yes."}),"\n",(0,i.jsx)(n.p,{children:"Please assign your consensus key as stated above."}),"\n",(0,i.jsxs)(n.h3,{id:"can-i-set-up-a-new-node-to-validate-the-standaloneconsumer-chain-after-it-transitions-to-interchain-security",children:["Can I set up a new node to validate the ",(0,i.jsx)(n.code,{children:"standalone/consumer"})," chain after it transitions to Interchain Security?"]}),"\n",(0,i.jsx)(n.p,{children:"Yes."}),"\n",(0,i.jsxs)(n.p,{children:["If you are planning to do this please make sure that the node is synced with ",(0,i.jsx)(n.code,{children:"standalone"})," network and to submit ",(0,i.jsx)(n.code,{children:"AssignConsumerKey"})," tx before ",(0,i.jsx)(n.code,{children:"spawn_time"}),"."]}),"\n",(0,i.jsxs)(n.h3,{id:"what-happens-to-the-standalone-validator-set-after-it-transitions-to-interchain-security",children:["What happens to the ",(0,i.jsx)(n.code,{children:"standalone"})," validator set after it transitions to Interchain Security?"]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"standalone"})," chain validators will stop being validators after the first 3 blocks are created while using Interchain Security. The ",(0,i.jsx)(n.code,{children:"standalone"})," validators will become ",(0,i.jsx)(n.strong,{children:"governors"})," and still can receive delegations if the ",(0,i.jsx)(n.code,{children:"consumer"})," chain is using the ",(0,i.jsx)(n.code,{children:"consumer-democracy"})," module."]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Governors DO NOT VALIDATE BLOCKS"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"Instead, they can participate in the governance process and take on other chain-specific roles."}),"\n",(0,i.jsx)(n.h2,{id:"credits",children:"Credits"}),"\n",(0,i.jsx)(n.p,{children:"Thank you Stride team for providing detailed instructions about the changeover procedure."})]})}function l(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},6038:(e,n,a)=>{a.d(n,{Z:()=>i});const i=a.p+"assets/images/ics_changeover_timeline_stride-9bcad1834fef24a0fea7f2c80c9ccd71.png"},1151:(e,n,a)=>{a.d(n,{Z:()=>r,a:()=>o});var i=a(7294);const t={},s=i.createContext(t);function o(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c3827980.f880929a.js b/assets/js/c3827980.f880929a.js new file mode 100644 index 0000000000..3f5c7317da --- /dev/null +++ b/assets/js/c3827980.f880929a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5032],{5082:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>m,frontMatter:()=>s,metadata:()=>i,toc:()=>h});var o=t(5893),a=t(1151);const s={sidebar_position:2},r="Consumer Chain Governance",i={id:"consumer-development/consumer-chain-governance",title:"Consumer Chain Governance",description:'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.',source:"@site/versioned_docs/version-v5.0.0/consumer-development/consumer-chain-governance.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-chain-governance",permalink:"/interchain-security/v5.0.0/consumer-development/consumer-chain-governance",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/v5.0.0/consumer-development/app-integration"},next:{title:"Onboarding Checklist",permalink:"/interchain-security/v5.0.0/consumer-development/onboarding"}},c={},h=[{value:"Democracy module",id:"democracy-module",level:2},{value:"CosmWasm",id:"cosmwasm",level:2},{value:"The Whitelist",id:"the-whitelist",level:2}];function l(e){const n={a:"a",h1:"h1",h2:"h2",p:"p",...(0,a.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"consumer-chain-governance",children:"Consumer Chain Governance"}),"\n",(0,o.jsx)(n.p,{children:'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.'}),"\n",(0,o.jsx)(n.h2,{id:"democracy-module",children:"Democracy module"}),"\n",(0,o.jsx)(n.p,{children:"The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy."}),"\n",(0,o.jsx)(n.p,{children:"Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus."}),"\n",(0,o.jsxs)(n.p,{children:["For an example, see the ",(0,o.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy",children:"Democracy Consumer"})]}),"\n",(0,o.jsx)(n.h2,{id:"cosmwasm",children:"CosmWasm"}),"\n",(0,o.jsx)(n.p,{children:"There are several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain."}),"\n",(0,o.jsxs)(n.p,{children:["For an example, see ",(0,o.jsx)(n.a,{href:"https://github.com/neutron-org/neutron/",children:"Neutron"}),"."]}),"\n",(0,o.jsx)(n.h2,{id:"the-whitelist",children:"The Whitelist"}),"\n",(0,o.jsxs)(n.p,{children:["Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see ",(0,o.jsx)(n.a,{href:"https://github.com/neutron-org/neutron/blob/main/app/proposals_allowlisting.go",children:"Neutron's"})," whitelist."]})]})}function m(e={}){const{wrapper:n}={...(0,a.a)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>i,a:()=>r});var o=t(7294);const a={},s=o.createContext(a);function r(e){const n=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:r(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c551d695.fa70b161.js b/assets/js/c551d695.fa70b161.js new file mode 100644 index 0000000000..6fbbf74312 --- /dev/null +++ b/assets/js/c551d695.fa70b161.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4635],{5414:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>a,metadata:()=>t,toc:()=>d});var i=s(5893),r=s(1151);const a={sidebar_position:1},o="Key Assignment",t={id:"features/key-assignment",title:"Key Assignment",description:"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.",source:"@site/versioned_docs/version-v4.2.0-docs/features/key-assignment.md",sourceDirName:"features",slug:"/features/key-assignment",permalink:"/interchain-security/v4.2.0/features/key-assignment",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Technical Specification",permalink:"/interchain-security/v4.2.0/introduction/technical-specification"},next:{title:"Reward Distribution",permalink:"/interchain-security/v4.2.0/features/reward-distribution"}},c={},d=[{value:"Rules",id:"rules",level:2},{value:"Adding a key",id:"adding-a-key",level:2},{value:"Changing a key",id:"changing-a-key",level:2},{value:"Removing a key",id:"removing-a-key",level:2},{value:"Querying proposed consumer chains",id:"querying-proposed-consumer-chains",level:2}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"key-assignment",children:"Key Assignment"}),"\n",(0,i.jsx)(n.p,{children:"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.\nThere are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains."}),"\n",(0,i.jsxs)(n.p,{children:["The feature is outlined in this ",(0,i.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-001-key-assignment",children:"ADR-001"})]}),"\n",(0,i.jsxs)(n.p,{children:["By sending an ",(0,i.jsx)(n.code,{children:"AssignConsumerKey"})," transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator."]}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsx)(n.p,{children:"Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity."})}),"\n",(0,i.jsx)(n.h2,{id:"rules",children:"Rules"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"a key can be assigned as soon as the consumer addition proposal is submitted to the provider"}),"\n",(0,i.jsx)(n.li,{children:"validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider"}),"\n",(0,i.jsx)(n.li,{children:"validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X"}),"\n",(0,i.jsx)(n.li,{children:"a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain"}),"\n"]}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsx)(n.p,{children:"Validators can use a different key for each consumer chain."})}),"\n",(0,i.jsx)(n.h2,{id:"adding-a-key",children:"Adding a key"}),"\n",(0,i.jsx)(n.p,{children:"First, create a new node on the consumer chain using the equivalent:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"consumerd init <moniker>\n"})}),"\n",(0,i.jsx)(n.p,{children:"Then query your node for the consensus key."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Then, make an ",(0,i.jsx)(n.code,{children:"assign-consensus-key"})," transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad tx provider assign-consensus-key <consumer-chain-id> '<pubkey>' --from <tx-signer> --home <home_dir> --gas 900000 -b sync -y -o json\n"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"consumer-chain-id"})," is the string identifier of the consumer chain, as assigned on the provider chain"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"consumer-pub-key"})," has the following format ",(0,i.jsx)(n.code,{children:'{"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}'})]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Check that the key was assigned correctly by querying the provider:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad query provider validator-consumer-key <consumer-chain-id> cosmosvalcons1e....3xsj3ayzf4uv6\n"})}),"\n",(0,i.jsxs)(n.p,{children:["You must use a ",(0,i.jsx)(n.code,{children:"valcons"})," address. You can obtain it by querying your node on the provider ",(0,i.jsx)(n.code,{children:"gaiad tendermint show-address"})]}),"\n",(0,i.jsx)(n.p,{children:"OR"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad query provider validator-provider-key <consumer-chain-id> consumervalcons1e....123asdnoaisdao\n"})}),"\n",(0,i.jsxs)(n.p,{children:["You must use a ",(0,i.jsx)(n.code,{children:"valcons"})," address. You can obtain it by querying your node on the consumer ",(0,i.jsx)(n.code,{children:"consumerd tendermint show-address"})]}),"\n",(0,i.jsx)(n.p,{children:"OR"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad query provider all-pairs-valconsensus-address <consumer-chain-id>\n"})}),"\n",(0,i.jsxs)(n.p,{children:["You just need to use the ",(0,i.jsx)(n.code,{children:"chainId"})," of consumer to query all pairs valconsensus address with ",(0,i.jsx)(n.code,{children:"consumer-pub-key"})," for each of pair"]}),"\n",(0,i.jsx)(n.h2,{id:"changing-a-key",children:"Changing a key"}),"\n",(0,i.jsx)(n.p,{children:"To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied"}),"\n",(0,i.jsx)(n.h2,{id:"removing-a-key",children:"Removing a key"}),"\n",(0,i.jsxs)(n.p,{children:["To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the ",(0,i.jsx)(n.code,{children:"Adding a key"})," section and using your provider consensus key."]}),"\n",(0,i.jsx)(n.admonition,{type:"warning",children:(0,i.jsxs)(n.p,{children:["Validators are strongly recommended to assign a separate key for each consumer chain\nand ",(0,i.jsx)(n.strong,{children:"not"})," reuse the provider key across consumer chains for security reasons."]})}),"\n",(0,i.jsx)(n.h2,{id:"querying-proposed-consumer-chains",children:"Querying proposed consumer chains"}),"\n",(0,i.jsx)(n.p,{children:"To query the consumer addition proposals that are in the voting period, you can use the following command on the provider:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad query provider list-proposed-consumer-chains\n"})}),"\n",(0,i.jsx)(n.p,{children:"This query is valuable for staying informed about when keys can be assigned to newly proposed consumer chains."})]})}function l(e={}){const{wrapper:n}={...(0,r.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},1151:(e,n,s)=>{s.d(n,{Z:()=>t,a:()=>o});var i=s(7294);const r={},a=i.createContext(r);function o(e){const n=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function t(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),i.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/caea946b.e5a1de44.js b/assets/js/caea946b.e5a1de44.js new file mode 100644 index 0000000000..1e88790507 --- /dev/null +++ b/assets/js/caea946b.e5a1de44.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3713],{5483:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>h,frontMatter:()=>t,metadata:()=>d,toc:()=>l});var i=s(5893),o=s(1151);const t={sidebar_position:2,title:"ADR Template"},r="ADR 004: Denom DOS fixes",d={id:"adrs/adr-004-denom-dos-fixes",title:"ADR Template",description:"Changelog",source:"@site/versioned_docs/version-v5.0.0/adrs/adr-004-denom-dos-fixes.md",sourceDirName:"adrs",slug:"/adrs/adr-004-denom-dos-fixes",permalink:"/interchain-security/v5.0.0/adrs/adr-004-denom-dos-fixes",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"ADR Template"},sidebar:"tutorialSidebar",previous:{title:"ADRs",permalink:"/interchain-security/v5.0.0/adrs/intro"},next:{title:"ADR Template",permalink:"/interchain-security/v5.0.0/adrs/adr-007-pause-unbonding-on-eqv-prop"}},a={},l=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Provider",id:"provider",level:3},{value:"Consumer",id:"consumer",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3}];function c(e){const n={h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,o.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"adr-004-denom-dos-fixes",children:"ADR 004: Denom DOS fixes"}),"\n",(0,i.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"5/9/2023: ADR created"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(n.p,{children:"Accepted"}),"\n",(0,i.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,i.jsx)(n.p,{children:"The provider and consumer modules are vulnerable to similar issues involving an attacker sending millions of denoms to certain addresses and causing the chain to halt. This ADR outlines both fixes since they are similar. Both fixes involve processing only denoms that are on a whitelist to avoid iterating over millions of junk denoms but have different requirements and are implemented in different ways."}),"\n",(0,i.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,i.jsx)(n.h3,{id:"provider",children:"Provider"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Put the distribution module's FeePoolAddress back on the blocklist so that it cannot receive funds from users."}),"\n",(0,i.jsx)(n.li,{children:"Create a new address called ConsumerRewardPool and unblock it, allowing funds to be sent to it."}),"\n",(0,i.jsx)(n.li,{children:"Create a set of strings in the store for allowed ConsumerRewardDenoms."}),"\n",(0,i.jsx)(n.li,{children:"Create an endpoint called RegisterConsumerRewardDenom which deducts a fee from the sender's account, sends it to the community pool and adds a string to the ConsumerRewardDenoms set."}),"\n",(0,i.jsx)(n.li,{children:"Create a parameter called ConsumerRewardDenomRegistrationFee which determines the fee which is charged to register a consumer reward denom in the step above."}),"\n",(0,i.jsxs)(n.li,{children:["Create a function called TransferRewardsToFeeCollector which gets the entire ConsumerRewardDenoms set from the store, iterates over it, and for each entry:","\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Gets the balance of this denom for the ConsumerRewardPool account"}),"\n",(0,i.jsx)(n.li,{children:"Sends the entire balance out to the FeePoolAddress using SendCoinsFromModuleToModule which is not affected by the blocklist."}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.li,{children:"Run TransferRewardsToFeeCollector in the endblock"}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Now, nobody can send millions of junk denoms to the FeePoolAddress because it is on the block list. If they send millions of junk denoms to the ConsumerRewardPool, this does not matter because all balances are not iterated over, only those which are in the ConsumerRewardDenoms set."}),"\n",(0,i.jsx)(n.p,{children:"We also add a new tx: register-consumer-reward-denom, and a new query: registered-consumer-reward-denoms"}),"\n",(0,i.jsx)(n.h3,{id:"consumer",children:"Consumer"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Create a new param RewardDenoms with a list of strings"}),"\n",(0,i.jsx)(n.li,{children:"Create a new param ProviderRewardDenoms with a list of strings"}),"\n",(0,i.jsx)(n.li,{children:"Create a function AllowedRewardDenoms which iterates over ProviderRewardDenoms and converts each denom to its ibc-prefixed denom using the provider chain's ibc channel information, then concatenates the RewardDenoms list and returns the combined list of allowed denoms."}),"\n",(0,i.jsx)(n.li,{children:"In SendRewardsToProvider, instead of iterating over the balances of all denoms in the ToSendToProvider address, iterate over AllowedRewardDenoms"}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Now, if somebody sends millions of junk denoms to ToSendToProvider, they will not be iterated over. Only the RewardDenoms and ProviderRewardDenoms will be iterated over. Since we do not require this feature to be permissionless on the consumer, the registration fee process is not needed."}),"\n",(0,i.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,i.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Denom DOS is no longer possible on either provider or consumer."}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Consumer chain teams must pay a fee to register a denom for distribution on the provider, and add some extra parameters in their genesis file."}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,o.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},1151:(e,n,s)=>{s.d(n,{Z:()=>d,a:()=>r});var i=s(7294);const o={},t=i.createContext(o);function r(e){const n=i.useContext(t);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:r(e.components),i.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/cf411473.69556536.js b/assets/js/cf411473.69556536.js new file mode 100644 index 0000000000..0e655c793b --- /dev/null +++ b/assets/js/cf411473.69556536.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3153],{511:(t,e,i)=>{i.r(e),i.d(e,{assets:()=>s,contentTitle:()=>r,default:()=>d,frontMatter:()=>o,metadata:()=>a,toc:()=>p});var n=i(5893),c=i(1151);const o={sidebar_position:4},r="Technical Specification",a={id:"introduction/technical-specification",title:"Technical Specification",description:"For a technical deep dive into the replicated security protocol, see the specification.",source:"@site/docs/introduction/technical-specification.md",sourceDirName:"introduction",slug:"/introduction/technical-specification",permalink:"/interchain-security/introduction/technical-specification",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Parameters",permalink:"/interchain-security/introduction/params"},next:{title:"Upgrading to ICS v5.0.0",permalink:"/interchain-security/upgrading/migrate_v4_v5"}},s={},p=[];function u(t){const e={a:"a",h1:"h1",p:"p",...(0,c.a)(),...t.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{id:"technical-specification",children:"Technical Specification"}),"\n",(0,n.jsxs)(e.p,{children:["For a technical deep dive into the replicated security protocol, see the ",(0,n.jsx)(e.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/README.md",children:"specification"}),"."]})]})}function d(t={}){const{wrapper:e}={...(0,c.a)(),...t.components};return e?(0,n.jsx)(e,{...t,children:(0,n.jsx)(u,{...t})}):u(t)}},1151:(t,e,i)=>{i.d(e,{Z:()=>a,a:()=>r});var n=i(7294);const c={},o=n.createContext(c);function r(t){const e=n.useContext(o);return n.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function a(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(c):t.components||c:r(t.components),n.createElement(o.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/d0088cb9.e41155f8.js b/assets/js/d0088cb9.e41155f8.js new file mode 100644 index 0000000000..ffefe64094 --- /dev/null +++ b/assets/js/d0088cb9.e41155f8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[709],{7015:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>h,contentTitle:()=>a,default:()=>l,frontMatter:()=>t,metadata:()=>r,toc:()=>d});var i=o(5893),s=o(1151);const t={sidebar_position:14,title:"Slashing on the provider for consumer equivocation"},a="ADR 013: Slashing on the provider for consumer equivocation",r={id:"adrs/adr-013-equivocation-slashing",title:"Slashing on the provider for consumer equivocation",description:"Changelog",source:"@site/versioned_docs/version-v5.0.0/adrs/adr-013-equivocation-slashing.md",sourceDirName:"adrs",slug:"/adrs/adr-013-equivocation-slashing",permalink:"/interchain-security/v5.0.0/adrs/adr-013-equivocation-slashing",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:14,frontMatter:{sidebar_position:14,title:"Slashing on the provider for consumer equivocation"},sidebar:"tutorialSidebar",previous:{title:"Separate Releasing",permalink:"/interchain-security/v5.0.0/adrs/adr-012-separate-releasing"},next:{title:"Epochs",permalink:"/interchain-security/v5.0.0/adrs/adr-014-epochs"}},h={},d=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Single-chain slashing",id:"single-chain-slashing",level:3},{value:"Slashing undelegations and redelegations",id:"slashing-undelegations-and-redelegations",level:4},{value:"Slashing delegations",id:"slashing-delegations",level:4},{value:"Old evidence",id:"old-evidence",level:4},{value:"Slashing for equivocation on the consumer",id:"slashing-for-equivocation-on-the-consumer",level:3},{value:"Proposed solution",id:"proposed-solution",level:2},{value:"Implementation",id:"implementation",level:3},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}];function c(e){const n={a:"a",blockquote:"blockquote",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"adr-013-slashing-on-the-provider-for-consumer-equivocation",children:"ADR 013: Slashing on the provider for consumer equivocation"}),"\n",(0,i.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"1st Sept. 2023: Initial draft"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(n.p,{children:"Accepted"}),"\n",(0,i.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,i.jsxs)(n.p,{children:["This ADR presents some approaches on how to slash on the provider chain validators that performed equivocations on consumer chains.\nCurrently, the provider chain can ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/1232",children:"receive and verify evidence of equivocation"}),", but it cannot slash the misbehaving validator."]}),"\n",(0,i.jsx)(n.p,{children:"In the remainder of this section, we explain how slashing is performed on a single chain and show why slashing on the provider for equivocation on the consumer is challenging."}),"\n",(0,i.jsxs)(n.p,{children:["Note that future versions of the Cosmos SDK, CometBFT, and ibc-go could modify the way we slash, etc. Therefore, a future reader of this ADR, should note that when we refer to Cosmos SDK, CometBFT, and ibc-go we specifically refer to their ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/v0.47/intro/overview",children:"v0.47"}),", ",(0,i.jsx)(n.a,{href:"https://docs.cometbft.com/v0.37/",children:"v0.37"})," and ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/ibc-go/blob/v7.3.0",children:"v7.3.0"})," versions respectively."]}),"\n",(0,i.jsx)(n.h3,{id:"single-chain-slashing",children:"Single-chain slashing"}),"\n",(0,i.jsxs)(n.p,{children:["Slashing is implemented across the ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/v0.47/modules/slashing",children:"slashing"}),"\nand ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/v0.47/modules/staking",children:"staking"})," modules.\nThe slashing module's keeper calls the staking module's ",(0,i.jsx)(n.code,{children:"Slash()"})," method, passing among others, the ",(0,i.jsx)(n.code,{children:"infractionHeight"})," (i.e., the height when the equivocation occurred), the validator's ",(0,i.jsx)(n.code,{children:"power"})," at the infraction height, and the ",(0,i.jsx)(n.code,{children:"slashFactor"})," (currently set to ",(0,i.jsx)(n.code,{children:"5%"})," in case of equivocation on the Cosmos Hub)."]}),"\n",(0,i.jsx)(n.h4,{id:"slashing-undelegations-and-redelegations",children:"Slashing undelegations and redelegations"}),"\n",(0,i.jsxs)(n.p,{children:["To slash undelegations, ",(0,i.jsx)(n.code,{children:"Slash"})," goes through all undelegations and checks whether they started before or after the infraction occurred. If an undelegation started before the ",(0,i.jsx)(n.code,{children:"infractionHeight"}),", then it is ",(0,i.jsx)(n.strong,{children:"not"})," slashed, otherwise it is slashed by ",(0,i.jsx)(n.code,{children:"slashFactor"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["The slashing of redelegations happens in a similar way, meaning that ",(0,i.jsx)(n.code,{children:"Slash"})," goes through all redelegations and checks whether the redelegations started before or after the ",(0,i.jsx)(n.code,{children:"infractionHeight"}),"."]}),"\n",(0,i.jsx)(n.h4,{id:"slashing-delegations",children:"Slashing delegations"}),"\n",(0,i.jsxs)(n.p,{children:["Besides undelegations and redelegations, the validator's delegations need to also be slashed.\nThis is performed by deducting the appropriate amount of tokens from the validator. Note that this deduction is computed based on the voting ",(0,i.jsx)(n.code,{children:"power"})," the misbehaving validator had at the height of the equivocation. As a result of the tokens deduction,\nthe ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/v0.47/modules/staking#delegator-shares",children:"tokens per share"}),"\nreduce and hence later on, when delegators undelegate or redelegate, the delegators retrieve back less\ntokens, effectively having their tokens slashed. The rationale behind this slashing mechanism, as mentioned in the ",(0,i.jsx)(n.a,{href:"https://docs.cosmos.network/v0.47/modules/staking#delegator-shares",children:"Cosmos SDK documentation"})]}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsx)(n.p,{children:"[...] is to simplify the accounting around slashing. Rather than iteratively slashing the tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, effectively reducing the value of each issued delegator share."}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["This approach of slashing delegations does not utilize the\n",(0,i.jsx)(n.code,{children:"infractionHeight"})," in any way and hence the following scenario could occur:"]}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["a validator ",(0,i.jsx)(n.code,{children:"V"})," performs an equivocation at a height ",(0,i.jsx)(n.code,{children:"Hi"})]}),"\n",(0,i.jsxs)(n.li,{children:["a new delegator ",(0,i.jsx)(n.code,{children:"D"})," delegates to ",(0,i.jsx)(n.code,{children:"V"})," after height ",(0,i.jsx)(n.code,{children:"Hi"})]}),"\n",(0,i.jsxs)(n.li,{children:["evidence of the equivocation by validator ",(0,i.jsx)(n.code,{children:"V"})," is received"]}),"\n",(0,i.jsxs)(n.li,{children:["the tokens of delegator ",(0,i.jsx)(n.code,{children:"D"})," are slashed"]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["In the above scenario, delegator ",(0,i.jsx)(n.code,{children:"D"})," is slashed, even though ",(0,i.jsx)(n.code,{children:"D"}),"'s voting power did not contribute to the infraction."]}),"\n",(0,i.jsx)(n.h4,{id:"old-evidence",children:"Old evidence"}),"\n",(0,i.jsxs)(n.p,{children:["In the single-chain case, old evidence (e.g., from 3 years ago) is ignored. This is achieved through\n",(0,i.jsx)(n.a,{href:"https://docs.cometbft.com/v0.37/spec/consensus/evidence",children:"CometBFT"})," that ignores old evidence based on the parameters ",(0,i.jsx)(n.code,{children:"MaxAgeNumBlocks"})," and ",(0,i.jsx)(n.code,{children:"MaxAgeDuration"})," (see ",(0,i.jsx)(n.a,{href:"https://github.com/cometbft/cometbft/blob/v0.37.0/evidence/pool.go#271",children:"here"}),").\nAdditionally, note that when the evidence is sent by CometBFT to the application, the evidence is rechecked in the ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L54",children:"evidence module"})," of Cosmos SDK and if it is old, the evidence is ignored.\nIn Cosmos Hub, the ",(0,i.jsx)(n.code,{children:"MaxAgeNumBlocks"})," is set to 1000000 (i.e., ~70 days if we assume we need ~6 sec per block) and ",(0,i.jsx)(n.code,{children:"MaxAgeDuration"})," is set to 172800000000000 ns (i.e., 2 days). Because of this check, we can easily exclude old evidence."]}),"\n",(0,i.jsx)(n.h3,{id:"slashing-for-equivocation-on-the-consumer",children:"Slashing for equivocation on the consumer"}),"\n",(0,i.jsxs)(n.p,{children:["In the single-chain case, slashing requires both the ",(0,i.jsx)(n.code,{children:"infractionHeight"})," and the voting ",(0,i.jsx)(n.code,{children:"power"}),".\nIn order to slash on the provider for an equivocation on a consumer, we need to have both the provider's ",(0,i.jsx)(n.code,{children:"infractionHeight"})," and voting ",(0,i.jsx)(n.code,{children:"power"}),".\nNote that the ",(0,i.jsx)(n.code,{children:"infractionHeight"})," on the consumer chain must be mapped to a height on the provider chain.\nUnless we have a way to find the corresponding ",(0,i.jsx)(n.code,{children:"infractionHeight"})," and ",(0,i.jsx)(n.code,{children:"power"})," on the provider chain, we cannot slash for equivocation on the consumer in the same way as we would slash in the single-chain case."]}),"\n",(0,i.jsxs)(n.p,{children:["The challenge of figuring out the corresponding ",(0,i.jsx)(n.code,{children:"infractionHeight"})," and ",(0,i.jsx)(n.code,{children:"power"})," values on the provider chain is due to the following trust assumption:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["We trust the consensus layer and validator set of the consumer chains, ",(0,i.jsx)(n.em,{children:"but we do not trust the application layer"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["As a result, we cannot trust anything that stems from the ",(0,i.jsx)(n.em,{children:"application state"})," of a consumer chain."]}),"\n",(0,i.jsxs)(n.p,{children:["Note that when a relayer or a user sends evidence through a ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/1232",children:"MsgSubmitConsumerDoubleVoting"})," message, the provider gets access to ",(0,i.jsx)(n.a,{href:"https://github.com/cometbft/cometbft/blob/v0.37.0/types/evidence.go#L35",children:"DuplicateVoteEvidence"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-protobuf",children:'type DuplicateVoteEvidence struct {\n\tVoteA *Vote `json:"vote_a"`\n\tVoteB *Vote `json:"vote_b"`\n\n\t// abci specific information\n\tTotalVotingPower int64\n\tValidatorPower int64\n\tTimestamp time.Time\n}\n'})}),"\n",(0,i.jsxs)(n.p,{children:['The "abci specific information" fields cannot be trusted because they are not signed. Therefore,\nwe can use neither ',(0,i.jsx)(n.code,{children:"ValidatorPower"})," for slashing on the provider chain, nor the ",(0,i.jsx)(n.code,{children:"Timestamp"})," to check the evidence age. We can get the ",(0,i.jsx)(n.code,{children:"infractionHeight"})," from the votes, but this ",(0,i.jsx)(n.code,{children:"infractionHeight"})," corresponds to the infraction height on the consumer and ",(0,i.jsx)(n.strong,{children:"not"})," on the provider chain.\nSimilarly, when a relayer or a user sends evidence through a ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/826",children:"MsgSubmitConsumerMisbehaviour"})," message, the provider gets access to ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/ibc-go/blob/v7.3.0/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79",children:"Misbehaviour"})," that we cannot use to extract the infraction height, power, or the time on the provider chain."]}),"\n",(0,i.jsx)(n.h2,{id:"proposed-solution",children:"Proposed solution"}),"\n",(0,i.jsx)(n.p,{children:"As a first iteration, we propose the following approach. At the moment the provider receives evidence of equivocation on a consumer:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["slash all the undelegations and redelegations using ",(0,i.jsx)(n.code,{children:"slashFactor"}),";"]}),"\n",(0,i.jsxs)(n.li,{children:["slash all delegations using as voting ",(0,i.jsx)(n.code,{children:"power"})," the sum of the voting power of the misbehaving validator and the power of all the ongoing undelegations and redelegations."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Evidence expiration:"})," Additionally, because we cannot infer the actual time of the evidence (i.e., the timestamp of the evidence cannot be trusted), we do not consider ",(0,i.jsx)(n.em,{children:"evidence expiration"})," and hence old evidence is never ignored (e.g., the provider would act on 3 year-old evidence of equivocation on a consumer).\nAdditionally, we do not need to store equivocation evidence to avoid slashing a validator more than once, because we ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L94",children:"do not slash"})," tombstoned validators and we ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L138",children:"tombstone"})," a validator when slashed."]}),"\n",(0,i.jsxs)(n.p,{children:["We do not act on evidence that was signed by a validator ",(0,i.jsx)(n.a,{href:"https://tutorials.cosmos.network/tutorials/9-path-to-prod/3-keys.html#what-validator-keys",children:"consensus key"})," that is ",(0,i.jsx)(n.em,{children:"pruned"})," when we receive the evidence. We prune a validator's consensus key if the validator has assigned a new consumer key (using ",(0,i.jsx)(n.code,{children:"MsgAssignConsumerKey"}),") and an unbonding period on the consumer chain has elapsed (see ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-001-key-assignment.md",children:"key assignment ADR"}),"). Note that the provider chain is informed that the unbonding period has elapsed on the consumer when the provider receives a ",(0,i.jsx)(n.code,{children:"VSCMaturedPacket"})," and because of this, if the consumer delays the sending of a ",(0,i.jsx)(n.code,{children:"VSCMaturedPacket"}),", we would delay the pruning of the key as well."]}),"\n",(0,i.jsx)(n.h3,{id:"implementation",children:"Implementation"}),"\n",(0,i.jsxs)(n.p,{children:["The following logic needs to be added to the ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/1232",children:"HandleConsumerDoubleVoting"})," and ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/826",children:"HandleConsumerMisbehaviour"})," methods:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-go",children:"undelegationsInTokens := sdk.NewInt(0)\nfor _, v := range k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validatorAddress) {\n for _, entry := range v.Entries {\n if entry.IsMature(now) && !entry.OnHold() {\n // undelegation no longer eligible for slashing, skip it\n continue\n }\n undelegationsInTokens = undelegationsInTokens.Add(entry.InitialBalance)\n }\n}\n\nredelegationsInTokens := sdk.NewInt(0)\nfor _, v := range k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validatorAddress) {\n for _, entry := range v.Entries {\n if entry.IsMature(now) && !entry.OnHold() {\n // redelegation no longer eligible for slashing, skip it\n continue\n }\n redelegationsInTokens = redelegationsInTokens.Add(entry.InitialBalance)\n }\n}\n\ninfractionHeight := 0\nundelegationsAndRedelegationsInPower = sdk.TokensToConsensusPower(undelegationsInTokens.Add(redelegationsInTokens))\ntotalPower := validator's voting power + undelegationsAndRedelegationsInPower\nslashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)\n\nk.stakingKeeper.Slash(ctx, validatorConsAddress, infractionHeight, totalPower, slashFraction, DoubleSign)\n"})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Infraction height:"})," We provide a zero ",(0,i.jsx)(n.code,{children:"infractionHeight"})," to the ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L33",children:"Slash"})," method in order to slash all ongoing undelegations and redelegations (see checks in ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L92",children:"Slash"}),", ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L195",children:"SlashUnbondingDelegation"}),", and ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L249",children:"SlashRedelegation"}),")."]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Power:"})," We pass the sum of the voting power of the misbehaving validator when the evidence was received (i.e., at evidence height) and the power of all the ongoing undelegations and redelegations.\nIf we assume that the ",(0,i.jsx)(n.code,{children:"slashFactor"})," is ",(0,i.jsx)(n.code,{children:"5%"}),", then the voting power we pass is ",(0,i.jsx)(n.code,{children:"power + totalPower(undelegations) + totalPower(redelegations)"}),".\nHence, when the ",(0,i.jsx)(n.code,{children:"Slash"})," method slashes all the undelegations and redelegations it would end up with ",(0,i.jsx)(n.code,{children:"0.05 * power + 0.05 * totalPower(undelegations) + 0.05 * totalPower(redelegations) - 0.05 * totalPower(undelegations) - 0.05 * totalPower(redelegations) = 0.05 * power"})," and hence it would slash ",(0,i.jsx)(n.code,{children:"5%"})," of the validator's power when the evidence is received."]}),"\n",(0,i.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsx)(n.p,{children:"With the proposed approach we can quickly implement slashing functionality on the provider chain for consumer chain equivocations.\nThis approach does not need to change the staking module and therefore does not change in any way how slashing is performed today for a single chain."}),"\n",(0,i.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["We ",(0,i.jsx)(n.em,{children:"definitely"})," slash more when it comes to undelegations and redelegations because we slash for all of them without considering an ",(0,i.jsx)(n.code,{children:"infractionHeight"}),"."]}),"\n",(0,i.jsxs)(n.li,{children:["We ",(0,i.jsx)(n.em,{children:"potentially"})," slash more than what we would have slashed if we knew the voting ",(0,i.jsx)(n.code,{children:"power"})," at the corresponding ",(0,i.jsx)(n.code,{children:"infractionHeight"})," in the provider chain."]}),"\n",(0,i.jsx)(n.li,{children:"We slash on old evidence of equivocation on a consumer."}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md",children:"ADR 005: Cryptographic verification of equivocation evidence"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/732",children:"EPIC tracking cryptographic equivocation feature"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://forum.cosmos.network/t/cryptographic-equivocation-slashing-design/11400",children:"Cosmos Hub Forum discussion on cryptographic equivocation slashing"})}),"\n"]})]})}function l(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},1151:(e,n,o)=>{o.d(n,{Z:()=>r,a:()=>a});var i=o(7294);const s={},t=i.createContext(s);function a(e){const n=i.useContext(t);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),i.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/d0d0ba0d.87d75440.js b/assets/js/d0d0ba0d.87d75440.js new file mode 100644 index 0000000000..7bf49fe252 --- /dev/null +++ b/assets/js/d0d0ba0d.87d75440.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8772],{9133:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>d,frontMatter:()=>a,metadata:()=>i,toc:()=>h});var s=t(5893),o=t(1151);const a={sidebar_position:11,title:"Standalone to Consumer Changeover"},r=void 0,i={id:"adrs/adr-010-standalone-changeover",title:"Standalone to Consumer Changeover",description:"ADR 010: Standalone to Consumer Changeover",source:"@site/docs/adrs/adr-010-standalone-changeover.md",sourceDirName:"adrs",slug:"/adrs/adr-010-standalone-changeover",permalink:"/interchain-security/adrs/adr-010-standalone-changeover",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:11,frontMatter:{sidebar_position:11,title:"Standalone to Consumer Changeover"},sidebar:"tutorialSidebar",previous:{title:"Soft Opt-Out",permalink:"/interchain-security/adrs/adr-009-soft-opt-out"},next:{title:"Improving testing and increasing confidence",permalink:"/interchain-security/adrs/adr-011-improving-test-confidence"}},c={},h=[{value:"ADR 010: Standalone to Consumer Changeover",id:"adr-010-standalone-to-consumer-changeover",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Process",id:"process",level:3},{value:"Changes to CCV Protocol",id:"changes-to-ccv-protocol",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}];function l(e){const n={a:"a",code:"code",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,o.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h2,{id:"adr-010-standalone-to-consumer-changeover",children:"ADR 010: Standalone to Consumer Changeover"}),"\n",(0,s.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"6/30/23: Feature completed, first draft of ADR."}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,s.jsx)(n.p,{children:"Implemented"}),"\n",(0,s.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.a,{href:"https://github.com/Stride-Labs/stride",children:"Stride"}),' will be the first consumer to "changeover" from a standalone cosmos blockchain, to a consumer chain secured by the Cosmos Hub. This document outlines the changes made to support this changeover process.']}),"\n",(0,s.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,s.jsx)(n.h3,{id:"process",children:"Process"}),"\n",(0,s.jsx)(n.p,{children:'Prior to the changeover, the consumer chain will have an existing staking keeper and validator set, these may be referred to as the "standalone staking keeper" and "standalone validator set" respectively.'}),"\n",(0,s.jsx)(n.p,{children:"The first step in the changeover process is to submit a ConsumerAdditionProposal. If the proposal passes, the provider will create a new IBC client for the consumer at spawn time, with the provider's validator set. A consumer genesis will also be constructed by the provider for validators to query. Within this consumer genesis contains the initial validator set for the consumer to apply after the changeover."}),"\n",(0,s.jsx)(n.p,{children:"Next, the standalone consumer chain runs an upgrade which adds the CCV module, and is properly setup to execute changeover logic."}),"\n",(0,s.jsx)(n.p,{children:"The consumer upgrade height must be reached after the provider has created the new IBC client. Any Interchain Security validators who will run the consumer, but are not a part of the sovereign validator set, must sync up a full node before the consumer upgrade height is reached. The disk state of said full node will be used to run the consumer chain after the changeover has completed."}),"\n",(0,s.jsxs)(n.p,{children:["The meat of the changeover logic is that the consumer chain validator set is updated to that which was specified by the provider via the queried consumer genesis. Validators which were a part of the old set, but not the new set, are given zero voting power. Once these validator updates are given to Comet, the set is committed, and in effect 2 blocks later (see ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/x/ccv/consumer/keeper/changeover.go#L19",children:"FirstConsumerHeight"}),")."]}),"\n",(0,s.jsx)(n.p,{children:"A relayer then establishes the new IBC connection between the provider and consumer. The CCV channel handshake is started on top of this connection. Once the CCV channel is established and VSC packets are being relayed, the consumer chain is secured by the provider."}),"\n",(0,s.jsx)(n.h3,{id:"changes-to-ccv-protocol",children:"Changes to CCV Protocol"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Consumer Genesis state is updated to include a ",(0,s.jsx)(n.code,{children:"PreCCV"})," boolean. When this boolean is set true in the consumer genesis JSON, ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/x/ccv/consumer/keeper/changeover.go",children:"special logic"})," is executed on InitGenesis to trigger the changeover process on the consumer's first endblocker after the upgrade which adds the CCV module. Note that InitGenesis is not automatically called during chain upgrades, so the consumer must manually call the consumer's InitGenesis method in an upgrade handler."]}),"\n",(0,s.jsxs)(n.li,{children:["The ",(0,s.jsx)(n.code,{children:"ConsumerAdditionProposal"})," type is updated to include a ",(0,s.jsx)(n.code,{children:"DistributionTransmissionChannel"})," field. This field allows the consumer to use an existing IBC transfer channel to send rewards as a part of the CCV protocol. Consumers that're not changing over from a standalone chain will leave this field blank, indicating that a new transfer channel should be created on top of the same connection as the CCV channel."]}),"\n",(0,s.jsx)(n.li,{children:"The CCV consumer keeper is updated to contain an optional reference to the standalone staking keeper. The standalone staking keeper is used to slash for infractions that happened before the changeover was completed. Ie. any infraction from a block height before the changeover, that is submitted after the changeover, will call the standalone staking keeper's slash method. Note that a changeover consumer's standalone staking keeper becomes a democracy module keeper, so it is possible for a governance token to be slashed."}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,s.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Existing cosmos chains are now able to onboard over to a consumer chain secured by a provider."}),"\n",(0,s.jsx)(n.li,{children:"The previous staking keepers for such chains can be transitioned to democracy staking module keepers."}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["The delineation between different types of consumers in this repo becomes less clear. Ie. there is code in the ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/app/consumer-democracy/app.go",children:"democracy consumer's app.go"})," that only applies to a previously standalone chain, but that file also serves as the base for a normal democracy consumer launched with RS from genesis."]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["EPIC: Standalone to Consumer Changeover ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/756",children:"#756"})]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt",children:"Changeover diagram from Stride"})}),"\n"]})]})}function d(e={}){const{wrapper:n}={...(0,o.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>i,a:()=>r});var s=t(7294);const o={},a=s.createContext(o);function r(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:r(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/d0d80f5c.af276b99.js b/assets/js/d0d80f5c.af276b99.js new file mode 100644 index 0000000000..92b6d50d29 --- /dev/null +++ b/assets/js/d0d80f5c.af276b99.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9982],{2543:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>l,frontMatter:()=>a,metadata:()=>t,toc:()=>c});var i=s(5893),r=s(1151);const a={sidebar_position:1},o="Key Assignment",t={id:"features/key-assignment",title:"Key Assignment",description:"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.",source:"@site/versioned_docs/version-v5.0.0/features/key-assignment.md",sourceDirName:"features",slug:"/features/key-assignment",permalink:"/interchain-security/v5.0.0/features/key-assignment",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Upgrading to ICS v5.0.0",permalink:"/interchain-security/v5.0.0/upgrading/migrate_v4_v5"},next:{title:"Reward Distribution",permalink:"/interchain-security/v5.0.0/features/reward-distribution"}},d={},c=[{value:"Rules",id:"rules",level:2},{value:"Adding a key",id:"adding-a-key",level:2},{value:"Changing a key",id:"changing-a-key",level:2},{value:"Removing a key",id:"removing-a-key",level:2},{value:"Querying proposed consumer chains",id:"querying-proposed-consumer-chains",level:2}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"key-assignment",children:"Key Assignment"}),"\n",(0,i.jsx)(n.p,{children:"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.\nThere are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains."}),"\n",(0,i.jsxs)(n.p,{children:["The feature is outlined in this ",(0,i.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-001-key-assignment",children:"ADR-001"})]}),"\n",(0,i.jsxs)(n.p,{children:["By sending an ",(0,i.jsx)(n.code,{children:"AssignConsumerKey"})," transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator."]}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsx)(n.p,{children:"Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity."})}),"\n",(0,i.jsx)(n.h2,{id:"rules",children:"Rules"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"a key can be assigned as soon as the consumer addition proposal is submitted to the provider"}),"\n",(0,i.jsx)(n.li,{children:"validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider"}),"\n",(0,i.jsx)(n.li,{children:"validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X"}),"\n",(0,i.jsx)(n.li,{children:"a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain"}),"\n"]}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsx)(n.p,{children:"Validators can use a different key for each consumer chain."})}),"\n",(0,i.jsx)(n.h2,{id:"adding-a-key",children:"Adding a key"}),"\n",(0,i.jsx)(n.p,{children:"First, create a new node on the consumer chain using the equivalent:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"consumerd init <moniker>\n"})}),"\n",(0,i.jsx)(n.p,{children:"Then query your node for the consensus key."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Then, make an ",(0,i.jsx)(n.code,{children:"assign-consensus-key"})," transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad tx provider assign-consensus-key <consumer-chain-id> '<pubkey>' --from <tx-signer> --home <home_dir> --gas 900000 -b sync -y -o json\n"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"consumer-chain-id"})," is the string identifier of the consumer chain, as assigned on the provider chain"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"consumer-pub-key"})," has the following format ",(0,i.jsx)(n.code,{children:'{"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}'})]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Check that the key was assigned correctly by querying the provider:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad query provider validator-consumer-key <consumer-chain-id> cosmosvalcons1e....3xsj3ayzf4uv6\n"})}),"\n",(0,i.jsxs)(n.p,{children:["You must use a ",(0,i.jsx)(n.code,{children:"valcons"})," address. You can obtain it by querying your node on the provider ",(0,i.jsx)(n.code,{children:"gaiad tendermint show-address"})]}),"\n",(0,i.jsx)(n.p,{children:"OR"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad query provider validator-provider-key <consumer-chain-id> consumervalcons1e....123asdnoaisdao\n"})}),"\n",(0,i.jsxs)(n.p,{children:["You must use a ",(0,i.jsx)(n.code,{children:"valcons"})," address. You can obtain it by querying your node on the consumer ",(0,i.jsx)(n.code,{children:"consumerd tendermint show-address"})]}),"\n",(0,i.jsx)(n.p,{children:"OR"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad query provider all-pairs-valconsensus-address <consumer-chain-id>\n"})}),"\n",(0,i.jsxs)(n.p,{children:["You just need to use the ",(0,i.jsx)(n.code,{children:"chainId"})," of consumer to query all pairs valconsensus address with ",(0,i.jsx)(n.code,{children:"consumer-pub-key"})," for each of pair"]}),"\n",(0,i.jsx)(n.h2,{id:"changing-a-key",children:"Changing a key"}),"\n",(0,i.jsx)(n.p,{children:"To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied"}),"\n",(0,i.jsx)(n.h2,{id:"removing-a-key",children:"Removing a key"}),"\n",(0,i.jsxs)(n.p,{children:["To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the ",(0,i.jsx)(n.code,{children:"Adding a key"})," section and using your provider consensus key."]}),"\n",(0,i.jsx)(n.h2,{id:"querying-proposed-consumer-chains",children:"Querying proposed consumer chains"}),"\n",(0,i.jsx)(n.p,{children:"To query the consumer addition proposals that are in the voting period, you can use the following command on the provider:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gaiad query provider list-proposed-consumer-chains\n"})}),"\n",(0,i.jsx)(n.p,{children:"This query is valuable for staying informed about when keys can be assigned to newly proposed consumer chains."})]})}function l(e={}){const{wrapper:n}={...(0,r.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},1151:(e,n,s)=>{s.d(n,{Z:()=>t,a:()=>o});var i=s(7294);const r={},a=i.createContext(r);function o(e){const n=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function t(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),i.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/d1daeca6.bfecf8bd.js b/assets/js/d1daeca6.bfecf8bd.js new file mode 100644 index 0000000000..cf59526e4c --- /dev/null +++ b/assets/js/d1daeca6.bfecf8bd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3845],{6142:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>s,metadata:()=>t,toc:()=>c});var i=o(5893),r=o(1151);const s={sidebar_position:3},a="ICS Provider Proposals",t={id:"features/proposals",title:"ICS Provider Proposals",description:"Interchain security module introduces new proposal types to the provider.",source:"@site/docs/features/proposals.md",sourceDirName:"features",slug:"/features/proposals",permalink:"/interchain-security/features/proposals",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Reward Distribution",permalink:"/interchain-security/features/reward-distribution"},next:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/features/slashing"}},d={},c=[{value:"<code>ConsumerAdditionProposal</code>",id:"consumeradditionproposal",level:2},{value:"<code>ConsumerRemovalProposal</code>",id:"consumerremovalproposal",level:2},{value:"<code>ConsumerModificationProposal</code>",id:"consumermodificationproposal",level:2},{value:"ChangeRewardDenomProposal",id:"changerewarddenomproposal",level:2}];function l(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",strong:"strong",...(0,r.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"ics-provider-proposals",children:"ICS Provider Proposals"}),"\n",(0,i.jsx)(n.p,{children:"Interchain security module introduces new proposal types to the provider."}),"\n",(0,i.jsx)(n.p,{children:"The proposals are used to propose upcoming interchain security events through governance."}),"\n",(0,i.jsx)(n.h2,{id:"consumeradditionproposal",children:(0,i.jsx)(n.code,{children:"ConsumerAdditionProposal"})}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["If you are preparing a ",(0,i.jsx)(n.code,{children:"ConsumerAdditionProposal"})," you can find more information in the ",(0,i.jsx)(n.a,{href:"/interchain-security/consumer-development/onboarding",children:"consumer onboarding checklist"}),"."]})}),"\n",(0,i.jsx)(n.p,{children:"Proposal type used to suggest adding a new consumer chain."}),"\n",(0,i.jsxs)(n.p,{children:["When proposals of this type are passed and the ",(0,i.jsx)(n.code,{children:"spawn_time"})," specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain."]}),"\n",(0,i.jsx)(n.p,{children:"Minimal example:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-js",children:'{\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n "title": "Add consumer chain",\n "description": ".md description of your chain and all other relevant information",\n "chain_id": "newchain-1",\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Unbonding period for the consumer chain.\n // It should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n "transfer_timeout_period": 1800000000000,\n "consumer_redistribution_fraction": "0.75",\n "blocks_per_distribution_transmission": 1000,\n "historical_entries": 10000,\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n "distribution_transmission_channel": "channel-123",\n "top_N": 95,\n "validators_power_cap": 0,\n "validator_set_cap": 0,\n "allowlist": [],\n "denylist": []\n}\n'})}),"\n",(0,i.jsxs)(n.p,{children:["More examples can be found in the interchain security testnet repository ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/stopped/baryon-1/proposal-baryon-1.json",children:"here"})," and ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/stopped/noble-1/start-proposal-noble-1.json",children:"here"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"consumerremovalproposal",children:(0,i.jsx)(n.code,{children:"ConsumerRemovalProposal"})}),"\n",(0,i.jsx)(n.p,{children:"Proposal type used to suggest removing an existing consumer chain."}),"\n",(0,i.jsx)(n.p,{children:"When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain.\nAfter the consumer chain removal, the chain in question will no longer be secured by the provider's validator set."}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain.\nAdditional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set.\nMore information will be made available in the ",(0,i.jsx)(n.a,{href:"/interchain-security/consumer-development/offboarding",children:"Consumer Offboarding Checklist"}),"."]})}),"\n",(0,i.jsx)(n.p,{children:"Minimal example:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-js",children:'{\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details"\n}\n'})}),"\n",(0,i.jsx)(n.h2,{id:"consumermodificationproposal",children:(0,i.jsx)(n.code,{children:"ConsumerModificationProposal"})}),"\n",(0,i.jsx)(n.p,{children:"Proposal type used to change the power shaping parameters of a running consumer chain, as well as to change a Top N running\nconsumer chain to an Opt-In chain and vice versa."}),"\n",(0,i.jsxs)(n.p,{children:["When a ",(0,i.jsx)(n.code,{children:"ConsumerModificationProposal"})," passes for a running consumer chain, the consumer chain would change all its\nparameters to the ones passed in the ",(0,i.jsx)(n.code,{children:"ConsumerModificationProposal"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["Assume, a ",(0,i.jsx)(n.code,{children:"chain-1"})," is a Top N chain. If the following ",(0,i.jsx)(n.code,{children:"ConsumerModificationProposal"})," passes, then ",(0,i.jsx)(n.code,{children:"chain-1"})," would become\nan Opt-In chain with a 40% validators power cap, a maximum number of 30 validators, and one denylisted validator."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-js",children:'{\n "title": "Modify consumer chain",\n "description": ".md description of your chain and all other relevant information",\n "chain_id": "chain-1",\n "top_N": 0,\n "validators_power_cap": 40,\n "validator_set_cap": 30,\n "allowlist": [],\n "denylist": ["cosmosvalcons1qmq08eruchr5sf5s3rwz7djpr5a25f7xw4mceq"]\n}\n'})}),"\n",(0,i.jsxs)(n.admonition,{type:"warning",children:[(0,i.jsxs)(n.p,{children:["If ",(0,i.jsx)(n.code,{children:"top_N"}),", ",(0,i.jsx)(n.code,{children:"validators_power_cap"}),", or some other argument is not included in the proposal, then it is considered\nthat the default value is set for this argument. For example, if a Top 50% chain wants to only modify ",(0,i.jsx)(n.code,{children:"validators_power_cap"}),"\nfrom 35 to 40, then the ",(0,i.jsx)(n.code,{children:"ConsumerModificationProposal"})," would still need to include that ",(0,i.jsx)(n.code,{children:"top_N"})," is 50. Otherwise\n",(0,i.jsx)(n.code,{children:"top_N"})," would be set to its default value of 0, and the chain would become an Opt-In chain."]}),(0,i.jsxs)(n.p,{children:["To be ",(0,i.jsx)(n.strong,{children:"safe"}),", always include ",(0,i.jsx)(n.code,{children:"top_N"})," and all the power shaping parameters in your ",(0,i.jsx)(n.code,{children:"ConsumerModificationProposal"}),"."]})]}),"\n",(0,i.jsx)(n.h2,{id:"changerewarddenomproposal",children:"ChangeRewardDenomProposal"}),"\n",(0,i.jsx)(n.p,{children:"Proposal type used to mutate the set of denoms accepted by the provider as rewards."}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["A ",(0,i.jsx)(n.code,{children:"ChangeRewardDenomProposal"})," will only be accepted on the provider chain if at least one of the ",(0,i.jsx)(n.code,{children:"denomsToAdd"})," or ",(0,i.jsx)(n.code,{children:"denomsToRemove"})," fields is populated with at least one denom. Also, a denom cannot be repeated in both sets."]})}),"\n",(0,i.jsx)(n.p,{children:"Minimal example:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-js",children:'{\n "title": "Add uatom as a reward denom",\n "description": "Here is more information about the proposal",\n "denomsToAdd": ["uatom"],\n "denomsToRemove": []\n}\n'})}),"\n",(0,i.jsxs)(n.admonition,{type:"tip",children:[(0,i.jsxs)(n.p,{children:["Besides native provider denoms (e.g., ",(0,i.jsx)(n.code,{children:"uatom"})," for the Cosmos Hub), please use the ",(0,i.jsx)(n.code,{children:"ibc/*"})," denom trace format.\nFor example, for ",(0,i.jsx)(n.code,{children:"untrn"})," transferred over the path ",(0,i.jsx)(n.code,{children:"transfer/channel-569"}),", the denom trace\ncan be queried using the following command:"]}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"> gaiad query ibc-transfer denom-hash transfer/channel-569/untrn\nhash: 0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5\n"})}),(0,i.jsxs)(n.p,{children:["Then use the resulting hash in the ",(0,i.jsx)(n.code,{children:"ChangeRewardDenomProposal"}),", e.g.,"]}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-js",children:'{\n "title": "Add untrn as a reward denom",\n "description": "Here is more information about the proposal",\n "denomsToAdd": ["ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5"],\n "denomsToRemove": []\n}\n'})})]})]})}function h(e={}){const{wrapper:n}={...(0,r.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},1151:(e,n,o)=>{o.d(n,{Z:()=>t,a:()=>a});var i=o(7294);const r={},s=i.createContext(r);function a(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function t(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/d21f9ede.fc07846e.js b/assets/js/d21f9ede.fc07846e.js new file mode 100644 index 0000000000..098735fc3a --- /dev/null +++ b/assets/js/d21f9ede.fc07846e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4932],{4330:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>l,contentTitle:()=>t,default:()=>h,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var i=s(5893),o=s(1151);const r={sidebar_position:13,title:"Separate Releasing"},t="ADR 012: Separate Releasing",a={id:"adrs/adr-012-separate-releasing",title:"Separate Releasing",description:"Changelog",source:"@site/docs/adrs/adr-012-separate-releasing.md",sourceDirName:"adrs",slug:"/adrs/adr-012-separate-releasing",permalink:"/interchain-security/adrs/adr-012-separate-releasing",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:13,frontMatter:{sidebar_position:13,title:"Separate Releasing"},sidebar:"tutorialSidebar",previous:{title:"Improving testing and increasing confidence",permalink:"/interchain-security/adrs/adr-011-improving-test-confidence"},next:{title:"Slashing on the provider for consumer equivocation",permalink:"/interchain-security/adrs/adr-013-equivocation-slashing"}},l={},d=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Spike results",id:"spike-results",level:3},{value:"Why go.mod split is not the way to go",id:"why-gomod-split-is-not-the-way-to-go",level:3},{value:"Why separate repos is cool but also not the way to go",id:"why-separate-repos-is-cool-but-also-not-the-way-to-go",level:3},{value:"Decision",id:"decision",level:2},{value:"Example release flow",id:"example-release-flow",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function c(e){const n={a:"a",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",strong:"strong",ul:"ul",...(0,o.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"adr-012-separate-releasing",children:"ADR 012: Separate Releasing"}),"\n",(0,i.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[8/18/22,": Initial draft of idea in ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/801",children:"#801"})]}),"\n",(0,i.jsxs)(n.li,{children:[8/22/22,": Put idea in this ADR"]}),"\n",(0,i.jsxs)(n.li,{children:[.05,": Reject this ADR"]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(n.p,{children:"Rejected"}),"\n",(0,i.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,i.jsx)(n.h3,{id:"spike-results",children:"Spike results"}),"\n",(0,i.jsxs)(n.p,{children:["I explored the idea of ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/801",children:"#801"})," with this ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/tree/shawn%2Fgo-mod-split-aug-spike",children:"spike branch"}),". Here's my conclusions:"]}),"\n",(0,i.jsxs)(n.p,{children:["Splitting this repo to have multiple go.mods is possible. However there are various intricacies involved in decoupling the package hierarchy to have ",(0,i.jsx)(n.code,{children:"x/ccv/types"})," as the lowest level dep, with ",(0,i.jsx)(n.code,{children:"x/ccv/consumer"})," and ",(0,i.jsx)(n.code,{children:"x/ccv/provider"})," being one dep layer above, with high-level tests depending on all three of the mentioned packages. I'd estimate this decoupling would take 2-5 workdays to finish, and require significant review effort."]}),"\n",(0,i.jsx)(n.h3,{id:"why-gomod-split-is-not-the-way-to-go",children:"Why go.mod split is not the way to go"}),"\n",(0,i.jsxs)(n.p,{children:["Let's take a step back and remember the issue we're trying to solve - ",(0,i.jsx)(n.strong,{children:"We need a clean way to decouple semver/releasing for the consumer and provider modules"}),". After more consideration, splitting up go.mods gives us little benefit in achieving this. Reasons:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["The ",(0,i.jsx)(n.code,{children:"go.mod"})," dependency system is tied to git tags for the entire repo (ex: ",(0,i.jsx)(n.code,{children:"require github.com/cometbft/cometbft v0.37.2"})," refers to a historical tag for the entire cometbft repo)."]}),"\n",(0,i.jsx)(n.li,{children:"It'd be an odd dev experience to allow modules to reference past releases of other modules in the same repo. When would we ever want the consumer module to reference a past release of the types module for example?"}),"\n",(0,i.jsxs)(n.li,{children:["If we allow for ",(0,i.jsx)(n.code,{children:"go.mod"})," replace statements to build from local source code, why split up the package deps at all?"]}),"\n",(0,i.jsxs)(n.li,{children:["Splitting go.mods adds a bunch of complexity with ",(0,i.jsx)(n.code,{children:"go.work"})," files and all that shiz. VSCode does not play well with multiple module repos either."]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"why-separate-repos-is-cool-but-also-not-the-way-to-go",children:"Why separate repos is cool but also not the way to go"}),"\n",(0,i.jsxs)(n.p,{children:["All this considered, the cleanest solution to decoupling semver/releasing for the consumer and provider modules would be to have multiple repos, each with their own go.mod (3-4 repos total including high level tests). With this scheme we could separately tag each repo as changes are merged, they could share some code from ",(0,i.jsx)(n.code,{children:"types"})," being an external dep, etc."]}),"\n",(0,i.jsx)(n.p,{children:"I don't think any of us want to split up the monorepo, that's a lot of work and seems like bikeshedding. There's another solution that's very simple.."}),"\n",(0,i.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,i.jsxs)(n.p,{children:["Slightly adapting ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/cca008d856e3ffc60ec1a486871d0faa702abe26/CONTRIBUTING.md#semantic-versioning",children:"the current semver ruleset"}),":"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"A library API breaking change to EITHER the provider or consumer module will result in an increase of the MAJOR version number for BOTH modules (X.y.z-provider AND X.y.z-consumer)."}),"\n",(0,i.jsx)(n.li,{children:"A state breaking change (change requiring coordinated upgrade and/or state migration) will result in an increase of the MINOR version number for the AFFECTED module(s) (x.Y.z-provider AND/OR x.Y.z-consumer)."}),"\n",(0,i.jsx)(n.li,{children:"Any other changes (including node API breaking changes) will result in an increase of the PATCH version number for the AFFECTED module(s) (x.y.Z-provider AND/OR x.y.Z-consumer)."}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"example-release-flow",children:"Example release flow"}),"\n",(0,i.jsxs)(n.p,{children:["We upgrade ",(0,i.jsx)(n.code,{children:"main"})," to use a new version of SDK. This is a major version bump, triggering a new release for both the provider and consumer modules, ",(0,i.jsx)(n.code,{children:"v5.0.0-provider"})," and ",(0,i.jsx)(n.code,{children:"v5.0.0-consumer"}),"."]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["A state breaking change is merged to ",(0,i.jsx)(n.code,{children:"main"})," for the provider module. We release only a ",(0,i.jsx)(n.code,{children:"v5.1.0-provider"})," off main."]}),"\n",(0,i.jsxs)(n.li,{children:["Another state breaking change is merged to ",(0,i.jsx)(n.code,{children:"main"})," for the provider module. We release only a ",(0,i.jsx)(n.code,{children:"v5.2.0-provider"})," off main."]}),"\n",(0,i.jsxs)(n.li,{children:["At this point, the latest consumer version is still ",(0,i.jsx)(n.code,{children:"v5.0.0-consumer"}),". We now merge a state breaking change for the consumer module to ",(0,i.jsx)(n.code,{children:"main"}),", and consequently release ",(0,i.jsx)(n.code,{children:"v5.1.0-consumer"}),". Note that ",(0,i.jsx)(n.code,{children:"v5.1.0-consumer"})," is tagged off a LATER commit from main than ",(0,i.jsx)(n.code,{children:"v5.2.0-provider"}),". This is fine, as the consumer module should not be affected by the provider module's state breaking changes."]}),"\n",(0,i.jsxs)(n.li,{children:["Once either module sees a library API breaking change, we bump the major version for both modules. For example, we merge a library API breaking change to ",(0,i.jsx)(n.code,{children:"main"})," for the provider module. We release ",(0,i.jsx)(n.code,{children:"v6.0.0-provider"})," and ",(0,i.jsx)(n.code,{children:"v6.0.0-consumer"})," off main. Note that most often, a library API breaking change will affect both modules simultaneously (example being bumping sdk version)."]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,i.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Consumer repos have clear communication of what tagged versions are relevant to them. Consumer devs should know to never reference an ICS version that starts with ",(0,i.jsx)(n.code,{children:"provider"}),", even if it'd technically build."]}),"\n",(0,i.jsx)(n.li,{children:"Consumer and provider modules do not deviate as long as we continually release off a shared main branch. Backporting remains relatively unchanged besides being explicit about what module(s) your changes should affect."}),"\n",(0,i.jsx)(n.li,{children:"No code changes, just changes in process. Very simple."}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"~~Slightly more complexity.~~Considerably more complex to manage the ICS library.\nThis is because ICS needs to support multiple versions of SDK (e.g., 0.45, 0.47, 0.50).\nIn addition, ICS needs to support a special fork of SDK (with LSM included) for the Cosmos Hub.\nThis means that instead of focusing on main the development team needs to manage multiple release\nbranches with different dependency trees."}),"\n",(0,i.jsx)(n.li,{children:"This solution does not allow having provider and consumer on separate versions of e.g. the Cosmos SDK."}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,i.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsx)(n.p,{children:"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!"}),"\n"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/801",children:"#801"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/801#issuecomment-1683349298",children:"#801 comment"})}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,o.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},1151:(e,n,s)=>{s.d(n,{Z:()=>a,a:()=>t});var i=s(7294);const o={},r=i.createContext(o);function t(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:t(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/d2e13769.80866211.js b/assets/js/d2e13769.80866211.js new file mode 100644 index 0000000000..b5c12d84be --- /dev/null +++ b/assets/js/d2e13769.80866211.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8382],{3396:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>t,metadata:()=>r,toc:()=>l});var o=i(5893),s=i(1151);const t={sidebar_position:2,title:"ADR Template"},a="ADR 007: Pause validator unbonding during equivocation proposal",r={id:"adrs/adr-007-pause-unbonding-on-eqv-prop",title:"ADR Template",description:"Changelog",source:"@site/versioned_docs/version-v5.0.0/adrs/adr-007-pause-unbonding-on-eqv-prop.md",sourceDirName:"adrs",slug:"/adrs/adr-007-pause-unbonding-on-eqv-prop",permalink:"/interchain-security/v5.0.0/adrs/adr-007-pause-unbonding-on-eqv-prop",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"ADR Template"},sidebar:"tutorialSidebar",previous:{title:"ADR Template",permalink:"/interchain-security/v5.0.0/adrs/adr-004-denom-dos-fixes"},next:{title:"ADR Template",permalink:"/interchain-security/v5.0.0/adrs/adr-template"}},d={},l=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"How",id:"how",level:3},{value:"When pause",id:"when-pause",level:3},{value:"When unpause",id:"when-unpause",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function c(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"adr-007-pause-validator-unbonding-during-equivocation-proposal",children:"ADR 007: Pause validator unbonding during equivocation proposal"}),"\n",(0,o.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"2023-05-16: Initial Draft"}),"\n",(0,o.jsx)(n.li,{children:"2023-11-30: Change the status to rejected"}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,o.jsx)(n.p,{children:"Rejected"}),"\n",(0,o.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.strong,{children:"Note:"})," ADR rejected as the equivocation proposal was removed by the\ncryptographic verification of equivocation feature\n(see ",(0,o.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-005-cryptographic-equivocation-verification",children:"ADR-005"})," and\n",(0,o.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-013-equivocation-slashing",children:"ADR-013"}),")."]}),"\n",(0,o.jsx)(n.p,{children:"Currently, if an equivocation slashing proposal is created after more than one\nweek has passed since the equivocation, it is possible that the validator in\nquestion could unbond and get away without being slashed, since the unbonding\nperiod is 3 weeks, and the voting period is 2 weeks. For this reason, it might\nbe good to pause unbondings for validators named in an equivocation slashing\nproposal until the proposal's voting period is over."}),"\n",(0,o.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,o.jsx)(n.h3,{id:"how",children:"How"}),"\n",(0,o.jsxs)(n.p,{children:["Pausing the unbonding period is already possible thanks to the changes in the\n",(0,o.jsx)(n.code,{children:"staking"})," module of the cosmos-sdk:"]}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"stakingKeeper.PutUnbondingOnHold"})," pauses an unbonding period"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"stakingKeeper.UnbondingCanComplete"})," unpauses an unbonding period"]}),"\n"]}),"\n",(0,o.jsxs)(n.p,{children:["These methods use a reference counter under the hood, that gets incremented\nevery time ",(0,o.jsx)(n.code,{children:"PutUnbondingOnHold"})," is called, and decreased when\n",(0,o.jsx)(n.code,{children:"UnbondingCanComplete"})," is called instead. A specific unbonding is considered\nfully unpaused when its underlying reference counter reaches 0. Therefore, as\nlong as we safeguard consistency - i.e. we make sure we eventually decrement\nthe reference counter for each time we have incremented it - we can safely use\nthis existing mechanism without conflicts with the ",(0,o.jsx)(n.em,{children:"Completion of Unbonding\nOperations"})," system."]}),"\n",(0,o.jsx)(n.h3,{id:"when-pause",children:"When pause"}),"\n",(0,o.jsxs)(n.p,{children:["The unbonding period (if there is any unbonding) should be paused once an\nequivocation proposal enters the voting period. For that, the ",(0,o.jsx)(n.code,{children:"gov"})," module's\nhook ",(0,o.jsx)(n.code,{children:"AfterProposalDeposit"})," can be used."]}),"\n",(0,o.jsx)(n.p,{children:"If the hook is triggered with a an equivocation proposal in voting period, then\nfor each equivocation of the proposal, the unbonding operations of the related\nvalidator that were initiated after the equivocation block time must be paused"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"i.e. the underlying reference counter has to be increased."}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:"Note that even after the voting period has started, a proposal can receive\nadditional deposits. The hook is triggered however at arrival of a deposit, so\na check to verify that the proposal is not already in voting period is\nrequired."}),"\n",(0,o.jsx)(n.h3,{id:"when-unpause",children:"When unpause"}),"\n",(0,o.jsxs)(n.p,{children:["We can use a ",(0,o.jsx)(n.code,{children:"gov"})," module's hook also here and it is\n",(0,o.jsx)(n.code,{children:"AfterProposalVotingPeriodEnded"}),"."]}),"\n",(0,o.jsx)(n.p,{children:"If the hook is triggered with an equivocation proposal, then for each\nassociated equivocation, the unbonding operations of the related validator that\nwere initiated between the equivocation block time and the start of the\nproposal voting period must be unpaused - i.e. decrease the underlying\nreference counter - regardless of the proposal outcome."}),"\n",(0,o.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,o.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Validators subject to an equivocation proposal cannot finish unbonding\ntheir tokens before the end of the voting period."}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"A malicious consumer chain could forge slash packets enabling submission of\nan equivocation proposal on the provider chain, resulting in the freezing of\nvalidator's unbondings for an undeterminated amount of time."}),"\n",(0,o.jsx)(n.li,{children:"Misbehavior on a consumer chain can potentially go unpunished, if no one\nsubmits an equivocation proposal in time, or if the proposal doesn't pass."}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"This feature can't be used for social slashing, because an equivocation\nproposal is only accepted if there's a slash log for the related\nvalidator(s), meaning the consumer chain has reported the equivocation to\nthe provider chain."}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/747",children:"https://github.com/cosmos/interchain-security/issues/747"})}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/791",children:"https://github.com/cosmos/interchain-security/pull/791"})}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(c,{...e})}):c(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>r,a:()=>a});var o=i(7294);const s={},t=o.createContext(s);function a(e){const n=o.useContext(t);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),o.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/d784d738.71e628a7.js b/assets/js/d784d738.71e628a7.js new file mode 100644 index 0000000000..779eeadf6d --- /dev/null +++ b/assets/js/d784d738.71e628a7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7333],{5093:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>s,contentTitle:()=>a,default:()=>u,frontMatter:()=>r,metadata:()=>c,toc:()=>h});var i=o(5893),t=o(1151);const r={sidebar_position:1},a="Developing an ICS consumer chain",c={id:"consumer-development/app-integration",title:"Developing an ICS consumer chain",description:"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.",source:"@site/docs/consumer-development/app-integration.md",sourceDirName:"consumer-development",slug:"/consumer-development/app-integration",permalink:"/interchain-security/consumer-development/app-integration",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Power Shaping",permalink:"/interchain-security/features/power-shaping"},next:{title:"Consumer Chain Governance",permalink:"/interchain-security/consumer-development/consumer-chain-governance"}},s={},h=[{value:"Basic consumer chain",id:"basic-consumer-chain",level:2},{value:"Democracy consumer chain",id:"democracy-consumer-chain",level:2},{value:"Standalone chain to consumer chain changeover",id:"standalone-chain-to-consumer-chain-changeover",level:2}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",...(0,t.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"developing-an-ics-consumer-chain",children:"Developing an ICS consumer chain"}),"\n",(0,i.jsx)(n.p,{children:"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.\nTo help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications."}),"\n",(0,i.jsx)(n.h2,{id:"basic-consumer-chain",children:"Basic consumer chain"}),"\n",(0,i.jsxs)(n.p,{children:["The source code for the example app can be found ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer",children:"here"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["Please note that consumer chains do not implement the staking module - part of the validator set of the provider is replicated over to the consumer,\nmeaning that the consumer uses a subset of provider validator set and the stake of the validators on the provider determines their stake on the consumer.\nNote that after the introduction of ",(0,i.jsx)(n.a,{href:"/interchain-security/adrs/adr-015-partial-set-security",children:"Partial Set Security"}),", not all the provider validators have to validate a consumer chain (e.g., if ",(0,i.jsx)(n.code,{children:"top_N != 100"}),")."]}),"\n",(0,i.jsxs)(n.p,{children:["Your chain should import the consumer module from ",(0,i.jsx)(n.code,{children:"x/consumer"})," and register it in the correct places in your ",(0,i.jsx)(n.code,{children:"app.go"}),".\nThe ",(0,i.jsx)(n.code,{children:"x/consumer"})," module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in.\nYou should not need to manage or override any code from the ",(0,i.jsx)(n.code,{children:"x/consumer"})," module."]}),"\n",(0,i.jsx)(n.h2,{id:"democracy-consumer-chain",children:"Democracy consumer chain"}),"\n",(0,i.jsxs)(n.p,{children:["The source code for the example app can be found ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy",children:"here"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["This type of consumer chain wraps the basic CosmosSDK ",(0,i.jsx)(n.code,{children:"x/distribution"}),", ",(0,i.jsx)(n.code,{children:"x/staking"})," and ",(0,i.jsx)(n.code,{children:"x/governance"})," modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system."]}),"\n",(0,i.jsxs)(n.p,{children:["This allows the consumer chain to leverage those modules while also using the ",(0,i.jsx)(n.code,{children:"x/consumer"})," module."]}),"\n",(0,i.jsx)(n.p,{children:'With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.'}),"\n",(0,i.jsx)(n.h2,{id:"standalone-chain-to-consumer-chain-changeover",children:"Standalone chain to consumer chain changeover"}),"\n",(0,i.jsxs)(n.p,{children:["See the ",(0,i.jsx)(n.a,{href:"/interchain-security/consumer-development/changeover-procedure",children:"standalone chain to consumer chain changeover guide"})," for more information on how to transition your standalone chain to a consumer chain."]})]})}function u(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},1151:(e,n,o)=>{o.d(n,{Z:()=>c,a:()=>a});var i=o(7294);const t={},r=i.createContext(t);function a(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:a(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/da448d6e.641c7bd2.js b/assets/js/da448d6e.641c7bd2.js new file mode 100644 index 0000000000..65b4a4fb47 --- /dev/null +++ b/assets/js/da448d6e.641c7bd2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4744],{1974:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>t,metadata:()=>r,toc:()=>d});var o=i(5893),s=i(1151);const t={sidebar_position:4,title:"Equivocation governance proposal"},a="ADR 003: Equivocation governance proposal",r={id:"adrs/adr-003-equivocation-gov-proposal",title:"Equivocation governance proposal",description:"Changelog",source:"@site/versioned_docs/version-v5.0.0/adrs/adr-003-equivocation-gov-proposal.md",sourceDirName:"adrs",slug:"/adrs/adr-003-equivocation-gov-proposal",permalink:"/interchain-security/v5.0.0/adrs/adr-003-equivocation-gov-proposal",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Equivocation governance proposal"},sidebar:"tutorialSidebar",previous:{title:"Jail Throttling",permalink:"/interchain-security/v5.0.0/adrs/adr-002-throttle"},next:{title:"Cryptographic verification of equivocation evidence",permalink:"/interchain-security/v5.0.0/adrs/adr-005-cryptographic-equivocation-verification"}},c={},d=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function l(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"adr-003-equivocation-governance-proposal",children:"ADR 003: Equivocation governance proposal"}),"\n",(0,o.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"2023-02-06: Initial draft"}),"\n",(0,o.jsx)(n.li,{children:"2023-11-30: Change status to deprecated"}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,o.jsx)(n.p,{children:"Deprecated"}),"\n",(0,o.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.strong,{children:"Note:"})," ADR deprecated as the equivocation proposal was removed by the\ncryptographic verification of equivocation feature\n(see ",(0,o.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-005-cryptographic-equivocation-verification",children:"ADR-005"})," and\n",(0,o.jsx)(n.a,{href:"/interchain-security/v5.0.0/adrs/adr-013-equivocation-slashing",children:"ADR-013"}),")."]}),"\n",(0,o.jsx)(n.p,{children:"We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain."}),"\n",(0,o.jsx)(n.p,{children:"For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence."}),"\n",(0,o.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,o.jsx)(n.p,{children:"To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain."}),"\n",(0,o.jsxs)(n.p,{children:["A new kind of governance proposal is added to the ",(0,o.jsx)(n.code,{children:"provider"})," module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain."]}),"\n",(0,o.jsxs)(n.p,{children:["If such proposal passes, the proposal handler delegates to the ",(0,o.jsx)(n.code,{children:"evidence"})," module to process the equivocation. This module ensures the evidence isn\u2019t too old, or else ignores it (see ",(0,o.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/21021b837882d1d40f1d79bcbc4fad2e79a3fefe/x/evidence/keeper/infraction.go#L54-L62",children:"code"}),"). ",(0,o.jsx)(n.em,{children:"Too old"})," is determined by 2 consensus params :"]}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"evidence.max_age_duration"})," number of nanoseconds before an evidence is considered too old"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"evidence.max_age_numblocks"})," number of blocks before an evidence is considered too old."]}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:"On the hub, those parameters are equals to"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-json",children:'// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682\n(...)\n"evidence": {\n\t"max_age_num_blocks": "1000000",\n\t"max_age_duration": "172800000000000",\n (...)\n},\n(...)\n'})}),"\n",(0,o.jsxs)(n.p,{children:["A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the ",(0,o.jsx)(n.code,{children:"evidence"})," module when the proposal passes and is handled by the hub."]}),"\n",(0,o.jsxs)(n.p,{children:["For ",(0,o.jsx)(n.code,{children:"max_age_num_blocks=1M"}),", the parameter is big enough if we consider the hub produces 12k blocks per day (",(0,o.jsx)(n.code,{children:"blocks_per_year/365 = 436,0000/365"}),"). The evidence can be up to 83 days old (",(0,o.jsx)(n.code,{children:"1,000,000/12,000"}),") and not be ignored."]}),"\n",(0,o.jsxs)(n.p,{children:["For ",(0,o.jsx)(n.code,{children:"max_age_duration=172,800,000,000,000"}),", the parameter is too low, because the value is in nanoseconds so it\u2019s 2 days. Fortunately the condition that checks those 2 parameters uses a ",(0,o.jsx)(n.strong,{children:"AND"}),", so if ",(0,o.jsx)(n.code,{children:"max_age_num_blocks"})," condition passes, the evidence won\u2019t be ignored."]}),"\n",(0,o.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,o.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Remove the possibility from a malicious consumer chain to \u201cattack\u201d the provider chain by slashing/jailing validators."}),"\n",(0,o.jsx)(n.li,{children:"Provide a more acceptable implementation for the validator community."}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Punishment action of double-signing isn\u2019t \u201cautomated\u201d, a governance proposal is required which takes more time."}),"\n",(0,o.jsx)(n.li,{children:"You need to pay 250ATOM to submit an equivocation evidence."}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,o.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:["PR that ignores non downtime slash packet : ",(0,o.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/692",children:"https://github.com/cosmos/interchain-security/pull/692"})]}),"\n",(0,o.jsxs)(n.li,{children:["PR that adds the governance slash proposal: ",(0,o.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/703",children:"https://github.com/cosmos/interchain-security/pull/703"})]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>r,a:()=>a});var o=i(7294);const s={},t=o.createContext(s);function a(e){const n=o.useContext(t);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),o.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/dc9efaba.5a3ab637.js b/assets/js/dc9efaba.5a3ab637.js new file mode 100644 index 0000000000..8292321f20 --- /dev/null +++ b/assets/js/dc9efaba.5a3ab637.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1324],{38:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>c,contentTitle:()=>s,default:()=>p,frontMatter:()=>i,metadata:()=>a,toc:()=>d});var t=o(5893),r=o(1151);const i={sidebar_position:4,title:"Offboarding Checklist"},s="Consumer Offboarding",a={id:"consumer-development/offboarding",title:"Offboarding Checklist",description:"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).",source:"@site/docs/consumer-development/offboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/offboarding",permalink:"/interchain-security/consumer-development/offboarding",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Offboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Onboarding Checklist",permalink:"/interchain-security/consumer-development/onboarding"},next:{title:"Changeover Procedure",permalink:"/interchain-security/consumer-development/changeover-procedure"}},c={},d=[];function l(e){const n={code:"code",h1:"h1",p:"p",pre:"pre",...(0,r.a)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"consumer-offboarding",children:"Consumer Offboarding"}),"\n",(0,t.jsxs)(n.p,{children:["To offboard a consumer chain simply submit a ",(0,t.jsx)(n.code,{children:"ConsumerRemovalProposal"})," governance proposal listing a ",(0,t.jsx)(n.code,{children:"stop_time"}),". After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates)."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:'// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.\n// If it passes, all the consumer chain\'s state is removed from the provider chain. The outstanding unbonding\n// operation funds are released.\n{\n // the title of the proposal\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"More information will be listed in a future version of this document."})]})}function p(e={}){const{wrapper:n}={...(0,r.a)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},1151:(e,n,o)=>{o.d(n,{Z:()=>a,a:()=>s});var t=o(7294);const r={},i=t.createContext(r);function s(e){const n=t.useContext(i);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),t.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/ded36896.f0182e76.js b/assets/js/ded36896.f0182e76.js new file mode 100644 index 0000000000..ad69ef062a --- /dev/null +++ b/assets/js/ded36896.f0182e76.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7429],{2030:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>t,metadata:()=>r,toc:()=>c});var o=i(5893),s=i(1151);const t={sidebar_position:2,title:"Pause validator unbonding during equivocation proposal"},a="ADR 007: Pause validator unbonding during equivocation proposal",r={id:"adrs/adr-007-pause-unbonding-on-eqv-prop",title:"Pause validator unbonding during equivocation proposal",description:"Changelog",source:"@site/docs/adrs/adr-007-pause-unbonding-on-eqv-prop.md",sourceDirName:"adrs",slug:"/adrs/adr-007-pause-unbonding-on-eqv-prop",permalink:"/interchain-security/adrs/adr-007-pause-unbonding-on-eqv-prop",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"Pause validator unbonding during equivocation proposal"},sidebar:"tutorialSidebar",previous:{title:"Denom DOS fixes",permalink:"/interchain-security/adrs/adr-004-denom-dos-fixes"},next:{title:"Key Assignment",permalink:"/interchain-security/adrs/adr-001-key-assignment"}},d={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"How",id:"how",level:3},{value:"When pause",id:"when-pause",level:3},{value:"When unpause",id:"when-unpause",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function l(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"adr-007-pause-validator-unbonding-during-equivocation-proposal",children:"ADR 007: Pause validator unbonding during equivocation proposal"}),"\n",(0,o.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"2023-05-16: Initial Draft"}),"\n",(0,o.jsx)(n.li,{children:"2023-11-30: Change the status to rejected"}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,o.jsx)(n.p,{children:"Rejected"}),"\n",(0,o.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.strong,{children:"Note:"})," ADR rejected as the equivocation proposal was removed by the\ncryptographic verification of equivocation feature\n(see ",(0,o.jsx)(n.a,{href:"/interchain-security/adrs/adr-005-cryptographic-equivocation-verification",children:"ADR-005"})," and\n",(0,o.jsx)(n.a,{href:"/interchain-security/adrs/adr-013-equivocation-slashing",children:"ADR-013"}),")."]}),"\n",(0,o.jsx)(n.p,{children:"Currently, if an equivocation slashing proposal is created after more than one\nweek has passed since the equivocation, it is possible that the validator in\nquestion could unbond and get away without being slashed, since the unbonding\nperiod is 3 weeks, and the voting period is 2 weeks. For this reason, it might\nbe good to pause unbondings for validators named in an equivocation slashing\nproposal until the proposal's voting period is over."}),"\n",(0,o.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,o.jsx)(n.h3,{id:"how",children:"How"}),"\n",(0,o.jsxs)(n.p,{children:["Pausing the unbonding period is already possible thanks to the changes in the\n",(0,o.jsx)(n.code,{children:"staking"})," module of the cosmos-sdk:"]}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"stakingKeeper.PutUnbondingOnHold"})," pauses an unbonding period"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"stakingKeeper.UnbondingCanComplete"})," unpauses an unbonding period"]}),"\n"]}),"\n",(0,o.jsxs)(n.p,{children:["These methods use a reference counter under the hood, that gets incremented\nevery time ",(0,o.jsx)(n.code,{children:"PutUnbondingOnHold"})," is called, and decreased when\n",(0,o.jsx)(n.code,{children:"UnbondingCanComplete"})," is called instead. A specific unbonding is considered\nfully unpaused when its underlying reference counter reaches 0. Therefore, as\nlong as we safeguard consistency - i.e. we make sure we eventually decrement\nthe reference counter for each time we have incremented it - we can safely use\nthis existing mechanism without conflicts with the ",(0,o.jsx)(n.em,{children:"Completion of Unbonding\nOperations"})," system."]}),"\n",(0,o.jsx)(n.h3,{id:"when-pause",children:"When pause"}),"\n",(0,o.jsxs)(n.p,{children:["The unbonding period (if there is any unbonding) should be paused once an\nequivocation proposal enters the voting period. For that, the ",(0,o.jsx)(n.code,{children:"gov"})," module's\nhook ",(0,o.jsx)(n.code,{children:"AfterProposalDeposit"})," can be used."]}),"\n",(0,o.jsx)(n.p,{children:"If the hook is triggered with a an equivocation proposal in voting period, then\nfor each equivocation of the proposal, the unbonding operations of the related\nvalidator that were initiated after the equivocation block time must be paused"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"i.e. the underlying reference counter has to be increased."}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:"Note that even after the voting period has started, a proposal can receive\nadditional deposits. The hook is triggered however at arrival of a deposit, so\na check to verify that the proposal is not already in voting period is\nrequired."}),"\n",(0,o.jsx)(n.h3,{id:"when-unpause",children:"When unpause"}),"\n",(0,o.jsxs)(n.p,{children:["We can use a ",(0,o.jsx)(n.code,{children:"gov"})," module's hook also here and it is\n",(0,o.jsx)(n.code,{children:"AfterProposalVotingPeriodEnded"}),"."]}),"\n",(0,o.jsx)(n.p,{children:"If the hook is triggered with an equivocation proposal, then for each\nassociated equivocation, the unbonding operations of the related validator that\nwere initiated between the equivocation block time and the start of the\nproposal voting period must be unpaused - i.e. decrease the underlying\nreference counter - regardless of the proposal outcome."}),"\n",(0,o.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,o.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Validators subject to an equivocation proposal cannot finish unbonding\ntheir tokens before the end of the voting period."}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"A malicious consumer chain could forge slash packets enabling submission of\nan equivocation proposal on the provider chain, resulting in the freezing of\nvalidator's unbondings for an undeterminated amount of time."}),"\n",(0,o.jsx)(n.li,{children:"Misbehavior on a consumer chain can potentially go unpunished, if no one\nsubmits an equivocation proposal in time, or if the proposal doesn't pass."}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"This feature can't be used for social slashing, because an equivocation\nproposal is only accepted if there's a slash log for the related\nvalidator(s), meaning the consumer chain has reported the equivocation to\nthe provider chain."}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/747",children:"https://github.com/cosmos/interchain-security/issues/747"})}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/pull/791",children:"https://github.com/cosmos/interchain-security/pull/791"})}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>r,a:()=>a});var o=i(7294);const s={},t=o.createContext(s);function a(e){const n=o.useContext(t);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),o.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/ded5fac2.f0ee3953.js b/assets/js/ded5fac2.f0ee3953.js new file mode 100644 index 0000000000..2858b66e3f --- /dev/null +++ b/assets/js/ded5fac2.f0ee3953.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2383],{4249:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>h});var a=i(5893),n=i(1151);const o={sidebar_position:5},r="Partial Set Security",s={id:"features/partial-set-security",title:"Partial Set Security",description:"Partial Set Security (PSS) allows consumer chains to leverage only a subset of validators from the provider chain, which offers more flexibility than the traditional Replicated Security model. By introducing the top_N parameter, each consumer chain can choose the extent of security needed:",source:"@site/versioned_docs/version-v4.2.0-docs/features/partial-set-security.md",sourceDirName:"features",slug:"/features/partial-set-security",permalink:"/interchain-security/v4.2.0/features/partial-set-security",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/v4.2.0/features/slashing"},next:{title:"Power Shaping",permalink:"/interchain-security/v4.2.0/features/power-shaping"}},c={},h=[];function l(e){const t={admonition:"admonition",code:"code",h1:"h1",li:"li",p:"p",ul:"ul",...(0,n.a)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h1,{id:"partial-set-security",children:"Partial Set Security"}),"\n",(0,a.jsx)(t.p,{children:"Partial Set Security (PSS) allows consumer chains to leverage only a subset of validators from the provider chain, which offers more flexibility than the traditional Replicated Security model. By introducing the top_N parameter, each consumer chain can choose the extent of security needed:"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:["\n",(0,a.jsx)(t.p,{children:"Top N: Requires the top N% validators from the provider chain to secure the consumer chain. This guarantees that the validators with the most power on the provider will validate the consumer chain, while others can voluntarily opt in."}),"\n"]}),"\n",(0,a.jsxs)(t.li,{children:["\n",(0,a.jsxs)(t.p,{children:["Opt-In: If the ",(0,a.jsx)(t.code,{children:"top_N"})," parameter is set to zero, no validator is mandated to secure the consumer chain. Instead, any validator from the provider chain can opt in using a dedicated transaction."]}),"\n"]}),"\n"]}),"\n",(0,a.jsx)(t.p,{children:"An advantage of a Top N chain is that the consumer chain is guaranteed to receive at least a certain fraction of the market cap of the provider chain in security. In turn, this chain needs to be approved by governance, since validators will be forced to run the chain. Thus, Top N chains should typically expect to need to provide a strong case for why they should be added to the provider chain, and they should make sure they offer enough rewards to incentivize validators and delegators to vote for their proposal."}),"\n",(0,a.jsx)(t.p,{children:"Opt-In chains, on the other hand, are more flexible. While for technical reasons, they are also currently added via governance proposals, since validators are never forced to validate these chains and simply opt in if they want to, they should typically expect to get their proposals approved much more easily compared to Top N chains, since validators that do not want to validate the chain can simply choose not to opt in.\nHowever, opt in chains do not get a fixed amount of security as a relation of the market cap of the provider as top N chains do, so opt in chains might want to keep an eye on how many validators have opted in to validate their chain and adjust their reward emissions accordingly to incentivize validators."}),"\n",(0,a.jsx)(t.admonition,{type:"tip",children:(0,a.jsx)(t.p,{children:"Partial Set Security is handled only by the provider chain - the consumer chains are simply sent validator sets, and they are not aware that this represents only a subset of the provider chain's validator set."})}),"\n",(0,a.jsxs)(t.admonition,{type:"caution",children:[(0,a.jsx)(t.p,{children:"Both Opt In and Top N chains currently require a governance proposal to be added to the provider chain."}),(0,a.jsx)(t.p,{children:"For Top N chains, this is also the long term vision for how they are launched."}),(0,a.jsx)(t.p,{children:"For Opt In chains, this is a temporary measure to prevent issues around chain ID squatting, i.e. someone could spuriously register many desirable chain IDs of upcoming consumer chain and simply deny legitimate consumer chains from using them. Eventually, the plan is to allow launching Opt In chains permissionlessly without going through governance, with quality control being handled by the market of validators deciding which chains they would like to validate on."})]})]})}function d(e={}){const{wrapper:t}={...(0,n.a)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(l,{...e})}):l(e)}},1151:(e,t,i)=>{i.d(t,{Z:()=>s,a:()=>r});var a=i(7294);const n={},o=a.createContext(n);function r(e){const t=a.useContext(o);return a.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function s(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:r(e.components),a.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e005c37e.7aec7bcf.js b/assets/js/e005c37e.7aec7bcf.js new file mode 100644 index 0000000000..9f201f6cf3 --- /dev/null +++ b/assets/js/e005c37e.7aec7bcf.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2883],{5837:(e,i,t)=>{t.r(i),t.d(i,{assets:()=>r,contentTitle:()=>a,default:()=>d,frontMatter:()=>o,metadata:()=>c,toc:()=>h});var n=t(5893),s=t(1151);const o={sidebar_position:4,title:"Cryptographic verification of equivocation evidence"},a="ADR 005: Cryptographic verification of equivocation evidence",c={id:"adrs/adr-005-cryptographic-equivocation-verification",title:"Cryptographic verification of equivocation evidence",description:"Changelog",source:"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-005-cryptographic-equivocation-verification.md",sourceDirName:"adrs",slug:"/adrs/adr-005-cryptographic-equivocation-verification",permalink:"/interchain-security/v4.2.0/adrs/adr-005-cryptographic-equivocation-verification",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Cryptographic verification of equivocation evidence"},sidebar:"tutorialSidebar",previous:{title:"Equivocation governance proposal",permalink:"/interchain-security/v4.2.0/adrs/adr-003-equivocation-gov-proposal"},next:{title:"Throttle with retries",permalink:"/interchain-security/v4.2.0/adrs/adr-008-throttle-retries"}},r={},h=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Light Client Attack",id:"light-client-attack",level:3},{value:"Double Signing Attack",id:"double-signing-attack",level:3},{value:"Decision",id:"decision",level:2},{value:"Light Client Attack",id:"light-client-attack-1",level:3},{value:"Double Signing Attack",id:"double-signing-attack-1",level:3},{value:"Current limitations:",id:"current-limitations",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}];function l(e){const i={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,s.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(i.h1,{id:"adr-005-cryptographic-verification-of-equivocation-evidence",children:"ADR 005: Cryptographic verification of equivocation evidence"}),"\n",(0,n.jsx)(i.h2,{id:"changelog",children:"Changelog"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsx)(i.li,{children:"5/1/2023: First draft"}),"\n",(0,n.jsx)(i.li,{children:"7/23/2023: Add light client attacks handling"}),"\n",(0,n.jsx)(i.li,{children:"9/6/2023: Add double signing attacks handling"}),"\n",(0,n.jsx)(i.li,{children:"11/3/2023: Update limitations to clarify amnesia attacks are ignored"}),"\n"]}),"\n",(0,n.jsx)(i.h2,{id:"status",children:"Status"}),"\n",(0,n.jsx)(i.p,{children:"Accepted"}),"\n",(0,n.jsx)(i.h2,{id:"context",children:"Context"}),"\n",(0,n.jsx)(i.p,{children:"Currently, we use a governance proposal to slash validators for equivocation (double signing and light client attacks).\nEvery proposal needs to go through a (two weeks) voting period before it can be approved.\nGiven a three-week unbonding period, this means that an equivocation proposal needs to be submitted within one week since the infraction occurred."}),"\n",(0,n.jsx)(i.p,{children:"This ADR proposes a system to slash validators automatically for equivocation, immediately upon the provider chain's receipt of the evidence. Another thing to note is that we intend to introduce this system in stages, since even the partial ability to slash and/or tombstone is a strict improvement in security.\nThe feature is implemented in two parts, each with its dedicated endpoint. One endpoint handles light client attacks, while the other handles double signing attacks."}),"\n",(0,n.jsx)(i.h3,{id:"light-client-attack",children:"Light Client Attack"}),"\n",(0,n.jsx)(i.p,{children:"In a nutshell, the light client is a process that solely verifies a specific state machine's\nconsensus without executing the transactions. The light clients get new headers by querying\nmultiple nodes, called primary and witness nodes."}),"\n",(0,n.jsxs)(i.p,{children:["Light clients download new headers committed on chain from a primary. Headers can be verified in two ways: sequentially,\nwhere the block height of headers is serial, or using skipping. This second verification method allows light clients to download headers\nwith nonconsecutive block height, where some intermediate headers are skipped (see ",(0,n.jsx)(i.a,{href:"https://arxiv.org/pdf/2010.07031.pdf",children:"Tendermint Light Client, Figure 1 and Figure 3"}),").\nAdditionally, light clients are cross-checking new headers obtained from a primary with witnesses to ensure all nodes share the same state."]}),"\n",(0,n.jsxs)(i.p,{children:["A light client attack occurs when a Byzantine validator sends invalid headers to a light client.\nAs the light client doesn't execute transactions, it can be deceived into trusting corrupted application state transitions.\nFor instance, if a light client receives header ",(0,n.jsx)(i.code,{children:"A"})," from the primary and header ",(0,n.jsx)(i.code,{children:"B"})," from a witness for the same block height ",(0,n.jsx)(i.code,{children:"H"}),",\nand both headers are successfully verified, it indicates a light client attack.\nNote that in this case, either the primary or the witness or both are malicious."]}),"\n",(0,n.jsxs)(i.p,{children:["The types of light client attacks are defined by analyzing the differences between the conflicting headers.\nThere are three types of light client attacks: lunatic attack, equivocation attack, and amnesia attack.\nFor details, see the ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/main/spec/light-client/attacks/notes-on-evidence-handling.md#evidence-handling",children:"CometBFT specification"}),"."]}),"\n",(0,n.jsxs)(i.p,{children:["When a light client agent detects two conflicting headers, it will initially verify their traces (see ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/light/detector.go#L28",children:"cometBFT detector"}),") using its primary and witness nodes.\nIf these headers pass successful verification, the Byzantine validators will be identified based on the header's commit signatures\nand the type of light client attack. The agent will then transmit this information to its nodes using a ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#light-client-attacks",children:(0,n.jsx)(i.code,{children:"LightClientAttackEvidence"})})," evidence to be eventually voted on and added to a block.\nNote that from a light client agent perspective, it is not possible to establish whether a primary or a witness node, or both, are malicious.\nTherefore, it will create and send two evidences: one against the primary (sent to the witness), and one against the witness (sent to the primary).\nBoth nodes will then verify it before broadcasting it and adding it to the ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/evidence/pool.go#L28",children:"evidence pool"}),".\nIf an evidence is finally committed to a block, the chain's evidence module will execute it, resulting in the jailing and the slashing of the validators responsible for the light client attack."]}),"\n",(0,n.jsxs)(i.p,{children:["Light clients are a core component of IBC. In the event of a light client attack, IBC relayers notify the affected chains by submitting an ",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/ibc-go/blob/v4.4.2/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79",children:"IBC misbehavior message"}),".\nA misbehavior message includes the conflicting headers that constitute a light client attack evidence. Upon receiving such a message,\na chain will first verify whether these headers would have convinced its light client. This verification is achieved by checking\nthe header states against the light client consensus states (see ",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/ibc-go/blob/v4.4.2/modules/light-clients/07-tendermint/types/misbehaviour_handle.go#L24",children:"IBC misbehaviour handler"}),'). If the misbehaviour is successfully verified, the chain will then "freeze" the\nlight client, halting any further trust in or updating of its states.']}),"\n",(0,n.jsx)(i.h3,{id:"double-signing-attack",children:"Double Signing Attack"}),"\n",(0,n.jsxs)(i.p,{children:["A double signing attack, also known as equivocation,\noccurs when a validator votes for two different blocks in the same round of the CometBFT consensus.\nThis consensus mechanism operates with multiple voting rounds at each block height,\nand it strictly prohibits sending two votes of the same type during a round\n(see ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/consensus.md#state-machine-overview",children:"CometBFT State Machine Overview"}),")."]}),"\n",(0,n.jsxs)(i.p,{children:["When a node observes two votes from the same peer, it will use these two votes to create\na ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/types/evidence.go#L35",children:(0,n.jsx)(i.code,{children:"DuplicateVoteEvidence"})}),"\nevidence and gossip it to the other nodes in the network\n(see ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#detection",children:"CometBFT equivocation detection"}),").\nEach node will then verify the evidence according to the CometBFT rules that define a valid double signing infraction, and based on this verification, they will decide whether to add the evidence to a block.\nDuring the evidence verification process, the signatures of the conflicting votes must be verified successfully.\nNote that this is achieved using the public key of the misbehaving validator, along with the chain ID of the chain where the infraction occurred (see ",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#verification",children:"CometBFT equivocation verification"}),")."]}),"\n",(0,n.jsxs)(i.p,{children:["Once a double signing evidence is committed to a block, the consensus layer will report the equivocation to the evidence module of the Cosmos SDK application layer.\nThe application will, in turn, punish the malicious validator through jailing, tombstoning and slashing\n(see ",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/evidence/keeper/infraction.go#L263",children:"handleEquivocationEvidence"}),")."]}),"\n",(0,n.jsx)(i.h2,{id:"decision",children:"Decision"}),"\n",(0,n.jsx)(i.h3,{id:"light-client-attack-1",children:"Light Client Attack"}),"\n",(0,n.jsxs)(i.p,{children:["In the first part of the feature, we introduce a new endpoint: ",(0,n.jsx)(i.code,{children:"HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour)"}),".\nThe main idea is to leverage the current IBC misbehaviour handling and update it to solely jail and slash the validators that\nperformed a light client attack. Note that in this context, we assume that chains connected via a light client\nshare the same validator set, as is the case with Replicated Security."]}),"\n",(0,n.jsx)(i.p,{children:"This endpoint reuses the IBC client libraries to verify that the misbehaviour headers would have fooled the light client.\nAdditionally, it\u2019s crucial that the endpoint logic results in the slashing and jailing of validators under the same conditions\nas a light client agent detector. Therefore, the endpoint ensures that the two conditions are met:\nthe headers in the misbehaviour message have the same block height, and\nthe light client isn\u2019t expired."}),"\n",(0,n.jsx)(i.p,{children:"After having successfully verified a misbehaviour, the endpoint executes the jailing and slashing of the malicious validators similarly as in the evidence module."}),"\n",(0,n.jsx)(i.h3,{id:"double-signing-attack-1",children:"Double Signing Attack"}),"\n",(0,n.jsxs)(i.p,{children:["In the second part of the feature, we introduce a new endpoint ",(0,n.jsx)(i.code,{children:"HandleConsumerDoubleVoting( ctx sdk.Context, evidence *tmtypes.DuplicateVoteEvidence, chainID string, pubkey cryptotypes.PubKey)"}),".\nSimply put, the handling logic verifies a double signing evidence against a provided\npublic key and chain ID and, if successful, executes the jailing of the malicious validator who double voted."]}),"\n",(0,n.jsxs)(i.p,{children:["We define a new\n",(0,n.jsx)(i.code,{children:"MsgSubmitConsumerDoubleVoting"})," message to report a double voting evidence observed\non a consumer chain to the endpoint of the provider chain. This message contains two fields:\na double signing evidence\n",(0,n.jsx)(i.code,{children:"duplicate_vote_evidence"})," and a light client header for the infraction block height,\nreferred to as ",(0,n.jsx)(i.code,{children:"infraction_block_header"}),".\nThe latter provides the malicious validator's public key and the chain ID required to verify the signature of the votes contained in the evidence."]}),"\n",(0,n.jsxs)(i.p,{children:["Note that double signing evidence is not verified using the same conditions as in the implementation CometBFT (see\n",(0,n.jsx)(i.a,{href:"https://github.com/cometbft/cometbft/blob/v0.34.28/evidence/verify.go#L19",children:(0,n.jsx)(i.code,{children:"verify(evidence types.Evidence)"})})," method). Specifically, we do not check that the evidence hasn't expired.\nMore details can be found in the ",(0,n.jsx)(i.a,{href:"#current-limitations",children:'"Current limitations"'})," section below."]}),"\n",(0,n.jsxs)(i.p,{children:["Upon a successful equivocation verification, the misbehaving validator is jailed for the maximum time\n(see ",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/evidence/types/params.go#L11",children:"DoubleSignJailEndTime"}),"\nin the SDK evidence module)."]}),"\n",(0,n.jsx)(i.h3,{id:"current-limitations",children:"Current limitations:"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsxs)(i.li,{children:["\n",(0,n.jsx)(i.p,{children:"We cannot derive an infraction height from the evidence, so it is only possible to jail validators, not actually slash them.\nTo explain the technical reasons behind this limitation, let's recap the initial consumer initiated slashing logic.\nIn a nutshell, consumer heights are mapped to provider heights through VSCPackets, namely through the so called vscIDs.\nWhen an infraction occurs on the consumer, a SlashPacket containing the vscID obtained from mapping the consumer infraction height\nis sent to the provider. Upon receiving the packet, the provider maps the consumer infraction height to a local infraction height,\nwhich is used to slash the misbehaving validator. In the context of untrusted consumer chains, all their states, including vscIDs,\ncould be corrupted and therefore cannot be used for slashing purposes."}),"\n"]}),"\n",(0,n.jsxs)(i.li,{children:["\n",(0,n.jsx)(i.p,{children:"For the same reasons explained above, the age of a consumer double signing evidence can't be verified,\neither using its infraction height or its unsigned timestamp. Note that changes the jailing behaviour, potentially leading to a validator's jailing based on some \"old\" evidence from a consumer, which wouldn't occur if the consumer were a standalone chain."}),"\n"]}),"\n",(0,n.jsxs)(i.li,{children:["\n",(0,n.jsxs)(i.p,{children:["In the first stage of this feature, validators are jailed indefinitely without being tombstoned.\nThe underlying reason is that a malicious validator could take advantage of getting tombstoned\nto avoid being slashed on the provider (",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/interchain-security/pull/1232#issuecomment-1693127641",children:"see comment"}),")."]}),"\n"]}),"\n",(0,n.jsxs)(i.li,{children:["\n",(0,n.jsxs)(i.p,{children:["Currently, the endpoint can only handle ",(0,n.jsx)(i.em,{children:"equivocation"})," light client attacks. This is because the ",(0,n.jsx)(i.em,{children:"lunatic"})," attacks require the endpoint to possess the ability to dissociate which header is conflicted or trusted upon receiving a misbehavior message. Without this information, it's not possible to extract the Byzantine validators from the conflicting headers (see ",(0,n.jsx)(i.a,{href:"https://github.com/cosmos/interchain-security/pull/826#discussion_r1268668684",children:"comment"}),'). In addition, "amnesia" attacks are ignored, similar to CometBFT (see ',(0,n.jsx)(i.a,{href:"https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-047-handling-evidence-from-light-client.md#negative",children:"ADR-056"}),")."]}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(i.h2,{id:"consequences",children:"Consequences"}),"\n",(0,n.jsx)(i.h3,{id:"positive",children:"Positive"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsx)(i.li,{children:"It is now possible for the provider chain to jail validators who committed\nlight client or double signing attacks on a consumer chain."}),"\n"]}),"\n",(0,n.jsx)(i.h3,{id:"negative",children:"Negative"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsx)(i.li,{children:"N/A"}),"\n"]}),"\n",(0,n.jsx)(i.h2,{id:"references",children:"References"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://github.com/cosmos/interchain-security/pull/826",children:"ICS misbehaviour handling PR"})}),"\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://github.com/cosmos/interchain-security/pull/1232",children:"Consumer double voting handler PR"})}),"\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://docs.google.com/document/d/1fe1uSJl1ZIYWXoME3Yf4Aodvz7V597Ric875JH-rigM/edit#heading=h.rv4t8i6d6jfn",children:"Architectural diagrams"})}),"\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-013-equivocation-slashing.md",children:"ADR on equivocation slashing"})}),"\n"]})]})}function d(e={}){const{wrapper:i}={...(0,s.a)(),...e.components};return i?(0,n.jsx)(i,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},1151:(e,i,t)=>{t.d(i,{Z:()=>c,a:()=>a});var n=t(7294);const s={},o=n.createContext(s);function a(e){const i=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function c(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),n.createElement(o.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e0ad375d.01b8369f.js b/assets/js/e0ad375d.01b8369f.js new file mode 100644 index 0000000000..53aa066706 --- /dev/null +++ b/assets/js/e0ad375d.01b8369f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1840],{3978:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>s,metadata:()=>r,toc:()=>d});var n=o(5893),i=o(1151);const s={sidebar_position:10,title:"Soft Opt-Out"},a=void 0,r={id:"adrs/adr-009-soft-opt-out",title:"Soft Opt-Out",description:"ADR 009: Soft Opt-Out",source:"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-009-soft-opt-out.md",sourceDirName:"adrs",slug:"/adrs/adr-009-soft-opt-out",permalink:"/interchain-security/v4.2.0/adrs/adr-009-soft-opt-out",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:10,frontMatter:{sidebar_position:10,title:"Soft Opt-Out"},sidebar:"tutorialSidebar",previous:{title:"Throttle with retries",permalink:"/interchain-security/v4.2.0/adrs/adr-008-throttle-retries"},next:{title:"Standalone to Consumer Changeover",permalink:"/interchain-security/v4.2.0/adrs/adr-010-standalone-changeover"}},l={},d=[{value:"ADR 009: Soft Opt-Out",id:"adr-009-soft-opt-out",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function c(e){const t={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,i.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h2,{id:"adr-009-soft-opt-out",children:"ADR 009: Soft Opt-Out"}),"\n",(0,n.jsx)(t.h2,{id:"changelog",children:"Changelog"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"6/13/23: Initial draft of ADR. Feature already implemented and in production."}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"status",children:"Status"}),"\n",(0,n.jsx)(t.p,{children:"Accepted"}),"\n",(0,n.jsx)(t.h2,{id:"context",children:"Context"}),"\n",(0,n.jsxs)(t.p,{children:["Some small validators may not have the resources needed to validate all consumer chains. Therefore a need exists to allow the bottom ",(0,n.jsx)(t.code,{children:"x%"})," of validators to opt-out of validating a consumer chain. Meaning downtime infractions for these validators are dropped without ever reaching the provider."]}),"\n",(0,n.jsx)(t.p,{children:"This document specifies a modification to the ccv protocol which allows the bottom x% of the validator set by power to opt out of validating consumer chains without being jailed or otherwise punished for it. The feature is implemented with entirely consumer-side code."}),"\n",(0,n.jsx)(t.h2,{id:"decision",children:"Decision"}),"\n",(0,n.jsxs)(t.p,{children:["A consumer param exists, known as ",(0,n.jsx)(t.code,{children:"SoftOptOutThreshold"}),", which is a string decimal in the range of [0, 0.2], that determines the portion of validators which are allowed to opt out of validating that specific consumer."]}),"\n",(0,n.jsxs)(t.p,{children:["In every consumer beginblocker, a function is ran which determines the so called ",(0,n.jsx)(t.em,{children:"smallest non opt-out voting power"}),". Validators with voting power greater than or equal to this value must validate the consumer chain, while validators below this value may opt out of validating the consumer chain."]}),"\n",(0,n.jsxs)(t.p,{children:["The smallest non opt-out voting power is recomputed every beginblocker in ",(0,n.jsx)(t.code,{children:"UpdateSmallestNonOptOutPower()"}),". In a nutshell, the method obtains the total voting power of the consumer, iterates through the full valset (ordered power ascending) keeping track of a power sum, and when ",(0,n.jsx)(t.code,{children:"powerSum / totalPower > SoftOptOutThreshold"}),", the ",(0,n.jsx)(t.code,{children:"SmallestNonOptOutPower"})," is found and persisted."]}),"\n",(0,n.jsxs)(t.p,{children:["Then, whenever the ",(0,n.jsx)(t.code,{children:"Slash()"})," interface is executed on the consumer, if the voting power of the relevant validator being slashed is less than ",(0,n.jsx)(t.code,{children:"SmallestNonOptOutPower"})," for that block, the slash request is dropped and never sent to the provider."]}),"\n",(0,n.jsx)(t.h2,{id:"consequences",children:"Consequences"}),"\n",(0,n.jsx)(t.h3,{id:"positive",children:"Positive"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"Small validators can opt out of validating specific consumers without being punished for it."}),"\n"]}),"\n",(0,n.jsx)(t.h3,{id:"negative",children:"Negative"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["The bottom ",(0,n.jsx)(t.code,{children:"x%"})," is still part of the total voting power of the consumer chain. This means that if the soft opt-out threshold is set to ",(0,n.jsx)(t.code,{children:"10%"})," for example, and every validator in the bottom ",(0,n.jsx)(t.code,{children:"10%"})," opts out from validating the consumer, then a ",(0,n.jsx)(t.code,{children:"24%"})," downtime of the remaining voting power would halt the chain. This may be especially problematic during consumer upgrades."]}),"\n",(0,n.jsxs)(t.li,{children:["In nominal scenarios, consumers with soft opt out enabled will be constructing slash packets for small vals, which may be dropped. This is wasted computation, but necessary to keep implementation simple. Note that the sdk's ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/d3f09c222243bb3da3464969f0366330dcb977a8/x/slashing/keeper/infractions.go#L75",children:"full downtime logic"})," is always executed on the consumer, which can be computationally expensive and slow down certain blocks."]}),"\n",(0,n.jsx)(t.li,{children:"In a consumer chain, when a validator that has opted out becomes the proposer, there will naturally be no proposal made and validators would need to move to the next consensus round for the same height to reach a decision. As a result, we would need more time to finalize blocks on a consumer chain."}),"\n"]}),"\n",(0,n.jsx)(t.h3,{id:"neutral",children:"Neutral"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"Validators in the bottom of the valset who don't have to validate, may receive large delegation(s) which suddenly boost the validator to the subset that has to validate. This may catch the validator off guard."}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"references",children:"References"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["Original issue with some napkin math ",(0,n.jsx)(t.a,{href:"https://github.com/cosmos/interchain-security/issues/784",children:"#784"})]}),"\n"]})]})}function h(e={}){const{wrapper:t}={...(0,i.a)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(c,{...e})}):c(e)}},1151:(e,t,o)=>{o.d(t,{Z:()=>r,a:()=>a});var n=o(7294);const i={},s=n.createContext(i);function a(e){const t=n.useContext(s);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),n.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e2ddbbfd.d395360c.js b/assets/js/e2ddbbfd.d395360c.js new file mode 100644 index 0000000000..f51de25daf --- /dev/null +++ b/assets/js/e2ddbbfd.d395360c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8892],{2005:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>d,contentTitle:()=>o,default:()=>c,frontMatter:()=>s,metadata:()=>r,toc:()=>l});var a=i(5893),n=i(1151);const s={sidebar_position:18,title:"ICS with Inactive Provider Validators"},o="ADR 017: ICS with Inactive Provider Validators",r={id:"adrs/adr-017-allowing-inactive-validators",title:"ICS with Inactive Provider Validators",description:"Changelog",source:"@site/docs/adrs/adr-017-allowing-inactive-validators.md",sourceDirName:"adrs",slug:"/adrs/adr-017-allowing-inactive-validators",permalink:"/interchain-security/adrs/adr-017-allowing-inactive-validators",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:18,frontMatter:{sidebar_position:18,title:"ICS with Inactive Provider Validators"},sidebar:"tutorialSidebar",previous:{title:"Security aggregation",permalink:"/interchain-security/adrs/adr-016-securityaggregation"}},d={},l=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Changes to the state",id:"changes-to-the-state",level:3},{value:"Risk Mitigations",id:"risk-mitigations",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Sybil attacks",id:"sybil-attacks",level:4},{value:"Reputational damage is not a deterrent",id:"reputational-damage-is-not-a-deterrent",level:4},{value:"Additional negative consequences",id:"additional-negative-consequences",level:4},{value:"Neutral",id:"neutral",level:3},{value:"Alternative considerations",id:"alternative-considerations",level:2},{value:"Modifying the staking module",id:"modifying-the-staking-module",level:3},{value:"Allowing unbonding validators to validate",id:"allowing-unbonding-validators-to-validate",level:3},{value:"References",id:"references",level:2}];function h(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",img:"img",li:"li",p:"p",ul:"ul",...(0,n.a)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h1,{id:"adr-017-ics-with-inactive-provider-validators",children:"ADR 017: ICS with Inactive Provider Validators"}),"\n",(0,a.jsx)(t.h2,{id:"changelog",children:"Changelog"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsx)(t.li,{children:"15th May 2024: Initial draft"}),"\n"]}),"\n",(0,a.jsx)(t.h2,{id:"status",children:"Status"}),"\n",(0,a.jsx)(t.p,{children:"Proposed"}),"\n",(0,a.jsx)(t.h2,{id:"context",children:"Context"}),"\n",(0,a.jsx)(t.p,{children:"Currently, only validators in the active set on the provider can validate on consumer chains, which limits the number of validators that can participate in Interchain Security (ICS).\nValidators outside of the active set might be willing\nto validate on consumer chains, but we might not want to make the provider validator set larger, e.g. to not put more strain on the consensus engine.\nThis runs the risk of leaving consumer chains with too few validators."}),"\n",(0,a.jsxs)(t.p,{children:["The purpose of this ADR is to allow validators that are ",(0,a.jsx)(t.em,{children:"not"})," part of the consensus process on the provider chain (because they are inactive)\nto validate on consumer chains."]}),"\n",(0,a.jsx)(t.p,{children:'In the context of this ADR, "consensus validator set" is the set of validators participating in the consensus protocol, and "staking validator set" is the set of validators viewed as active by the staking module.'}),"\n",(0,a.jsx)(t.p,{children:"Currently, the staking module, provider module, and CometBFT interact in this way:"}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.img,{alt:"inactivevals_before.png",src:i(4823).Z+"",width:"874",height:"723"})}),"\n",(0,a.jsxs)(t.p,{children:["The staking module keeps a list of validators. The ",(0,a.jsx)(t.code,{children:"MaxValidators"}),' validators with the largest amount of stake are "active" validators. ',(0,a.jsx)(t.code,{children:"MaxValidators"})," is a parameter of the staking module. The staking module sends these validators to CometBFT to inform which validators make up the next consensus validators, that is, the set of validators participating in the consensus process. Separately, the provider module reads the list of bonded validators and sends this to the consumer chain, after shaping it according to which validators are opted in and the parameters set by the consumer chain for allowlist, denylist, etc."]}),"\n",(0,a.jsx)(t.h2,{id:"decision",children:"Decision"}),"\n",(0,a.jsx)(t.p,{children:"The proposed solution to allow validators that are not participating in the consensus process on the provider (inactive validators) is to change 3 main things:"}),"\n",(0,a.jsxs)(t.p,{children:["a) increase the ",(0,a.jsx)(t.code,{children:"MaxValidators"})," parameter of the staking module"]}),"\n",(0,a.jsxs)(t.p,{children:["b) do ",(0,a.jsx)(t.em,{children:"not"})," take the updates for CometBFT directly from the bonded validators in the staking module, by wrapping the staking modules ",(0,a.jsx)(t.code,{children:"EndBlocker"})," with a dummy EndBlocker that doesn't return any validator updates. Instead, we adjust the provider module to return validator updates on its EndBlocker. These validator updates are obtained by ",(0,a.jsx)(t.em,{children:"filtering"})," the bonded validators to send only the first ",(0,a.jsx)(t.code,{children:"MaxProviderConsensusValidators"})," (sorted by largest amount of stake first) many validators to CometBFT"]}),"\n",(0,a.jsx)(t.p,{children:"c) use the enlarged list of bonded validators from the staking module as basis for the validator set that the provider module sends to consumer chains (again after applying power shaping and filtering out validatiors that are not opted in)."}),"\n",(0,a.jsx)(t.p,{children:"In consequence, the provider chain can keep a reasonably-sized consensus validator set, while giving consumer chains a much larger pool of potential validators."}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.img,{alt:"inactivevals_after.png",src:i(9022).Z+"",width:"874",height:"723"})}),"\n",(0,a.jsx)(t.p,{children:"Some additional considerations:"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsx)(t.li,{children:"Migration: In the migration, the last consensus validator set will be set to the last active validator set from the view of the staking module. Existing consumer chains are migrated to have a validator set size cap (otherwise, they could end up with a huge validator set including all the staking-but-not-consensus-active validators from the provider chain)"}),"\n",(0,a.jsxs)(t.li,{children:["Slashing: Validators that are not part of the active set on the provider chain can still be jailed for downtime on a consumer chain (via an Interchain Security SlashPacket sent to the provider, who will then jail the validator), but they ",(0,a.jsx)(t.em,{children:"are not"})," slashed for downtime on the provider chain.\nThis is achieved without any additional changes to the slashing module, because the slashing module checks for downtime by looking at the consensus participants reported by CometBFT, and thus with the proposed solution, validators that are not part of the consensus validators on the provider chain are not considered for downtime slashing (see ",(0,a.jsx)(t.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.11/x/slashing/abci.go#L22",children:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.11/x/slashing/abci.go#L22"}),")."]}),"\n",(0,a.jsxs)(t.li,{children:["Rewards: Validators that are not part of the active set on the provider chain can still receive rewards on the consumer chain, but they ",(0,a.jsx)(t.em,{children:"do not"})," receive rewards from the provider chain. This change is\nachieved without further changes to staking or reward distributions, because similar to downtime, rewards are based on the consensus validator set (see ",(0,a.jsx)(t.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.11/x/distribution/abci.go#L28",children:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.11/x/distribution/abci.go#L28"}),")"]}),"\n"]}),"\n",(0,a.jsx)(t.h3,{id:"changes-to-the-state",children:"Changes to the state"}),"\n",(0,a.jsx)(t.p,{children:"The following changes to the state are required:"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:["Introduce the ",(0,a.jsx)(t.code,{children:"MaxProviderConsensusValidators"})," parameter to the provider module, which is the number of validators that the provider module will send to consumer chains."]}),"\n",(0,a.jsxs)(t.li,{children:["Store the provider consensus validator set in the provider module state under the ",(0,a.jsx)(t.code,{children:"LastProviderConsensusValsPrefix"})," key. This is the last set of validators that the provider sent to the consensus engine. This is needed to compute the ValUpdates to send to the consensus engine (by diffing the current set with this last sent set)."]}),"\n",(0,a.jsxs)(t.li,{children:["Increase the ",(0,a.jsx)(t.code,{children:"MaxValidators"})," parameter of the staking module to the desired size of the potential validator\nset of consumer chains."]}),"\n"]}),"\n",(0,a.jsx)(t.h2,{id:"risk-mitigations",children:"Risk Mitigations"}),"\n",(0,a.jsx)(t.p,{children:"To mitigate risks from validators with little stake, we introduce a minimum stake requirement for validators to be able to validate on consumer chains, which can be set by each consumer chain independently, with a default value set by the provider chain."}),"\n",(0,a.jsx)(t.p,{children:"Additionally, we independently allow individual consumer chains to disable this feature, which will disallow validators from outside the provider active set from validating on the consumer chain and revert them to the previous behaviour of only considering validators of the provider that are part of the active consensus validator set."}),"\n",(0,a.jsx)(t.p,{children:"Additional risk mitigations are to increase the active set size slowly, and to monitor the effects on the network closely. For the first iteration, we propose to increase the active set size to 200 validators (while keeping the consensus validators to 180), thus letting the 20 validators with the most stake outside of the active set validate on consumer chains."}),"\n",(0,a.jsx)(t.h2,{id:"consequences",children:"Consequences"}),"\n",(0,a.jsx)(t.h3,{id:"positive",children:"Positive"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsx)(t.li,{children:"Validators outside of the active set can validate on consumer chains without having an impact on the consensus engine of the provider chain"}),"\n",(0,a.jsx)(t.li,{children:"Consumer chains can have a much larger validator set than the provider chain if they prefer this e.g. for decentralization reasons"}),"\n",(0,a.jsx)(t.li,{children:"Consumer chain teams can, with much less cost than today, start up their own consumer chain node to keep the chain running (in a centralized manner) even if no hub validators have opted in to validate on the chain. This is useful to stop the chain from ending up with an empty validator set and becoming recoverable only with a hardfork"}),"\n"]}),"\n",(0,a.jsx)(t.h3,{id:"negative",children:"Negative"}),"\n",(0,a.jsx)(t.p,{children:"Allowing validators from the inactive set brings with it some additional risks.\nIn general, consumer chains will now face some of the problems also faced by standalone chains. It\u2019s reasonable to assume that the validator set on the hub has a minimum amount of operational quality due to being battle tested and decentralized, and consumer chains with validators from outside the hub active set cannot rely on this as much anymore."}),"\n",(0,a.jsx)(t.h4,{id:"sybil-attacks",children:"Sybil attacks"}),"\n",(0,a.jsx)(t.p,{children:"With the restricted size of the active set today, it\u2019s clear that the set is at least minimally competitive and it is not trivial to spin up multiple nodes as a validator."}),"\n",(0,a.jsx)(t.p,{children:"When we make the \u201cpotential validator set\u201d much larger, we should assume that it becomes much less competitive to be part of that set, and thus trivial for single entities to control many of those validators."}),"\n",(0,a.jsx)(t.h4,{id:"reputational-damage-is-not-a-deterrent",children:"Reputational damage is not a deterrent"}),"\n",(0,a.jsx)(t.p,{children:"For validators in the active set, we typically assume that if they would misbehave, they pay a large reputational cost. This represents delegators deciding to switch validators (potentially even on chains other than the one the misbehaviour happened on), and loss of credibility in the ecosystem. With the much larger active set, it seems prudent to assume that reputational damage is not a deterrent for many validators. They might only have minimal amounts of delegated stake and control most of it themselves, so they might not be deterred from performing actions that would usually bring reputational damage."}),"\n",(0,a.jsx)(t.h4,{id:"additional-negative-consequences",children:"Additional negative consequences"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsx)(t.li,{children:"The provider keeper will need to implement the staking keeper interface, and modules need to be wired up to either the staking or provider keeper, depending on whether they need the consensus or staking validator set"}),"\n",(0,a.jsx)(t.li,{children:"This will impact how future modules are integrated, since we will need to consider whether those modules should consider the consensus validators or the bonded validators (which other modules might assume to be the same)"}),"\n"]}),"\n",(0,a.jsx)(t.h3,{id:"neutral",children:"Neutral"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsx)(t.li,{children:"There might be validators that are bonded, but not validating on any chain at all. This is not a problem, but it might be a bit confusing."}),"\n"]}),"\n",(0,a.jsx)(t.h2,{id:"alternative-considerations",children:"Alternative considerations"}),"\n",(0,a.jsx)(t.h3,{id:"modifying-the-staking-module",children:"Modifying the staking module"}),"\n",(0,a.jsxs)(t.p,{children:["We could instead adapt the ",(0,a.jsx)(t.em,{children:"staking module"})," with a similar change.\nThis might be better if it turns out that the staking module active set is used in many other places."]}),"\n",(0,a.jsx)(t.h3,{id:"allowing-unbonding-validators-to-validate",children:"Allowing unbonding validators to validate"}),"\n",(0,a.jsx)(t.p,{children:"Instead of increasing the active set size, we could allow validators that are unbonded (but still exist on the provider) to validate consumer chains.\nFor this, we would need to:"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsx)(t.li,{children:"Modify the VSC updates to consider the set of all validators, even unbonded ones, instead of just active ones"}),"\n",(0,a.jsx)(t.li,{children:"Adjust our downtime jailing/equivocation slashing logic to work correctly with unbonded validators. This is very hard, because redelegations are not usually tracked for unbonded validators."}),"\n"]}),"\n",(0,a.jsx)(t.h2,{id:"references",children:"References"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.a,{href:"/interchain-security/adrs/adr-016-securityaggregation",children:"Security Aggregation"})," has similar concerns where the staking validator set will differ from the consensus validator set"]}),"\n"]})]})}function c(e={}){const{wrapper:t}={...(0,n.a)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(h,{...e})}):h(e)}},9022:(e,t,i)=>{i.d(t,{Z:()=>a});const a=i.p+"assets/images/inactivevals_after-ac23b4c6474ed6bb2105369cdf8482a0.png"},4823:(e,t,i)=>{i.d(t,{Z:()=>a});const a=i.p+"assets/images/inactivevals_before-a963b865d2029f6629845f7b1beb215b.png"},1151:(e,t,i)=>{i.d(t,{Z:()=>r,a:()=>o});var a=i(7294);const n={},s=a.createContext(n);function o(e){const t=a.useContext(s);return a.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:o(e.components),a.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e50733a4.f44db361.js b/assets/js/e50733a4.f44db361.js new file mode 100644 index 0000000000..d275a4bb56 --- /dev/null +++ b/assets/js/e50733a4.f44db361.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1937],{1370:(n,e,i)=>{i.r(e),i.d(e,{assets:()=>d,contentTitle:()=>t,default:()=>p,frontMatter:()=>s,metadata:()=>a,toc:()=>h});var r=i(5893),o=i(1151);const s={sidebar_position:4},t="Consumer Initiated Slashing",a={id:"features/slashing",title:"Consumer Initiated Slashing",description:"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the Interchain Security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.",source:"@site/versioned_docs/version-v4.2.0-docs/features/slashing.md",sourceDirName:"features",slug:"/features/slashing",permalink:"/interchain-security/v4.2.0/features/slashing",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"ICS Provider Proposals",permalink:"/interchain-security/v4.2.0/features/proposals"},next:{title:"Partial Set Security",permalink:"/interchain-security/v4.2.0/features/partial-set-security"}},d={},h=[{value:"Downtime Infractions",id:"downtime-infractions",level:2},{value:"Equivocation Infractions",id:"equivocation-infractions",level:2},{value:"Report equivocation infractions through CLI",id:"report-equivocation-infractions-through-cli",level:3},{value:"Report equivocation infractions with Hermes",id:"report-equivocation-infractions-with-hermes",level:3}];function c(n){const e={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,o.a)(),...n.components},{Details:i}=e;return i||function(n,e){throw new Error("Expected "+(e?"component":"object")+" `"+n+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(e.h1,{id:"consumer-initiated-slashing",children:"Consumer Initiated Slashing"}),"\n",(0,r.jsx)(e.p,{children:"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the Interchain Security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.\nIn essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake)."}),"\n",(0,r.jsx)(e.p,{children:"To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized.\nAny infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains."}),"\n",(0,r.jsx)(e.p,{children:"In the current implementation there are two important changes brought by the Interchain Security module."}),"\n",(0,r.jsx)(e.h2,{id:"downtime-infractions",children:"Downtime Infractions"}),"\n",(0,r.jsx)(e.p,{children:"Downtime infractions are reported by consumer chains and are acted upon on the provider as soon as the provider receives the infraction evidence."}),"\n",(0,r.jsx)(e.p,{children:"Instead of slashing, the provider will only jail offending validator for the duration of time established by the chain parameters."}),"\n",(0,r.jsx)(e.admonition,{type:"info",children:(0,r.jsxs)(e.p,{children:[(0,r.jsx)(e.a,{href:"/interchain-security/v4.2.0/adrs/adr-002-throttle",children:"Slash throttling"})," (sometimes called jail throttling) mechanism ensures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider."]})}),"\n",(0,r.jsx)(e.p,{children:"Note that validators are only jailed for downtime on consumer chains that they opted-in to validate on,\nor in the case of Top N chains, where they are automatically opted in by being in the Top N% of the validator set on the provider."}),"\n",(0,r.jsx)(e.h2,{id:"equivocation-infractions",children:"Equivocation Infractions"}),"\n",(0,r.jsxs)(e.p,{children:["Equivocation infractions are reported by external agents (e.g., relayers) that can submit to the provider evidence of light client or double signing attacks observed on a consumer chain.\nThe evidence is submitted by sending ",(0,r.jsx)(e.code,{children:"MsgSubmitConsumerMisbehaviour"})," or ",(0,r.jsx)(e.code,{children:"MsgSubmitConsumerDoubleVoting"})," transactions to the provider.\nWhen valid evidence is received, the malicious validators are slashed, jailed, and tombstoned on the provider.\nThis is enabled through the ",(0,r.jsx)(e.em,{children:"cryptographic verification of equivocation"})," feature.\nFor more details, see ",(0,r.jsx)(e.a,{href:"/interchain-security/v4.2.0/adrs/adr-005-cryptographic-equivocation-verification",children:"ADR-005"})," and ",(0,r.jsx)(e.a,{href:"/interchain-security/v4.2.0/adrs/adr-013-equivocation-slashing",children:"ADR-013"}),"."]}),"\n",(0,r.jsx)(e.h3,{id:"report-equivocation-infractions-through-cli",children:"Report equivocation infractions through CLI"}),"\n",(0,r.jsx)(e.p,{children:"The ICS provider module offers two commands for submitting evidence of misbehavior originating from a consumer chain.\nBelow are two examples illustrating the process on Cosmos Hub."}),"\n",(0,r.jsx)(e.p,{children:"Use the following command to submit evidence of double signing attacks:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"gaiad tx provider submit-consumer-double-voting [path/to/evidence.json] [path/to/infraction_header.json] --from node0 --home ../node0 --chain-id $CID \n"})}),"\n",(0,r.jsxs)(i,{children:[(0,r.jsxs)("summary",{children:["Example of ",(0,r.jsx)(e.code,{children:"evidence.json"})]}),(0,r.jsx)("div",{children:(0,r.jsx)("div",{children:(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-json",children:'{\n "vote_a": {\n "type": 1,\n "height": 25,\n "round": 0,\n "block_id": {\n "hash": "tBBWTqjECl31S/clZGoxLdDqs93kTvy3qhpPqET/laY=",\n "part_set_header": {\n "total": 1,\n "hash": "ai2qCLgVZAFph4FJ4Cqw5QW1GZKR4zjOv0bI/Um5AIc="\n }\n },\n "timestamp": "2023-11-20T12:57:54.565207Z",\n "validator_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",\n "signature": "y9yILm9hmv45BZwAaaq9mS1FpH7QeAIJ5Jkcc3U2/k5uks9cuqr4NTIwaIrqMSMKwxVyqiR56xmCT59a6AngAA=="\n },\n "vote_b": {\n "type": 1,\n "height": 25,\n "round": 0,\n "block_id": {\n "hash": "3P06pszgPatuIdLTP5fDWiase4SYHIq9YXGSbRk9/50=",\n "part_set_header": {\n "total": 1,\n "hash": "S+SbOMxFRzfeNNpX9/jyFMz94VwBKk7Dpx6ZyvSYyNU="\n }\n },\n "timestamp": "2023-11-20T12:57:54.599273Z",\n "validator_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",\n "validator_index": 0,\n "signature": "DGFcn4Um1t2kXW60+JhMk5cj7ZFdE5goKVOGiZkLwnNv43+6aGmOWjoq0SHYVzM4MwSwOwbhgZNbkWX+EHGUBw=="\n },\n "total_voting_power": 300,\n "validator_power": 100,\n "timestamp": "2023-11-20T12:57:51.267308Z"\n}\n'})})})})]}),"\n",(0,r.jsxs)(i,{children:[(0,r.jsxs)("summary",{children:["Example of ",(0,r.jsx)(e.code,{children:"infraction_header.json"})]}),(0,r.jsx)("div",{children:(0,r.jsx)("div",{children:(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-json",children:'{\n "signed_header": {\n "header": {\n "version": {\n "block": 11,\n "app": 2\n },\n "chain_id": "consumer",\n "height": 22,\n "time": "2023-11-20T12:57:40.479686Z",\n "last_block_id": {\n "hash": "L63hyLJ+y9+fpb7WYKdmmBhPHwbfEGQEuKmvGzyBPiY=",\n "part_set_header": {\n "total": 18,\n "hash": "euzRQjN7MjGtM6skXM4B8wOgAldWGfZSJRA9JRlO42s="\n }\n },\n "last_commit_hash": "qdDJwVziW3pPqmf8QDGZG+5HVd3OF7fCVh2Z8KQqNVU=",\n "data_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",\n "validators_hash": "pVc+gSYkGesaP3OkK4ig3DBi4o9/GCdXGtO/PQ6i/Ik=",\n "next_validators_hash": "pVc+gSYkGesaP3OkK4ig3DBi4o9/GCdXGtO/PQ6i/Ik=",\n "consensus_hash": "BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8=",\n "app_hash": "Yu3HX62w7orbbY/pm2QEK7yIwR+AlNdjSSqiK1kmuJM=",\n "last_results_hash": "Yu3HX62w7orbbY/pm2QEK7yIwR+AlNdjSSqiK1kmuJM=",\n "evidence_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",\n "proposer_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA="\n },\n "commit": {\n "height": 22,\n "round": 1,\n "block_id": {\n "hash": "PKrS32IEZoFY2q2S3iQ68HQL751ieBhf5Eu/Y5Z/QPg=",\n "part_set_header": {\n "total": 1,\n "hash": "8UuA7Oqw5AH/KOacpmHVSMOIDe4l2eC8VmdH2mzcpiM="\n }\n },\n "signatures": [\n {\n "block_id_flag": 2,\n "validator_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",\n "timestamp": "2023-11-20T12:57:44.076538Z",\n "signature": "bSOH4+Vg2I37zeJphOguGOD0GK3JzM1ghSgJd0UlW/DHn1u9Hvv4EekHuCu6qwRLZcuS/ZxNlmr9qYNfxX3bDA=="\n },\n {\n "block_id_flag": 2,\n "validator_address": "i/A830FM7cfmA8yTn9n3xBg5XpU=",\n "timestamp": "2020-01-02T00:07:00Z",\n "signature": "7bXSDtlOwGK/gLEsFpTWOzm2TFoaARrWQUpbgWEwKtLlUs7iE06TOvJ3yPPfTfqqN/qYnvxxgjl0M0EhUWu5Bg=="\n },\n {\n "block_id_flag": 2,\n "validator_address": "lrQDkJ2fk7UAgNzRZfcwMKSYa2E=",\n "timestamp": "2023-11-20T12:57:44.076519Z",\n "signature": "Pb6G4bCg4wafmV89WNnzXxbSCknZUHnSQfSCE5QMFxPtSUIN4A7SK5m7yltqMJF5zkyenlFiEI4J3OZ4KCjCAw=="\n },\n {\n "block_id_flag": 2,\n "validator_address": "+R94nXSeM1Z49e/CXpyHT3M+h3k=",\n "timestamp": "2023-11-20T12:57:44.057451Z",\n "signature": "j3EasIHNYA6MxW/PiWyruzHsjVsBV9t11W6Qx800WMm/+P+CkfR+UZAp7MPTvKZEZFuh3GUsBtyfb/vA+jJWCw=="\n }\n ]\n }\n },\n "validator_set": {\n "validators": [\n {\n "address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",\n "pub_key": {\n "ed25519": "dtn+SfD+4QLo0+t0hAoP6Q2sGjh0XEI3LWVG+doh3u0="\n },\n "voting_power": 100,\n "proposer_priority": -200\n },\n {\n "address": "lrQDkJ2fk7UAgNzRZfcwMKSYa2E=",\n "pub_key": {\n "ed25519": "UgN2JsjPy2WLh7dzJRBkUQtdgNoT4/uGj7kbIVqqHT8="\n },\n "voting_power": 100,\n "proposer_priority": 100\n },\n {\n "address": "+R94nXSeM1Z49e/CXpyHT3M+h3k=",\n "pub_key": {\n "ed25519": "5svW8261x+cZosp2xIhqzgt2tyuawrSDyHlpbgS3BC4="\n },\n "voting_power": 100,\n "proposer_priority": 100\n },\n {\n "address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",\n "pub_key": {\n "ed25519": "dtn+SfD+4QLo0+t0hAoP6Q2sGjh0XEI3LWVG+doh3u0="\n },\n "voting_power": 100,\n "proposer_priority": -200\n }\n ],\n "proposer": {\n "address": "VUz+QceJ8Nu7GbJuVItwsfVjybA=",\n "pub_key": {\n "ed25519": "0s8KDTgEcwmOBrHWvV7mtBlItJ3upgM1FJsciwREdy4="\n },\n "voting_power": 1,\n "proposer_priority": -3\n }\n },\n "trusted_height": {\n "revision_height": 18\n },\n "trusted_validators": {\n "validators": [\n {\n "address": "VUz+QceJ8Nu7GbJuVItwsfVjybA=",\n "pub_key": {\n "ed25519": "0s8KDTgEcwmOBrHWvV7mtBlItJ3upgM1FJsciwREdy4="\n },\n "voting_power": 1,\n "proposer_priority": -3\n },\n {\n "address": "i/A830FM7cfmA8yTn9n3xBg5XpU=",\n "pub_key": {\n "ed25519": "FCmIw7hSuiAoWk/2f4LuGQ+3zx5101xiqU8DoC5wGkg="\n },\n "voting_power": 1,\n "proposer_priority": 1\n },\n {\n "address": "2DrZF0roNnnvEy4NS2aY811ncKg=",\n "pub_key": {\n "ed25519": "MI9c6sphsWlx0RAHCYOjMRXMFkTUaEYwOiOKG/0tsMs="\n },\n "voting_power": 1,\n "proposer_priority": 1\n },\n {\n "address": "73aN0uOc5b/Zfq2Xcjl0kH2r+tw=",\n "pub_key": {\n "ed25519": "gWNcDup4mdnsuqET4QeFRzVb+FnSP4Vz3iNMj5wvWXk="\n },\n "voting_power": 1,\n "proposer_priority": 1\n }\n ],\n "proposer": {\n "address": "VUz+QceJ8Nu7GbJuVItwsfVjybA=",\n "pub_key": {\n "ed25519": "0s8KDTgEcwmOBrHWvV7mtBlItJ3upgM1FJsciwREdy4="\n },\n "voting_power": 1,\n "proposer_priority": -3\n }\n }\n}\n'})})})})]}),"\n",(0,r.jsx)(e.p,{children:"Use the following command to submit evidence of light client attacks:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"gaiad tx provider submit-consumer-misbehaviour [path/to/misbehaviour.json] --from node0 --home ../node0 --chain-id $CID\n"})}),"\n",(0,r.jsxs)(i,{children:[(0,r.jsxs)("summary",{children:["Example of ",(0,r.jsx)(e.code,{children:"misbehaviour.json"})]}),(0,r.jsx)("div",{children:(0,r.jsx)("div",{children:(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-json",children:'{\n "client_id": "07-tendermint-0",\n "header_1": {\n "signed_header": {\n "header": {\n "version": {\n "block": "11",\n "app": "2"\n },\n "chain_id": "testchain2",\n "height": "19",\n "time": "2020-01-02T00:08:10Z",\n "last_block_id": {\n "hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",\n "part_set_header": {\n "total": 10000,\n "hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="\n }\n },\n "last_commit_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",\n "data_hash": "bW4ouLmLUycELqUKV91G5syFHHLlKL3qpu/e7v5moLg=",\n "validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",\n "next_validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",\n "consensus_hash": "5eVmxB7Vfj/4zBDxhBeHiLj6pgKwfPH0JSF72BefHyQ=",\n "app_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",\n "last_results_hash": "CS4FhjAkftYAmGOhLu4RfSbNnQi1rcqrN/KrNdtHWjc=",\n "evidence_hash": "c4ZdsI9J1YQokF04mrTKS5bkWjIGx6adQ6Xcc3LmBxQ=",\n "proposer_address": "CbKqPquy50bcrY7JRdW7zXybSuA="\n },\n "commit": {\n "height": "19",\n "round": 1,\n "block_id": {\n "hash": "W2xVqzPw03ZQ1kAMpcpht9WohwMzsGnyKKNjPYKDF6U=",\n "part_set_header": {\n "total": 3,\n "hash": "hwgKOc/jNqZj6lwNm97vSTq9wYt8Pj4MjmYTVMGDFDI="\n }\n },\n "signatures": [\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "timestamp": "2020-01-02T00:08:10Z",\n "signature": "PGTquCtnTNFFY5HfEFz9f9pA7PYqjtQfBwHq6cxF/Ux8OI6nVqyadD9a84Xm7fSm6mqdW+T6YVfqIKmIoRjJDQ=="\n },\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",\n "timestamp": "2020-01-02T00:08:10Z",\n "signature": "0e39yoBorwORAH/K9qJ7D1N1Yr7CutMiQJ+oiIK39eMhuoK3UWzQyMGRLzDOIDupf8yD99mvGVVAlNIODlV3Dg=="\n },\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",\n "timestamp": "2020-01-02T00:08:10Z",\n "signature": "lhc2tkwydag9D1iLQhdDCE8GgrHP94M1LbHFYMoL9tExaEq6RiFW/k71TQH5x96XQ9XYOznMIHKC2BDh4GlnAQ=="\n },\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",\n "timestamp": "2020-01-02T00:08:10Z",\n "signature": "8xeSBf0nSFs/X/rQ9CZLzwkJJhQBLA2jKdPGP3MlULxm992XxrOsIYq47u1daxvSsn6ql5OVYjzBNU0qbPpvCA=="\n }\n ]\n }\n },\n "validator_set": {\n "validators": [\n {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n {\n "address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",\n "pub_key": {\n "ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",\n "pub_key": {\n "ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",\n "pub_key": {\n "ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n }\n ],\n "proposer": {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n "total_voting_power": "0"\n },\n "trusted_height": {\n "revision_number": "0",\n "revision_height": "18"\n },\n "trusted_validators": {\n "validators": [\n {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n {\n "address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",\n "pub_key": {\n "ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",\n "pub_key": {\n "ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",\n "pub_key": {\n "ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n }\n ],\n "proposer": {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n "total_voting_power": "0"\n }\n },\n "header_2": {\n "signed_header": {\n "header": {\n "version": {\n "block": "11",\n "app": "2"\n },\n "chain_id": "testchain2",\n "height": "19",\n "time": "2020-01-02T00:08:20Z",\n "last_block_id": {\n "hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",\n "part_set_header": {\n "total": 10000,\n "hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="\n }\n },\n "last_commit_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",\n "data_hash": "bW4ouLmLUycELqUKV91G5syFHHLlKL3qpu/e7v5moLg=",\n "validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",\n "next_validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",\n "consensus_hash": "5eVmxB7Vfj/4zBDxhBeHiLj6pgKwfPH0JSF72BefHyQ=",\n "app_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",\n "last_results_hash": "CS4FhjAkftYAmGOhLu4RfSbNnQi1rcqrN/KrNdtHWjc=",\n "evidence_hash": "c4ZdsI9J1YQokF04mrTKS5bkWjIGx6adQ6Xcc3LmBxQ=",\n "proposer_address": "CbKqPquy50bcrY7JRdW7zXybSuA="\n },\n "commit": {\n "height": "19",\n "round": 1,\n "block_id": {\n "hash": "IZM8NKS+8FHB7CBmgB8Nz7BRVVXiiyqMQDvHFUvgzxo=",\n "part_set_header": {\n "total": 3,\n "hash": "hwgKOc/jNqZj6lwNm97vSTq9wYt8Pj4MjmYTVMGDFDI="\n }\n },\n "signatures": [\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "timestamp": "2020-01-02T00:08:20Z",\n "signature": "pLIEZ4WSAtnMsgryujheHSq4+YG3RqTfMn2ZxgEymr0wyi+BNlQAKRtRfesm0vfYxvjzc/jhGqtUqHtSIaCwCQ=="\n },\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",\n "timestamp": "2020-01-02T00:08:20Z",\n "signature": "XG7iTe/spWyTUkT7XDzfLMpYqrdyqizE4/X4wl/W+1eaQp0WsCHYnvPU3x9NAnYfZzaKdonZiDWs7wacbZTcDg=="\n },\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",\n "timestamp": "2020-01-02T00:08:20Z",\n "signature": "TqegK7ORuICSy++wVdPHt8fL2WfPlYsMPv1XW79wUdcjnQkezOM50OSqYaP4ua5frIZsn+sWteDrlqFTdkl3BA=="\n },\n {\n "block_id_flag": "BLOCK_ID_FLAG_COMMIT",\n "validator_address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",\n "timestamp": "2020-01-02T00:08:20Z",\n "signature": "dhvp3XlIaCxx5MFDs0TCkAPHSm0PS2EtJzYAx2c/7MWdLwUJFZrAUTeimQE2c9i9ro91cjZn/vI0/oFRXab6Aw=="\n }\n ]\n }\n },\n "validator_set": {\n "validators": [\n {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n {\n "address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",\n "pub_key": {\n "ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",\n "pub_key": {\n "ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",\n "pub_key": {\n "ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n }\n ],\n "proposer": {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n "total_voting_power": "0"\n },\n "trusted_height": {\n "revision_number": "0",\n "revision_height": "18"\n },\n "trusted_validators": {\n "validators": [\n {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n {\n "address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",\n "pub_key": {\n "ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",\n "pub_key": {\n "ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n },\n {\n "address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",\n "pub_key": {\n "ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="\n },\n "voting_power": "1",\n "proposer_priority": "1"\n }\n ],\n "proposer": {\n "address": "CbKqPquy50bcrY7JRdW7zXybSuA=",\n "pub_key": {\n "ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="\n },\n "voting_power": "1",\n "proposer_priority": "-3"\n },\n "total_voting_power": "0"\n }\n }\n}\n'})})})})]}),"\n",(0,r.jsx)(e.h3,{id:"report-equivocation-infractions-with-hermes",children:"Report equivocation infractions with Hermes"}),"\n",(0,r.jsxs)(e.p,{children:["Ensure you have a well-configured Hermes ",(0,r.jsx)(e.code,{children:"v1.7.3+"})," relayer effectively relaying packets between a consumer chain and a provider chain.\nThe following command demonstrates how to run a Hermes instance in ",(0,r.jsx)(e.em,{children:"evidence mode"})," to detect misbehaviors on a consumer chain and automatically submit the evidence to the provider chain."]}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"hermes evidence --chain <CONSUMER-CHAIN-ID>\n"})}),"\n",(0,r.jsx)(e.admonition,{type:"tip",children:(0,r.jsxs)(e.p,{children:[(0,r.jsx)(e.code,{children:"hermes evidence"})," takes a ",(0,r.jsx)(e.code,{children:"--check-past-blocks"})," option giving the possibility to look for older evidence (default is 100)."]})})]})}function p(n={}){const{wrapper:e}={...(0,o.a)(),...n.components};return e?(0,r.jsx)(e,{...n,children:(0,r.jsx)(c,{...n})}):c(n)}},1151:(n,e,i)=>{i.d(e,{Z:()=>a,a:()=>t});var r=i(7294);const o={},s=r.createContext(o);function t(n){const e=r.useContext(s);return r.useMemo((function(){return"function"==typeof n?n(e):{...e,...n}}),[e,n])}function a(n){let e;return e=n.disableParentContext?"function"==typeof n.components?n.components(o):n.components||o:t(n.components),r.createElement(s.Provider,{value:e},n.children)}}}]); \ No newline at end of file diff --git a/assets/js/e5b5a87b.c1818ef8.js b/assets/js/e5b5a87b.c1818ef8.js new file mode 100644 index 0000000000..60cee29636 --- /dev/null +++ b/assets/js/e5b5a87b.c1818ef8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5313],{6407:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>d,frontMatter:()=>s,metadata:()=>r,toc:()=>l});var i=t(5893),a=t(1151);const s={sidebar_position:3,title:"Onboarding Checklist"},o="Consumer Onboarding Checklist",r={id:"consumer-development/onboarding",title:"Onboarding Checklist",description:"The following checklists will aid in onboarding a new consumer chain to interchain security.",source:"@site/versioned_docs/version-v4.2.0-docs/consumer-development/onboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/onboarding",permalink:"/interchain-security/v4.2.0/consumer-development/onboarding",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Onboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Consumer Chain Governance",permalink:"/interchain-security/v4.2.0/consumer-development/consumer-chain-governance"},next:{title:"Offboarding Checklist",permalink:"/interchain-security/v4.2.0/consumer-development/offboarding"}},c={},l=[{value:"1. Complete testing & integration",id:"1-complete-testing--integration",level:2},{value:"2. Create an Onboarding Repository",id:"2-create-an-onboarding-repository",level:2},{value:"3. Submit a Governance Proposal",id:"3-submit-a-governance-proposal",level:2},{value:"4. Launch",id:"4-launch",level:2}];function h(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",input:"input",li:"li",p:"p",pre:"pre",ul:"ul",...(0,a.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"consumer-onboarding-checklist",children:"Consumer Onboarding Checklist"}),"\n",(0,i.jsx)(n.p,{children:"The following checklists will aid in onboarding a new consumer chain to interchain security."}),"\n",(0,i.jsxs)(n.p,{children:["Additionally, you can check the ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/CONSUMER_LAUNCH_GUIDE.md",children:"testnet repo"})," for a comprehensive guide on preparing and launching consumer chains."]}),"\n",(0,i.jsx)(n.h2,{id:"1-complete-testing--integration",children:"1. Complete testing & integration"}),"\n",(0,i.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","test integration with gaia"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","test your protocol with supported relayer versions (minimum hermes 1.4.1)"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","reach out to the ICS team if you are facing issues"]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"2-create-an-onboarding-repository",children:"2. Create an Onboarding Repository"}),"\n",(0,i.jsx)(n.p,{children:"To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain."}),"\n",(0,i.jsx)(n.p,{children:"This should include (at minimum):"}),"\n",(0,i.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","genesis.json without CCV data (before the proposal passes)"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see ",(0,i.jsx)(n.a,{href:"/interchain-security/v4.2.0/consumer-development/consumer-genesis-transformation",children:"Transform Consumer Genesis"}),")"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","information about relevant seed/peer nodes you are running"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","relayer information (compatible versions)"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","copy of your governance proposal (as JSON)"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","a script showing how to start your chain and connect to peers (optional)"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable"]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["Example of such a repository can be found ",(0,i.jsx)(n.a,{href:"https://github.com/hyphacoop/ics-testnets/tree/main/game-of-chains-2022/sputnik",children:"here"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"3-submit-a-governance-proposal",children:"3. Submit a Governance Proposal"}),"\n",(0,i.jsxs)(n.p,{children:["Before you submit a ",(0,i.jsx)(n.code,{children:"ConsumerChainAddition"})," proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch.\nIf possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues."]}),"\n",(0,i.jsxs)(n.p,{children:["Additionally, reach out to the community via the ",(0,i.jsx)(n.a,{href:"https://forum.cosmos.network/",children:"forum"})," to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers."]}),"\n",(0,i.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","determine your chain's spawn time"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","determine consumer chain parameters to be put in the proposal"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","take note to include a link to your onboarding repository"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","describe the purpose and benefits of running your chain"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","determine whether your chain should be an Opt-In chain or a Top N chain (see ",(0,i.jsx)(n.a,{href:"/interchain-security/v4.2.0/features/partial-set-security",children:"Partial Set Security"}),")"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","if desired, decide on power-shaping parameters (see ",(0,i.jsx)(n.a,{href:"/interchain-security/v4.2.0/features/power-shaping",children:"Power Shaping"}),")"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Example of a consumer chain addition proposal."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-js",children:'// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.\n// If it passes, if the top_N parameter is not equal to 0, the top N% of validators by voting power on the provider chain are expected to validate the consumer chain at spawn time.\n// Otherwise, only validators that opted in during the proposal period are expected to validate the consumer chain at spawn time.\n// It is recommended that spawn time occurs after the proposal end time.\n{\n // Title of the proposal\n "title": "Add consumer chain",\n // Description of the proposal\n // format the text as a .md file and include the file in your onboarding repository\n "description": ".md description of your chain and all other relevant information",\n // Proposed chain-id of the new consumer chain.\n // Must be unique from all other consumer chain ids of the executing provider chain.\n "chain_id": "newchain-1",\n // Initial height of new consumer chain.\n // For a completely new chain, this will be {0,1}.\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Hash of the consumer chain genesis state without the consumer CCV module genesis params.\n // It is used for off-chain confirmation of genesis.json validity by validators and other parties.\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n // Hash of the consumer chain binary that should be run by validators on chain initialization.\n // It is used for off-chain confirmation of binary validity by validators and other parties.\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n // Time on the provider chain at which the consumer chain genesis is finalized and validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n // Unbonding period for the consumer chain.\n // It should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n // IBC transfer packets will timeout after this interval elapses.\n "transfer_timeout_period": 1800000000000,\n // The fraction of tokens allocated to the consumer redistribution address during distribution events.\n // The fraction is a string representing a decimal number. For example "0.75" would represent 75%.\n // The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.\n "consumer_redistribution_fraction": "0.75",\n // BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.\n // eg. send rewards to the provider every 1000 blocks\n "blocks_per_distribution_transmission": 1000,\n // The number of historical info entries to persist in store.\n // This param is a part of the cosmos sdk staking module. In the case of\n // a ccv enabled consumer chain, the ccv module acts as the staking module.\n "historical_entries": 10000,\n // The ID of a token transfer channel used for the Reward Distribution\n\t// sub-protocol. If DistributionTransmissionChannel == "", a new transfer\n\t// channel is created on top of the same connection as the CCV channel.\n\t// Note that transfer_channel_id is the ID of the channel end on the consumer chain.\n // it is most relevant for chains performing a standalone to consumer changeover\n // in order to maintain the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123",\n // Corresponds to the percentage of validators that have to validate the chain under the Top N case.\n // For example, 53 corresponds to a Top 53% chain, meaning that the top 53% provider validators by voting power\n // have to validate the proposed consumer chain. top_N can either be 0 or any value in [50, 100].\n // A chain can join with top_N == 0 as an Opt In chain, or with top_N \u2208 [50, 100] as a Top N chain.\n "top_N": 95,\n // Corresponds to the maximum power (percentage-wise) a validator can have on the consumer chain. For instance, if\n // `validators_power_cap` is set to 32, it means that no validator can have more than 32% of the voting power on the\n // consumer chain. Note that this might not be feasible. For example, think of a consumer chain with only\n // 5 validators and with `validators_power_cap` set to 10%. In such a scenario, at least one validator would need\n // to have more than 20% of the total voting power. Therefore, `validators_power_cap` operates on a best-effort basis.\n "validators_power_cap": 0,\n // Corresponds to the maximum number of validators that can validate a consumer chain.\n // Only applicable to Opt In chains. Setting `validator_set_cap` on a Top N chain is a no-op.\n "validator_set_cap": 0,\n // Corresponds to a list of provider consensus addresses of validators that are the ONLY ones that can validate\n // the consumer chain.\n "allowlist": [],\n // Corresponds to a list of provider consensus addresses of validators that CANNOT validate the consumer chain.\n "denylist": []\n}\n'})}),"\n",(0,i.jsx)(n.h2,{id:"4-launch",children:"4. Launch"}),"\n",(0,i.jsxs)(n.p,{children:["The consumer chain starts after at least 66.67% of its voting power comes online.\nNote that this means 66.67% of the voting power in the ",(0,i.jsx)(n.em,{children:"consumer"})," validator set, which will be comprised of all validators that either opted in to the chain or are part of the top N% of the provider chain (and are thus automatically opted in).\nThe consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer"]}),"\n",(0,i.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","provide a repo with onboarding instructions for validators (it should already be listed in the proposal)"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","genesis.json with ccv data populated (MUST contain the initial validator set)"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)"]}),"\n",(0,i.jsxs)(n.li,{className:"task-list-item",children:[(0,i.jsx)(n.input,{type:"checkbox",disabled:!0})," ","have a block explorer in place to track chain activity & health"]}),"\n"]})]})}function d(e={}){const{wrapper:n}={...(0,a.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>r,a:()=>o});var i=t(7294);const a={},s=i.createContext(a);function o(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:o(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e69e9c61.942ce78c.js b/assets/js/e69e9c61.942ce78c.js new file mode 100644 index 0000000000..a67a8a79dd --- /dev/null +++ b/assets/js/e69e9c61.942ce78c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6882],{2489:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>d,contentTitle:()=>s,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>l});var i=r(5893),t=r(1151);const a={sidebar_position:17,title:"Security aggregation"},s="ADR 016: Security aggregation",o={id:"adrs/adr-016-securityaggregation",title:"Security aggregation",description:"Changelog",source:"@site/docs/adrs/adr-016-securityaggregation.md",sourceDirName:"adrs",slug:"/adrs/adr-016-securityaggregation",permalink:"/interchain-security/adrs/adr-016-securityaggregation",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:17,frontMatter:{sidebar_position:17,title:"Security aggregation"},sidebar:"tutorialSidebar",previous:{title:"Partial Set Security",permalink:"/interchain-security/adrs/adr-015-partial-set-security"},next:{title:"ICS with Inactive Provider Validators",permalink:"/interchain-security/adrs/adr-017-allowing-inactive-validators"}},d={},l=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Alternative Approaches",id:"alternative-approaches",level:2},{value:"Rewards",id:"rewards",level:3},{value:"Decision",id:"decision",level:2},{value:"Rewards will be sent back to external chains instead of paying rewards for external stakers on Cosmos chain",id:"rewards-will-be-sent-back-to-external-chains-instead-of-paying-rewards-for-external-stakers-on-cosmos-chain",level:3},{value:"Detailed Design",id:"detailed-design",level:2},{value:"Power Mixing",id:"power-mixing",level:3},{value:"Integration with <code>ICS provider</code>",id:"integration-with-ics-provider",level:4},{value:"Integration with <code>ICS consumer</code>",id:"integration-with-ics-consumer",level:4},{value:"Queries",id:"queries",level:3},{value:"Reward Handler",id:"reward-handler",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"Questions:",id:"questions",level:2},{value:"References",id:"references",level:2}];function c(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",pre:"pre",ul:"ul",...(0,t.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"adr-016-security-aggregation",children:"ADR 016: Security aggregation"}),"\n",(0,i.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"2024-04-24: Initial draft of ADR"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(n.p,{children:"Proposed"}),"\n",(0,i.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,i.jsx)(n.p,{children:"Security Aggregation enables staking of tokens from external sources such as Ethereum or Bitcoin to Cosmos blockchains. By integrating Security Aggregation, a Cosmos blockchain can be secured by both native tokens and external tokens (e.g. ETH, BTC)."}),"\n",(0,i.jsx)(n.p,{children:"Security Aggregation consists of the following parts:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"A mechanism for delegating external tokens to Cosmos validators, such as Babylon or EigenLayer AVS contract."}),"\n",(0,i.jsx)(n.li,{children:"An oracle that tracks how much external stake has been delegated to each Cosmos validator and provides price feeds for external tokens."}),"\n",(0,i.jsx)(n.li,{children:"Power mixing: a mechanism to combine external and native stake to derive the power of each validator."}),"\n",(0,i.jsx)(n.li,{children:"A reward distribution protocol that enables sending back rewards to the external source."}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"External staking information is received from an oracle together with price information of related stakes.\nThe CosmosLayer derives validator powers based on external and native staking information and initiates rewarding of external depositors."}),"\n",(0,i.jsxs)(n.p,{children:["This ADR describes the ",(0,i.jsx)(n.em,{children:"Cosmos modules"})," of the solution."]}),"\n",(0,i.jsx)(n.h2,{id:"alternative-approaches",children:"Alternative Approaches"}),"\n",(0,i.jsx)(n.h3,{id:"rewards",children:"Rewards"}),"\n",(0,i.jsx)(n.p,{children:"As an alternative to sending rewards back to the external chains, stakers could be rewarded on the Cosmos chain.\nThis would require a mapping of external addresses to addresses on Cosmos chain for each staker on external source.\nIn addition detailed external staking information such as staking addresses, amount of stakes per staker and validator, etc. have to be provided by the oracle."}),"\n",(0,i.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,i.jsx)(n.h3,{id:"rewards-will-be-sent-back-to-external-chains-instead-of-paying-rewards-for-external-stakers-on-cosmos-chain",children:"Rewards will be sent back to external chains instead of paying rewards for external stakers on Cosmos chain"}),"\n",(0,i.jsx)(n.p,{children:"Rewards will be sent back to external chains instead of paying rewards for external stakers on Cosmos chain"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"due to amount of additional staking information to be sent and tracked by the oracle"}),"\n",(0,i.jsx)(n.li,{children:"due to the additional complexity of managing external and Cosmos addresses"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"detailed-design",children:"Detailed Design"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"Power Mixing"})," feature and ",(0,i.jsx)(n.code,{children:"Reward Distribution"})," protocol are an integral part of the Security Aggregation solution.\nThe ",(0,i.jsx)(n.code,{children:"Power Mixing"})," module provides the capability of deriving validator power based on stake originated from external sources such as Ethereum/Bitcoin and the native staking module.\nThe ",(0,i.jsx)(n.code,{children:"Reward Distribution"})," manages the process of sending rewards to external stakers."]}),"\n",(0,i.jsx)(n.h3,{id:"power-mixing",children:"Power Mixing"}),"\n",(0,i.jsxs)(n.p,{children:["Power Mixing provides the final validator powers based on staking information of the native chain and the external stakes. The information about external staking and related price feeds are received from an oracle.\nOnce the final validator powers are determined the result is submitted to the underlying CometBFT consensus layer by ",(0,i.jsx)(n.a,{href:"https://docs.cometbft.com/v0.38/spec/abci/abci++_app_requirements#updating-the-validator-set",children:"updating"})," the validator set."]}),"\n",(0,i.jsx)(n.p,{children:"Requirements:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"validator updates are performed on each EndBlock"}),"\n",(0,i.jsx)(n.li,{children:"a validator's power is determined based on its native on-chain stakes and external stakes"}),"\n",(0,i.jsx)(n.li,{children:"price information of staked tokens is used to determine a validator\u2019s power, e.g. price ratio (price of native on-chain token / price of external stake)"}),"\n",(0,i.jsx)(n.li,{children:"price information of native/external tokens are received from an oracle"}),"\n",(0,i.jsx)(n.li,{children:"staking information from external sources received from the oracle"}),"\n",(0,i.jsxs)(n.li,{children:["native staking information are received from the ",(0,i.jsx)(n.code,{children:"Cosmos SDK Staking Module"})]}),"\n",(0,i.jsx)(n.li,{children:"set of validator stakes from oracle always have the current price, full set of validators, and current stakes"}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"Power Mixing"})," implementation"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["queries current validators and their powers from ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/cosmos-sdk/blob/a6f3fbfbeb7ea94bda6369a7163a523e118a123c/x/staking/types/staking.pb.go#L415",children:"x/staking"}),"\nand from oracle (see below)."]}),"\n",(0,i.jsx)(n.li,{children:"calculates power updates by mixing power values of external and internal sources\nFollowing pseudocode snippet shows a possible implementation of how power mixing\nfeature works."}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-golang",children:"// PowerSource is an abstract entity providing validator powers which\n// are used by the mixer. This can be an oracle, staking module or an\n// IBC connected bridge.\ntype PowerSource interface {\n GetValidatorUpdates() []abci.ValidatorUpdate\n}\n\n// MixPowers calculates power updates by mixing validator powers from different sources\nfunc (k *Keeper) MixPowers(source ...PowerSource) []abci.ValidatorUpdate {\n var valUpdate []abci.ValidatorUpdate\n for _, ps := range source {\n // mix powers from two sets of validator updates an return set of validator updates\n // with aggregated powers\n valUpdate = mixPower(valUpdate, ps.GetValidatorUpdates())\n }\n return valUpdate\n}\n\nfunc (k *keeper) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {\n // GetPowerSources (including local staking module)\n registeredPowerSource := GetPowerSources()\n return k.MixPowers(registeredPowerSource...)\n}\n"})}),"\n",(0,i.jsxs)(n.h4,{id:"integration-with-ics-provider",children:["Integration with ",(0,i.jsx)(n.code,{children:"ICS provider"})]}),"\n",(0,i.jsxs)(n.p,{children:["The provider module updates the validator set on CometBFT instead of the SDK staking module (x/staking). The provider implementation will intervene in this behavior and ensure that the validator updates are taken from the ",(0,i.jsx)(n.code,{children:"Power Mixing"})," feature."]}),"\n",(0,i.jsxs)(n.p,{children:["External power sources are managed by the provider module. Only registered power sources can provide input to the ",(0,i.jsx)(n.code,{children:"Power Mixing"})," feature.\nPower sources will be assigned a unique identifier which will be used by the oracle, provider module and the power mixing and rewarding feature."]}),"\n",(0,i.jsxs)(n.p,{children:["Updates with the next validator set are sent to consumer chains on each epoch (see ",(0,i.jsx)(n.code,{children:"EndBlockVSU()"}),").\nWhen collecting the validator updates for each consumer chain (see ",(0,i.jsx)(n.a,{href:"https://pkg.go.dev/github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper#Keeper.QueueVSCPackets",children:(0,i.jsx)(n.code,{children:"QueueVSCPackets()"})}),"), the validator powers of the bonded validators will be updated with the validator powers from the external sources using the ",(0,i.jsx)(n.code,{children:"Power Mixing"})," module.\nThese updates are sent as part of the VSC packets to all registered consumer chains."]}),"\n",(0,i.jsxs)(n.h4,{id:"integration-with-ics-consumer",children:["Integration with ",(0,i.jsx)(n.code,{children:"ICS consumer"})]}),"\n",(0,i.jsx)(n.p,{children:"Consumer chains receive validator updates as part of VSC packets from the provider.\nThese packets contain validator powers which were already mixed with external staked powers."}),"\n",(0,i.jsx)(n.h3,{id:"queries",children:"Queries"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-protobuf",children:"// GetValidatorUpdates returns the power mixed validator results from the provided sources\nservice Query {\n rpc GetValidatorUpdates(PowerMixedValUpdateRequest) PowerMixedValUpdateResponse {};\n}\n\n// PowerMixedValUpdateRequest contains the list of power sources on which the\n// power mixing should be based on\nmessage PowerMixedValUpdateRequest {\n repeated PowerSource sources;\n}\n\n// PowerMixedValUpdateResponse returns the validator set with the updated powers\n// from the power mixing feature\nmessage PowerMixedValUpdateResponse {\n repeated abci.ValidatorUpdate val_set\n}\n"})}),"\n",(0,i.jsx)(n.p,{children:"The following queries will be provided by the oracle"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-protobuf",children:'service Query {\n rpc GetExtValidators(GetExtValidatorRequest) returns (ExtValidatorsResponse) {\n option (google.api.http).get = "oracle/v1/get_validators";\n };\n}\n\nmessage GetExtValidatorRequest {}\n\n// ExtValidatorsResponse is the response from GetExtValidators queries\nmessage ExtValidatorsResponse {\n repeated ExtValPower powers;\n}\n\n// ExtValPower represents a validator with its staking and token information,\n// where:\n// `power_source_identifier` is the identifier of the registered power source\n// `validator_address` is the address of the validator\n// `stakes` is the total amount of stakes for a validator\n// `denom` is the source token of the stake e.g. ETH,BTC\n// `price_ratio` is the ratio of price of the external token to the price of the \'local\' token\nmessage ExtValPower {\n string power_source_identifier;\n string validator_address;\n uint64 stakes;\n string denom;\n float price_ratio;\n}\n\n// GetPrice returns a price feed for a given token\nservice Query {\n rpc GetPrice(GetPriceRequest) returns (GetPriceResponse) {\n option (google.api.http).get = "/oracle/v1/get_price";\n };\n}\n'})}),"\n",(0,i.jsx)(n.p,{children:"For security reasons the amount of external stakes needs to be limited. Limitation of external staking could be driven by governance and is not subject of this version of the ADR."}),"\n",(0,i.jsx)(n.h3,{id:"reward-handler",children:"Reward Handler"}),"\n",(0,i.jsxs)(n.p,{children:["For native staked tokens the ",(0,i.jsx)(n.code,{children:"Distribution Module"})," of the Cosmos SDK is taking care of sending the rewards to stakers.\nFor stakes originated from external chains (Ethereum/Bitcoin) the ",(0,i.jsx)(n.code,{children:"Reward Handler"})," module sends rewards to EigenLayer/Babylon.\nThe transfer of rewards is done using a bridge between the Cosmos chain and the external provider chain."]}),"\n",(0,i.jsxs)(n.p,{children:["Note: currently there's no support paying rewards on EigenLayer (see ",(0,i.jsx)(n.a,{href:"https://www.coindesk.com/tech/2024/04/10/eigenlayer-cryptos-biggest-project-launch-this-year-is-still-missing-crucial-functionality/",children:"here"}),")"]}),"\n",(0,i.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,i.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Allow external depositors to stake their tokens to secure a Cosmos chain"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Dependency to external sources e.g (price feeds) for validator power calculation"}),"\n",(0,i.jsx)(n.li,{children:"Security impact"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Additional complexity for staking"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"questions",children:"Questions:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Slashing: subject of this ADR? (Defined but ",(0,i.jsx)(n.a,{href:"https://www.coindesk.com/tech/2024/04/10/eigenlayer-cryptos-biggest-project-launch-this-year-is-still-missing-crucial-functionality/",children:"not activated"})," currently on EigenLayer)."]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://docs.eigenlayer.xyz/",children:"EigenLayer"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://babylonchain.io/",children:"Babylon"})}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},1151:(e,n,r)=>{r.d(n,{Z:()=>o,a:()=>s});var i=r(7294);const t={},a=i.createContext(t);function s(e){const n=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:s(e.components),i.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/ea42cb80.f06fff1b.js b/assets/js/ea42cb80.f06fff1b.js new file mode 100644 index 0000000000..89e0042dff --- /dev/null +++ b/assets/js/ea42cb80.f06fff1b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4117],{5956:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>o,contentTitle:()=>c,default:()=>l,frontMatter:()=>s,metadata:()=>a,toc:()=>d});var r=i(5893),t=i(1151);const s={sidebar_position:1,title:"ADRs"},c="Architecture Decision Records (ADR)",a={id:"adrs/intro",title:"ADRs",description:"This is a location to record all high-level architecture decisions in the Interchain Security project.",source:"@site/versioned_docs/version-v4.2.0-docs/adrs/intro.md",sourceDirName:"adrs",slug:"/adrs/intro",permalink:"/interchain-security/v4.2.0/adrs/intro",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:1,frontMatter:{sidebar_position:1,title:"ADRs"},sidebar:"tutorialSidebar",previous:{title:"Frequently Asked Questions",permalink:"/interchain-security/v4.2.0/faq"},next:{title:"ADR Template",permalink:"/interchain-security/v4.2.0/adrs/adr-004-denom-dos-fixes"}},o={},d=[{value:"Table of Contents",id:"table-of-contents",level:2},{value:"Accepted",id:"accepted",level:3},{value:"Proposed",id:"proposed",level:3},{value:"Rejected",id:"rejected",level:3},{value:"Deprecated",id:"deprecated",level:3}];function h(e){const n={a:"a",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,t.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"architecture-decision-records-adr",children:"Architecture Decision Records (ADR)"}),"\n",(0,r.jsx)(n.p,{children:"This is a location to record all high-level architecture decisions in the Interchain Security project."}),"\n",(0,r.jsxs)(n.p,{children:["You can read more about the ADR concept in this ",(0,r.jsx)(n.a,{href:"https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0#.78xhdix6t",children:"blog post"}),"."]}),"\n",(0,r.jsx)(n.p,{children:"An ADR should provide:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Context on the relevant goals and the current state"}),"\n",(0,r.jsx)(n.li,{children:"Proposed changes to achieve the goals"}),"\n",(0,r.jsx)(n.li,{children:"Summary of pros and cons"}),"\n",(0,r.jsx)(n.li,{children:"References"}),"\n",(0,r.jsx)(n.li,{children:"Changelog"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and\njustification for a change in architecture, or for the architecture of something\nnew. The spec is much more compressed and streamlined summary of everything as\nit is or should be."}),"\n",(0,r.jsx)(n.p,{children:"If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match."}),"\n",(0,r.jsx)(n.p,{children:"Note the context/background should be written in the present tense."}),"\n",(0,r.jsxs)(n.p,{children:["To suggest an ADR, please make use of the ",(0,r.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-template",children:"ADR template"})," provided."]}),"\n",(0,r.jsx)(n.h2,{id:"table-of-contents",children:"Table of Contents"}),"\n",(0,r.jsx)(n.h3,{id:"accepted",children:"Accepted"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-001-key-assignment",children:"ADR 001: Key Assignment"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-002-throttle",children:"ADR 002: Jail Throttling"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-004-denom-dos-fixes",children:"ADR 004: Denom DOS fixes"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-005-cryptographic-equivocation-verification",children:"ADR 005: Cryptographic verification of equivocation evidence"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-008-throttle-retries",children:"ADR 008: Throttle with retries"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-009-soft-opt-out",children:"ADR 009: Soft Opt-Out"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-010-standalone-changeover",children:"ADR 010: Standalone to Consumer Changeover"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-013-equivocation-slashing",children:"ADR 013: Slashing on the provider for consumer equivocation"})}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"proposed",children:"Proposed"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-011-improving-test-confidence",children:"ADR 011: Improving testing and increasing confidence"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-014-epochs",children:"ADR 014: Epochs"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-015-partial-set-security",children:"ADR 015: Partial Set Security"})}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"rejected",children:"Rejected"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop",children:"ADR 007: Pause validator unbonding during equivocation proposal"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-012-separate-releasing",children:"ADR 012: Separate Releasing"})}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"deprecated",children:"Deprecated"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/interchain-security/v4.2.0/adrs/adr-003-equivocation-gov-proposal",children:"ADR 003: Equivocation governance proposal"})}),"\n"]})]})}function l(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>a,a:()=>c});var r=i(7294);const t={},s=r.createContext(t);function c(e){const n=r.useContext(s);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:c(e.components),r.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/ed5b9256.caab0441.js b/assets/js/ed5b9256.caab0441.js new file mode 100644 index 0000000000..5bdcdbe1c9 --- /dev/null +++ b/assets/js/ed5b9256.caab0441.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8081],{8297:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>c,contentTitle:()=>s,default:()=>d,frontMatter:()=>a,metadata:()=>r,toc:()=>h});var i=o(5893),t=o(1151);const a={sidebar_position:1},s="Developing an ICS consumer chain",r={id:"consumer-development/app-integration",title:"Developing an ICS consumer chain",description:"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.",source:"@site/versioned_docs/version-v5.0.0/consumer-development/app-integration.md",sourceDirName:"consumer-development",slug:"/consumer-development/app-integration",permalink:"/interchain-security/v5.0.0/consumer-development/app-integration",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/v5.0.0/features/slashing"},next:{title:"Consumer Chain Governance",permalink:"/interchain-security/v5.0.0/consumer-development/consumer-chain-governance"}},c={},h=[{value:"Basic consumer chain",id:"basic-consumer-chain",level:2},{value:"Democracy consumer chain",id:"democracy-consumer-chain",level:2},{value:"Standalone chain to consumer chain changeover",id:"standalone-chain-to-consumer-chain-changeover",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",...(0,t.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"developing-an-ics-consumer-chain",children:"Developing an ICS consumer chain"}),"\n",(0,i.jsx)(n.p,{children:"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.\nTo help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications."}),"\n",(0,i.jsx)(n.h2,{id:"basic-consumer-chain",children:"Basic consumer chain"}),"\n",(0,i.jsxs)(n.p,{children:["The source code for the example app can be found ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer",children:"here"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"Please note that consumer chains do not implement the staking module - the validator set is replicated from the provider, meaning that the provider and the consumer use the same validator set and their stake on the provider directly determines their stake on the consumer.\nAt present there is no opt-in mechanism available, so all validators of the provider must also validate on the provider chain."}),"\n",(0,i.jsxs)(n.p,{children:["Your chain should import the consumer module from ",(0,i.jsx)(n.code,{children:"x/consumer"})," and register it in the correct places in your ",(0,i.jsx)(n.code,{children:"app.go"}),".\nThe ",(0,i.jsx)(n.code,{children:"x/consumer"})," module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in.\nYou should not need to manage or override any code from the ",(0,i.jsx)(n.code,{children:"x/consumer"})," module."]}),"\n",(0,i.jsx)(n.h2,{id:"democracy-consumer-chain",children:"Democracy consumer chain"}),"\n",(0,i.jsxs)(n.p,{children:["The source code for the example app can be found ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy",children:"here"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["This type of consumer chain wraps the basic CosmosSDK ",(0,i.jsx)(n.code,{children:"x/distribution"}),", ",(0,i.jsx)(n.code,{children:"x/staking"})," and ",(0,i.jsx)(n.code,{children:"x/governance"})," modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system."]}),"\n",(0,i.jsxs)(n.p,{children:["This allows the consumer chain to leverage those modules while also using the ",(0,i.jsx)(n.code,{children:"x/consumer"})," module."]}),"\n",(0,i.jsx)(n.p,{children:'With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.'}),"\n",(0,i.jsx)(n.h2,{id:"standalone-chain-to-consumer-chain-changeover",children:"Standalone chain to consumer chain changeover"}),"\n",(0,i.jsx)(n.p,{children:"This feature is being actively worked on. Information will be provided at a later time."})]})}function d(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},1151:(e,n,o)=>{o.d(n,{Z:()=>r,a:()=>s});var i=o(7294);const t={},a=i.createContext(t);function s(e){const n=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:s(e.components),i.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f0745980.e1109473.js b/assets/js/f0745980.e1109473.js new file mode 100644 index 0000000000..c876d329a3 --- /dev/null +++ b/assets/js/f0745980.e1109473.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7143],{7134:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>c,contentTitle:()=>t,default:()=>h,frontMatter:()=>o,metadata:()=>d,toc:()=>a});var r=n(5893),s=n(1151);const o={sidebar_position:3},t="Interchain Security Parameters",d={id:"introduction/params",title:"Interchain Security Parameters",description:"The parameters necessary for Interchain Security (ICS) are defined in",source:"@site/versioned_docs/version-v5.0.0/introduction/params.md",sourceDirName:"introduction",slug:"/introduction/params",permalink:"/interchain-security/v5.0.0/introduction/params",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Terminology",permalink:"/interchain-security/v5.0.0/introduction/terminology"},next:{title:"Technical Specification",permalink:"/interchain-security/v5.0.0/introduction/technical-specification"}},c={},a=[{value:"Time-Based Parameters",id:"time-based-parameters",level:2},{value:"ProviderUnbondingPeriod",id:"providerunbondingperiod",level:3},{value:"ConsumerUnbondingPeriod",id:"consumerunbondingperiod",level:3},{value:"TrustingPeriodFraction",id:"trustingperiodfraction",level:3},{value:"CCVTimeoutPeriod",id:"ccvtimeoutperiod",level:3},{value:"InitTimeoutPeriod",id:"inittimeoutperiod",level:3},{value:"VscTimeoutPeriod",id:"vsctimeoutperiod",level:3},{value:"BlocksPerDistributionTransmission",id:"blocksperdistributiontransmission",level:3},{value:"TransferPeriodTimeout",id:"transferperiodtimeout",level:3},{value:"Reward Distribution Parameters",id:"reward-distribution-parameters",level:2},{value:"ConsumerRedistributionFraction",id:"consumerredistributionfraction",level:3},{value:"BlocksPerDistributionTransmission",id:"blocksperdistributiontransmission-1",level:3},{value:"TransferTimeoutPeriod",id:"transfertimeoutperiod",level:3},{value:"DistributionTransmissionChannel",id:"distributiontransmissionchannel",level:3},{value:"ProviderFeePoolAddrStr",id:"providerfeepooladdrstr",level:3},{value:"Slash Throttle Parameters",id:"slash-throttle-parameters",level:2},{value:"SlashMeterReplenishPeriod",id:"slashmeterreplenishperiod",level:3},{value:"SlashMeterReplenishFraction",id:"slashmeterreplenishfraction",level:3},{value:"MaxThrottledPackets",id:"maxthrottledpackets",level:3},{value:"RetryDelayPeriod",id:"retrydelayperiod",level:3},{value:"Epoch Parameters",id:"epoch-parameters",level:2},{value:"BlocksPerEpoch",id:"blocksperepoch",level:3}];function l(e){const i={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(i.h1,{id:"interchain-security-parameters",children:"Interchain Security Parameters"}),"\n",(0,r.jsx)(i.p,{children:"The parameters necessary for Interchain Security (ICS) are defined in"}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:["the ",(0,r.jsx)(i.code,{children:"Params"})," structure in ",(0,r.jsx)(i.code,{children:"proto/interchain_security/ccv/provider/v1/provider.proto"})," for the provider;"]}),"\n",(0,r.jsxs)(i.li,{children:["the ",(0,r.jsx)(i.code,{children:"Params"})," structure in ",(0,r.jsx)(i.code,{children:"proto/interchain_security/ccv/consumer/v1/consumer.proto"})," for the consumer."]}),"\n"]}),"\n",(0,r.jsx)(i.h2,{id:"time-based-parameters",children:"Time-Based Parameters"}),"\n",(0,r.jsx)(i.p,{children:"ICS relies on the following time-based parameters."}),"\n",(0,r.jsx)(i.h3,{id:"providerunbondingperiod",children:"ProviderUnbondingPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"ProviderUnbondingPeriod"})," is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance."]}),"\n",(0,r.jsx)(i.h3,{id:"consumerunbondingperiod",children:"ConsumerUnbondingPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"ConsumerUnbondingPeriod"})," is the unbonding period on the consumer chain."]}),"\n",(0,r.jsxs)(i.admonition,{type:"info",children:[(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"ConsumerUnbondingPeriod"})," is set via the ",(0,r.jsx)(i.code,{children:"ConsumerAdditionProposal"})," governance proposal to add a new consumer chain.\nIt is recommended that every consumer chain set and unbonding period shorter than ",(0,r.jsx)(i.code,{children:"ProviderUnbondingPeriod"})]}),(0,r.jsx)("br",{}),(0,r.jsx)(i.p,{children:"Example:"}),(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{children:"ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day\n"})})]}),"\n",(0,r.jsx)(i.p,{children:"Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer."}),"\n",(0,r.jsx)(i.h3,{id:"trustingperiodfraction",children:"TrustingPeriodFraction"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"TrustingPeriodFraction"})," is used to calculate the ",(0,r.jsx)(i.code,{children:"TrustingPeriod"})," of created IBC clients on both provider and consumer chains."]}),"\n",(0,r.jsxs)(i.p,{children:["Setting ",(0,r.jsx)(i.code,{children:"TrustingPeriodFraction"})," to ",(0,r.jsx)(i.code,{children:"0.5"})," would result in the following:"]}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{children:"TrustingPeriodFraction = 0.5\nProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5\nConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5\n"})}),"\n",(0,r.jsxs)(i.p,{children:["Note that a light clients must be updated within the ",(0,r.jsx)(i.code,{children:"TrustingPeriod"})," in order to avoid being frozen."]}),"\n",(0,r.jsxs)(i.p,{children:["For more details, see the ",(0,r.jsx)(i.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/client/ics-007-tendermint-client/README.md",children:"IBC specification of Tendermint clients"}),"."]}),"\n",(0,r.jsx)(i.h3,{id:"ccvtimeoutperiod",children:"CCVTimeoutPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"CCVTimeoutPeriod"})," is the period used to compute the timeout timestamp when sending IBC packets."]}),"\n",(0,r.jsxs)(i.p,{children:["For more details, see the ",(0,r.jsx)(i.a,{href:"https://github.com/cosmos/ibc/blob/main/spec/core/ics-004-channel-and-packet-semantics/README.md#sending-packets",children:"IBC specification of Channel & Packet Semantics"}),"."]}),"\n",(0,r.jsx)(i.admonition,{type:"warning",children:(0,r.jsx)(i.p,{children:"If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed."})}),"\n",(0,r.jsx)(i.p,{children:"CCVTimeoutPeriod may have different values on the provider and consumer chains."}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"CCVTimeoutPeriod"})," on the provider ",(0,r.jsx)(i.strong,{children:"must"})," be larger than ",(0,r.jsx)(i.code,{children:"ConsumerUnbondingPeriod"})]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"CCVTimeoutPeriod"})," on the consumer is initial set via the ",(0,r.jsx)(i.code,{children:"ConsumerAdditionProposal"})]}),"\n"]}),"\n",(0,r.jsx)(i.h3,{id:"inittimeoutperiod",children:"InitTimeoutPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"InitTimeoutPeriod"})," is the maximum allowed duration for CCV channel initialization to execute."]}),"\n",(0,r.jsxs)(i.p,{children:["For any consumer chain, if the CCV channel is not established within ",(0,r.jsx)(i.code,{children:"InitTimeoutPeriod"})," then the consumer chain will be removed and therefore will not be secured by the provider chain."]}),"\n",(0,r.jsxs)(i.p,{children:["The countdown starts when the ",(0,r.jsx)(i.code,{children:"spawn_time"})," specified in the ",(0,r.jsx)(i.code,{children:"ConsumerAdditionProposal"})," is reached."]}),"\n",(0,r.jsx)(i.h3,{id:"vsctimeoutperiod",children:"VscTimeoutPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"VscTimeoutPeriod"})," is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live.\nIf the ",(0,r.jsx)(i.code,{children:"VscTimeoutPeriod"})," is ever reached for a consumer chain that chain will be considered not live and removed from interchain security."]}),"\n",(0,r.jsx)(i.admonition,{type:"tip",children:(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"VscTimeoutPeriod"})," MUST be larger than the ",(0,r.jsx)(i.code,{children:"ConsumerUnbondingPeriod"}),"."]})}),"\n",(0,r.jsx)(i.h3,{id:"blocksperdistributiontransmission",children:"BlocksPerDistributionTransmission"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"BlocksPerDistributionTransmission"})," is the number of blocks between rewards transfers from the consumer to the provider."]}),"\n",(0,r.jsx)(i.h3,{id:"transferperiodtimeout",children:"TransferPeriodTimeout"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"TransferPeriodTimeout"})," is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider."]}),"\n",(0,r.jsxs)(i.p,{children:["If this timeout expires, then the transfer is attempted again after ",(0,r.jsx)(i.code,{children:"BlocksPerDistributionTransmission"})," blocks."]}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"TransferPeriodTimeout"})," on the consumer is initial set via the ",(0,r.jsx)(i.code,{children:"ConsumerAdditionProposal"})," gov proposal to add the consumer"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"TransferPeriodTimeout"})," should be smaller than ",(0,r.jsx)(i.code,{children:"BlocksPerDistributionTransmission x avg_block_time"})]}),"\n"]}),"\n",(0,r.jsx)(i.h2,{id:"reward-distribution-parameters",children:"Reward Distribution Parameters"}),"\n",(0,r.jsx)(i.admonition,{type:"tip",children:(0,r.jsxs)(i.p,{children:["The following chain parameters dictate consumer chain distribution amount and frequency.\nThey are set at consumer genesis and ",(0,r.jsx)(i.code,{children:"BlocksPerDistributionTransmission"}),", ",(0,r.jsx)(i.code,{children:"ConsumerRedistributionFraction"}),"\n",(0,r.jsx)(i.code,{children:"TransferTimeoutPeriod"})," must be provided in every ",(0,r.jsx)(i.code,{children:"ConsumerChainAddition"})," proposal."]})}),"\n",(0,r.jsx)(i.h3,{id:"consumerredistributionfraction",children:"ConsumerRedistributionFraction"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"ConsumerRedistributionFraction"})," is the fraction of tokens allocated to the consumer redistribution address during distribution events. The fraction is a string representing a decimal number. For example ",(0,r.jsx)(i.code,{children:'"0.75"'})," would represent ",(0,r.jsx)(i.code,{children:"75%"}),"."]}),"\n",(0,r.jsxs)(i.admonition,{type:"tip",children:[(0,r.jsx)(i.p,{children:"Example:"}),(0,r.jsxs)(i.p,{children:["With ",(0,r.jsx)(i.code,{children:"ConsumerRedistributionFraction"})," set to ",(0,r.jsx)(i.code,{children:'"0.75"'})," the consumer chain would send ",(0,r.jsx)(i.code,{children:"75%"})," of its block rewards and accumulated fees to the consumer redistribution address, and the remaining ",(0,r.jsx)(i.code,{children:"25%"})," to the provider chain every ",(0,r.jsx)(i.code,{children:"BlocksPerDistributionTransmission"})," blocks."]})]}),"\n",(0,r.jsx)(i.h3,{id:"blocksperdistributiontransmission-1",children:"BlocksPerDistributionTransmission"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"BlocksPerDistributionTransmission"})," is the number of blocks between IBC token transfers from the consumer chain to the provider chain."]}),"\n",(0,r.jsx)(i.h3,{id:"transfertimeoutperiod",children:"TransferTimeoutPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"TransferTimeoutPeriod"})," is the timeout period for consumer chain reward distribution IBC packets."]}),"\n",(0,r.jsx)(i.h3,{id:"distributiontransmissionchannel",children:"DistributionTransmissionChannel"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"DistributionTransmissionChannel"})," is the provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."]}),"\n",(0,r.jsx)(i.h3,{id:"providerfeepooladdrstr",children:"ProviderFeePoolAddrStr"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"ProviderFeePoolAddrStr"})," is the provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."]}),"\n",(0,r.jsx)(i.h2,{id:"slash-throttle-parameters",children:"Slash Throttle Parameters"}),"\n",(0,r.jsx)(i.h3,{id:"slashmeterreplenishperiod",children:"SlashMeterReplenishPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"SlashMeterReplenishPeriod"})," exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed."]}),"\n",(0,r.jsxs)(i.p,{children:["The meter is replenished to an amount equal to the slash meter allowance for that block, or ",(0,r.jsx)(i.code,{children:"SlashMeterReplenishFraction * CurrentTotalVotingPower"}),"."]}),"\n",(0,r.jsx)(i.h3,{id:"slashmeterreplenishfraction",children:"SlashMeterReplenishFraction"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"SlashMeterReplenishFraction"})," exists on the provider as the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs."]}),"\n",(0,r.jsxs)(i.p,{children:["This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a ",(0,r.jsx)(i.code,{children:"sdk.Dec"})," when used."]}),"\n",(0,r.jsx)(i.h3,{id:"maxthrottledpackets",children:"MaxThrottledPackets"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"MaxThrottledPackets"})," exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value."]}),"\n",(0,r.jsx)(i.p,{children:"This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness."}),"\n",(0,r.jsx)(i.admonition,{type:"info",children:(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"MaxThrottledPackets"})," was deprecated in ICS versions >= v3.2.0 due to the implementation of ",(0,r.jsx)(i.a,{href:"/interchain-security/v5.0.0/adrs/adr-008-throttle-retries",children:"ADR-008"}),"."]})}),"\n",(0,r.jsx)(i.h3,{id:"retrydelayperiod",children:"RetryDelayPeriod"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"RetryDelayPeriod"})," exists on the consumer for ",(0,r.jsx)(i.strong,{children:"ICS versions >= v3.2.0"})," (introduced by the implementation of ",(0,r.jsx)(i.a,{href:"/interchain-security/v5.0.0/adrs/adr-008-throttle-retries",children:"ADR-008"}),") and is the period at which the consumer retries to send a ",(0,r.jsx)(i.code,{children:"SlashPacket"})," that was rejected by the provider."]}),"\n",(0,r.jsx)(i.h2,{id:"epoch-parameters",children:"Epoch Parameters"}),"\n",(0,r.jsx)(i.h3,{id:"blocksperepoch",children:"BlocksPerEpoch"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"BlocksPerEpoch"})," exists on the provider for ",(0,r.jsx)(i.strong,{children:"ICS versions >= 3.3.0"})," (introduced by the implementation of ",(0,r.jsx)(i.a,{href:"/interchain-security/v5.0.0/adrs/adr-014-epochs",children:"ADR-014"}),")\nand corresponds to the number of blocks that constitute an epoch. This param is set to 600 by default. Assuming we need 6 seconds to\ncommit a block, the duration of an epoch corresponds to 1 hour. This means that a ",(0,r.jsx)(i.code,{children:"VSCPacket"})," would be sent to a consumer\nchain once at the end of every epoch, so once every 600 blocks. This parameter can be adjusted via a governance proposal,\nhowever careful consideration is needed so that ",(0,r.jsx)(i.code,{children:"BlocksPerEpoch"})," is not too large. A large ",(0,r.jsx)(i.code,{children:"BlocksPerEpoch"})," could lead to a delay\nof ",(0,r.jsx)(i.code,{children:"VSCPacket"}),"s and hence potentially lead to ",(0,r.jsx)(i.a,{href:"https://informal.systems/blog/learning-to-live-with-unbonding-pausing",children:"unbonding pausing"}),".\nFor setting ",(0,r.jsx)(i.code,{children:"BlocksPerEpoch"}),", we also need to consider potential slow chain upgrades that could delay the sending of a\n",(0,r.jsx)(i.code,{children:"VSCPacket"}),", as well as potential increases in the time it takes to commit a block (e.g., from 6 seconds to 30 seconds)."]})]})}function h(e={}){const{wrapper:i}={...(0,s.a)(),...e.components};return i?(0,r.jsx)(i,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},1151:(e,i,n)=>{n.d(i,{Z:()=>d,a:()=>t});var r=n(7294);const s={},o=r.createContext(s);function t(e){const i=r.useContext(o);return r.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function d(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:t(e.components),r.createElement(o.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f5589540.4abf59ac.js b/assets/js/f5589540.4abf59ac.js new file mode 100644 index 0000000000..207bdbb845 --- /dev/null +++ b/assets/js/f5589540.4abf59ac.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6499],{5573:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>s,default:()=>m,frontMatter:()=>r,metadata:()=>i,toc:()=>h});var o=t(5893),a=t(1151);const r={sidebar_position:2},s="Consumer Chain Governance",i={id:"consumer-development/consumer-chain-governance",title:"Consumer Chain Governance",description:'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.',source:"@site/docs/consumer-development/consumer-chain-governance.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-chain-governance",permalink:"/interchain-security/consumer-development/consumer-chain-governance",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/consumer-development/app-integration"},next:{title:"Onboarding Checklist",permalink:"/interchain-security/consumer-development/onboarding"}},c={},h=[{value:"Democracy module",id:"democracy-module",level:2},{value:"CosmWasm",id:"cosmwasm",level:2},{value:"The Whitelist",id:"the-whitelist",level:2}];function l(e){const n={a:"a",h1:"h1",h2:"h2",p:"p",...(0,a.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"consumer-chain-governance",children:"Consumer Chain Governance"}),"\n",(0,o.jsx)(n.p,{children:'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.'}),"\n",(0,o.jsx)(n.h2,{id:"democracy-module",children:"Democracy module"}),"\n",(0,o.jsx)(n.p,{children:"The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy."}),"\n",(0,o.jsx)(n.p,{children:"Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus."}),"\n",(0,o.jsxs)(n.p,{children:["For an example, see the ",(0,o.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy",children:"Democracy Consumer"})]}),"\n",(0,o.jsx)(n.h2,{id:"cosmwasm",children:"CosmWasm"}),"\n",(0,o.jsx)(n.p,{children:"There are several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain."}),"\n",(0,o.jsxs)(n.p,{children:["For an example, see ",(0,o.jsx)(n.a,{href:"https://github.com/neutron-org/neutron/",children:"Neutron"}),"."]}),"\n",(0,o.jsx)(n.h2,{id:"the-whitelist",children:"The Whitelist"}),"\n",(0,o.jsxs)(n.p,{children:["Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see ",(0,o.jsx)(n.a,{href:"https://github.com/neutron-org/neutron/blob/main/app/proposals_allowlisting.go",children:"Neutron's"})," whitelist."]})]})}function m(e={}){const{wrapper:n}={...(0,a.a)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>i,a:()=>s});var o=t(7294);const a={},r=o.createContext(a);function s(e){const n=o.useContext(r);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:s(e.components),o.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f6addb2b.aca89816.js b/assets/js/f6addb2b.aca89816.js new file mode 100644 index 0000000000..a1f51b7d8f --- /dev/null +++ b/assets/js/f6addb2b.aca89816.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[35],{279:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>l,frontMatter:()=>a,metadata:()=>o,toc:()=>h});var s=i(5893),t=i(1151);const a={sidebar_position:1},r="Overview",o={id:"validators/overview",title:"Overview",description:"We advise that you join the Interchain Security testnet to gain hands-on experience with running consumer chains.",source:"@site/docs/validators/overview.md",sourceDirName:"validators",slug:"/validators/overview",permalink:"/interchain-security/validators/overview",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Consumer Genesis Transformation",permalink:"/interchain-security/consumer-development/consumer-genesis-transformation"},next:{title:"Joining Interchain Security testnet",permalink:"/interchain-security/validators/joining-testnet"}},c={},h=[{value:"Startup sequence overview",id:"startup-sequence-overview",level:2},{value:"1. Consumer Chain init + 2. Genesis generation",id:"1-consumer-chain-init--2-genesis-generation",level:3},{value:"3. Submit Proposal",id:"3-submit-proposal",level:3},{value:"4. CCV Genesis state generation",id:"4-ccv-genesis-state-generation",level:3},{value:"5. Updating the genesis file",id:"5-updating-the-genesis-file",level:3},{value:"6. Chain start",id:"6-chain-start",level:3},{value:"7. Creating IBC connections",id:"7-creating-ibc-connections",level:3},{value:"Downtime Infractions",id:"downtime-infractions",level:2},{value:"Double-signing Infractions",id:"double-signing-infractions",level:2},{value:"Key assignment",id:"key-assignment",level:2},{value:"References:",id:"references",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"overview",children:"Overview"}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["We advise that you join the ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/testnets/tree/master/interchain-security",children:"Interchain Security testnet"})," to gain hands-on experience with running consumer chains."]})}),"\n",(0,s.jsxs)(n.p,{children:["At present, Interchain Security requires some or all the validators of the provider chain (ie. Cosmos Hub) to run validator nodes for a consumer chain.\nWhether a validator has to run a validator node for a consumer chain depends on whether the consumer chain is a Top N or an\nOpt-In chain and also on the ",(0,s.jsx)(n.a,{href:"/interchain-security/features/power-shaping",children:"power-shaping features"}),". A validator can use the\n",(0,s.jsxs)(n.a,{href:"/interchain-security/validators/partial-set-security-for-validators#which-chains-does-a-validator-have-to-validate",children:[(0,s.jsx)(n.code,{children:"has-to-validate"})," query"]}),"\nto keep track of all the chains it has to validate."]}),"\n",(0,s.jsxs)(n.p,{children:["Once a ",(0,s.jsx)(n.code,{children:"ConsumerAdditionProposal"})," passes, relevant validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains."]}),"\n",(0,s.jsx)(n.p,{children:"Provider chain and consumer chains represent standalone chains that only share part of the validator set."}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsx)(n.p,{children:"To validate a consumer chain and be eligible for rewards, validators are required to be in the active set of the provider chain (first 180 validators for Cosmos Hub)."})}),"\n",(0,s.jsx)(n.h2,{id:"startup-sequence-overview",children:"Startup sequence overview"}),"\n",(0,s.jsxs)(n.p,{children:["Consumer chains cannot start and be secured by the validator set of the provider unless a ",(0,s.jsx)(n.code,{children:"ConsumerAdditionProposal"})," is passed.\nEach proposal contains defines a ",(0,s.jsx)(n.code,{children:"spawn_time"})," - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider."]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["Validators are required to run consumer chain binaries only after ",(0,s.jsx)(n.code,{children:"spawn_time"})," has passed."]})}),"\n",(0,s.jsx)(n.p,{children:"Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains."}),"\n",(0,s.jsxs)(n.p,{children:["The image below illustrates the startup sequence\n",(0,s.jsx)(n.img,{alt:"startup",src:i(4090).Z+"",width:"942",height:"632"})]}),"\n",(0,s.jsx)(n.h3,{id:"1-consumer-chain-init--2-genesis-generation",children:"1. Consumer Chain init + 2. Genesis generation"}),"\n",(0,s.jsxs)(n.p,{children:["Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ",(0,s.jsx)(n.code,{children:"ConsumerAdditionProposal"})]}),"\n",(0,s.jsx)(n.h3,{id:"3-submit-proposal",children:"3. Submit Proposal"}),"\n",(0,s.jsxs)(n.p,{children:["Consumer chain team (or their advocates) submits a ",(0,s.jsx)(n.code,{children:"ConsumerAdditionProposal"}),".\nThe most important parameters for validators are:"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"spawn_time"})," - the time after which the consumer chain must be started"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"genesis_hash"})," - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and ",(0,s.jsx)(n.code,{children:"spawn_time"})," is reached"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"binary_hash"})," - hash of the consumer chain binary used to validate the software builds"]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"4-ccv-genesis-state-generation",children:"4. CCV Genesis state generation"}),"\n",(0,s.jsxs)(n.p,{children:["After reaching ",(0,s.jsx)(n.code,{children:"spawn_time"})," the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain ",(0,s.jsx)(n.code,{children:"genesis.json"}),". The CCV validator set consists of the validator set on the provider at ",(0,s.jsx)(n.code,{children:"spawn_time"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"The state can be queried on the provider chain (in this case the Cosmos Hub):"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:" gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This is used by the launch coordinator to create the final ",(0,s.jsx)(n.code,{children:"genesis.json"})," that will be distributed to validators in step 5."]}),"\n",(0,s.jsx)(n.h3,{id:"5-updating-the-genesis-file",children:"5. Updating the genesis file"}),"\n",(0,s.jsxs)(n.p,{children:["Upon reaching the ",(0,s.jsx)(n.code,{children:"spawn_time"})," the initial validator set state will become available on the provider chain. The initial validator set is included in the ",(0,s.jsx)(n.strong,{children:"final genesis.json"})," of the consumer chain."]}),"\n",(0,s.jsx)(n.h3,{id:"6-chain-start",children:"6. Chain start"}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsx)(n.p,{children:"The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences."})}),"\n",(0,s.jsxs)(n.p,{children:["The new ",(0,s.jsx)(n.code,{children:"genesis.json"})," containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided ",(0,s.jsx)(n.code,{children:"genesis.json"})," to start their consumer chain node."]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["Please pay attention to any onboarding repositories provided by the consumer chain teams.\nRecommendations are available in ",(0,s.jsx)(n.a,{href:"/interchain-security/consumer-development/onboarding",children:"Consumer Onboarding Checklist"}),".\nAnother comprehensive guide is available in the ",(0,s.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/CONSUMER_LAUNCH_GUIDE.md",children:"Interchain Security testnet repo"}),"."]})}),"\n",(0,s.jsx)(n.h3,{id:"7-creating-ibc-connections",children:"7. Creating IBC connections"}),"\n",(0,s.jsx)(n.p,{children:"Finally, to fully establish interchain security an IBC relayer is used to establish connections and create the required channels."}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsx)(n.p,{children:"The relayer can establish the connection only after the consumer chain starts producing blocks."})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> \nhermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1\nhermes start\n"})}),"\n",(0,s.jsx)(n.h2,{id:"downtime-infractions",children:"Downtime Infractions"}),"\n",(0,s.jsxs)(n.p,{children:["At present, the consumer chain can report evidence about downtime infractions to the provider chain. The ",(0,s.jsx)(n.code,{children:"min_signed_per_window"})," and ",(0,s.jsx)(n.code,{children:"signed_blocks_window"})," can be different on each consumer chain and are subject to changes via consumer chain governance."]}),"\n",(0,s.jsxs)(n.admonition,{type:"info",children:[(0,s.jsx)(n.p,{children:"Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains."}),(0,s.jsxs)(n.p,{children:["To unjail, the validator must wait for the jailing period to elapse on the provider chain and ",(0,s.jsx)(n.a,{href:"https://hub.cosmos.network/main/validators/validator-setup#unjail-validator",children:"submit an unjail transaction"})," on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains."]}),(0,s.jsxs)(n.p,{children:["More information is available in ",(0,s.jsx)(n.a,{href:"/interchain-security/features/slashing#downtime-infractions",children:"Downtime Slashing documentation"})]})]}),"\n",(0,s.jsx)(n.h2,{id:"double-signing-infractions",children:"Double-signing Infractions"}),"\n",(0,s.jsxs)(n.p,{children:["To learn more about equivocation handling in interchain security check out the ",(0,s.jsx)(n.a,{href:"/interchain-security/features/slashing",children:"Slashing"})," documentation section."]}),"\n",(0,s.jsx)(n.h2,{id:"key-assignment",children:"Key assignment"}),"\n",(0,s.jsx)(n.p,{children:"Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use."}),"\n",(0,s.jsxs)(n.p,{children:["For more information check out the ",(0,s.jsx)(n.a,{href:"/interchain-security/features/key-assignment",children:"Key assignment overview and guide"})]}),"\n",(0,s.jsx)(n.h2,{id:"references",children:"References:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://hub.cosmos.network/main/validators/validator-faq",children:"Cosmos Hub Validators FAQ"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://hub.cosmos.network/main/validators/validator-setup",children:"Cosmos Hub Running a validator"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://github.com/cosmos/testnets/blob/master/interchain-security/CONSUMER_LAUNCH_GUIDE.md#chain-launch",children:"Startup Sequence"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://hub.cosmos.network/main/validators/validator-setup#unjail-validator",children:"Submit Unjailing Transaction"})}),"\n"]})]})}function l(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},4090:(e,n,i)=>{i.d(n,{Z:()=>s});const s=i.p+"assets/images/hypha-consumer-start-process-2141109f76c584706dd994d7965fd692.svg"},1151:(e,n,i)=>{i.d(n,{Z:()=>o,a:()=>r});var s=i(7294);const t={},a=s.createContext(t);function r(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:r(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f8a7cbf6.7e411975.js b/assets/js/f8a7cbf6.7e411975.js new file mode 100644 index 0000000000..388cc41380 --- /dev/null +++ b/assets/js/f8a7cbf6.7e411975.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2527],{4097:(e,r,n)=>{n.r(r),n.d(r,{assets:()=>o,contentTitle:()=>t,default:()=>h,frontMatter:()=>s,metadata:()=>d,toc:()=>c});var a=n(5893),i=n(1151);const s={sidebar_position:3},t="Withdrawing consumer chain validator rewards",d={id:"validators/withdraw_rewards",title:"Withdrawing consumer chain validator rewards",description:"Here are example steps for withdrawing rewards from consumer chains in the provider chain",source:"@site/versioned_docs/version-v5.0.0/validators/withdraw_rewards.md",sourceDirName:"validators",slug:"/validators/withdraw_rewards",permalink:"/interchain-security/v5.0.0/validators/withdraw_rewards",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Joining Interchain Security testnet",permalink:"/interchain-security/v5.0.0/validators/joining-testnet"},next:{title:"Validator Instructions for Changeover Procedure",permalink:"/interchain-security/v5.0.0/validators/changeover-procedure"}},o={},c=[{value:"Querying validator rewards",id:"querying-validator-rewards",level:2},{value:"Withdrawing rewards and commission",id:"withdrawing-rewards-and-commission",level:2},{value:"1. Withdraw rewards",id:"1-withdraw-rewards",level:3},{value:"2. Confirm withdrawal",id:"2-confirm-withdrawal",level:3}];function l(e){const r={admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,i.a)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(r.h1,{id:"withdrawing-consumer-chain-validator-rewards",children:"Withdrawing consumer chain validator rewards"}),"\n",(0,a.jsx)(r.p,{children:"Here are example steps for withdrawing rewards from consumer chains in the provider chain"}),"\n",(0,a.jsxs)(r.admonition,{type:"info",children:[(0,a.jsxs)(r.p,{children:["The examples used are from ",(0,a.jsx)(r.code,{children:"rs-testnet"}),", the replicated security persistent testnet."]}),(0,a.jsxs)(r.p,{children:["Validator operator address: ",(0,a.jsx)(r.code,{children:"cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6"}),"\nSelf-delegation address: ",(0,a.jsx)(r.code,{children:"cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf"})]})]}),"\n",(0,a.jsx)(r.p,{children:"Prior to withdrawing rewards, query balances for self-delegation address:"}),"\n",(0,a.jsx)(r.pre,{children:(0,a.jsx)(r.code,{className:"language-bash",children:'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "1000000000000"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n'})}),"\n",(0,a.jsx)(r.h2,{id:"querying-validator-rewards",children:"Querying validator rewards"}),"\n",(0,a.jsx)(r.p,{children:"Query rewards for the validator address:"}),"\n",(0,a.jsx)(r.pre,{children:(0,a.jsx)(r.code,{className:"language-bash",children:'gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6\n\nrewards:\n- amount: "158.069895000000000000"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "841842390516.072526500000000000"\n denom: uatom\n'})}),"\n",(0,a.jsxs)(r.p,{children:["The ",(0,a.jsx)(r.code,{children:"ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD"})," denom represents rewards from a consumer chain."]}),"\n",(0,a.jsx)(r.h2,{id:"withdrawing-rewards-and-commission",children:"Withdrawing rewards and commission"}),"\n",(0,a.jsx)(r.h3,{id:"1-withdraw-rewards",children:"1. Withdraw rewards"}),"\n",(0,a.jsx)(r.pre,{children:(0,a.jsx)(r.code,{className:"language-bash",children:"gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y\n\ntxhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A\n"})}),"\n",(0,a.jsx)(r.h3,{id:"2-confirm-withdrawal",children:"2. Confirm withdrawal"}),"\n",(0,a.jsx)(r.p,{children:"After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:"}),"\n",(0,a.jsx)(r.pre,{children:(0,a.jsx)(r.code,{className:"language-bash",children:'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "216"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "2233766225342"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n'})})]})}function h(e={}){const{wrapper:r}={...(0,i.a)(),...e.components};return r?(0,a.jsx)(r,{...e,children:(0,a.jsx)(l,{...e})}):l(e)}},1151:(e,r,n)=>{n.d(r,{Z:()=>d,a:()=>t});var a=n(7294);const i={},s=a.createContext(i);function t(e){const r=a.useContext(s);return a.useMemo((function(){return"function"==typeof e?e(r):{...r,...e}}),[r,e])}function d(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:t(e.components),a.createElement(s.Provider,{value:r},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/fc26cd25.e6be4cde.js b/assets/js/fc26cd25.e6be4cde.js new file mode 100644 index 0000000000..a10654c3d5 --- /dev/null +++ b/assets/js/fc26cd25.e6be4cde.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9198],{6801:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>a,toc:()=>c});var s=t(5893),i=t(1151);const o={sidebar_position:2,title:"ADR Template"},r="ADR [ADR-NUMBER]: [TITLE]",a={id:"adrs/adr-template",title:"ADR Template",description:"Changelog",source:"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-template.md",sourceDirName:"adrs",slug:"/adrs/adr-template",permalink:"/interchain-security/v4.2.0/adrs/adr-template",draft:!1,unlisted:!1,tags:[],version:"v4.2.0-docs",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"ADR Template"},sidebar:"tutorialSidebar",previous:{title:"ADR Template",permalink:"/interchain-security/v4.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop"},next:{title:"Key Assignment",permalink:"/interchain-security/v4.2.0/adrs/adr-001-key-assignment"}},l={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function d(e){const n={blockquote:"blockquote",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,i.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"adr-adr-number-title",children:"ADR [ADR-NUMBER]: [TITLE]"}),"\n",(0,s.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:'A decision may be "proposed" if it hasn\'t been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement.'}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"[Deprecated|Proposed|Accepted]"}),"\n",(0,s.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution."}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"This section explains all of the details of the proposed solution, including implementation details.\nIt should also describe affects / corollary items that may need to be changed as a part of this.\nIf the proposed change will be large, please also indicate a way to do the change to maximize ease of review.\n(e.g. the optimal split of things to do between separate PR's)"}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:'This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones.'}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,s.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,s.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,s.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!"}),"\n"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"[references]"}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>a,a:()=>r});var s=t(7294);const i={},o=s.createContext(i);function r(e){const n=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/ff0782b1.cbedc7fd.js b/assets/js/ff0782b1.cbedc7fd.js new file mode 100644 index 0000000000..79b1be05c8 --- /dev/null +++ b/assets/js/ff0782b1.cbedc7fd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7540],{3769:e=>{e.exports=JSON.parse('{"name":"docusaurus-plugin-content-docs","id":"default"}')}}]); \ No newline at end of file diff --git a/assets/js/ff9311cc.0e55d588.js b/assets/js/ff9311cc.0e55d588.js new file mode 100644 index 0000000000..a375ab532f --- /dev/null +++ b/assets/js/ff9311cc.0e55d588.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5051],{151:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>l,frontMatter:()=>o,metadata:()=>a,toc:()=>h});var i=t(5893),s=t(1151);const o={sidebar_position:15,title:"Epochs"},r="ADR 014: Epochs",a={id:"adrs/adr-014-epochs",title:"Epochs",description:"Changelog",source:"@site/versioned_docs/version-v5.0.0/adrs/adr-014-epochs.md",sourceDirName:"adrs",slug:"/adrs/adr-014-epochs",permalink:"/interchain-security/v5.0.0/adrs/adr-014-epochs",draft:!1,unlisted:!1,tags:[],version:"v5.0.0",sidebarPosition:15,frontMatter:{sidebar_position:15,title:"Epochs"},sidebar:"tutorialSidebar",previous:{title:"Slashing on the provider for consumer equivocation",permalink:"/interchain-security/v5.0.0/adrs/adr-013-equivocation-slashing"},next:{title:"Partial Set Security",permalink:"/interchain-security/v5.0.0/adrs/adr-015-partial-set-security"}},c={},h=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}];function d(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"adr-014-epochs",children:"ADR 014: Epochs"}),"\n",(0,i.jsx)(n.h2,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"2024-01-05: Proposed, first draft of ADR."}),"\n",(0,i.jsx)(n.li,{children:"2024-02-29: Updated so that it describes the implementation where we store the whole consumer validator set."}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"status",children:"Status"}),"\n",(0,i.jsx)(n.p,{children:"Proposed"}),"\n",(0,i.jsx)(n.h2,{id:"context",children:"Context"}),"\n",(0,i.jsxs)(n.p,{children:["In every block that the provider valset changes, a ",(0,i.jsx)(n.code,{children:"VSCPacket"})," must be sent to every consumer and a corresponding ",(0,i.jsx)(n.code,{children:"VSCMaturedPacket"})," sent back.\nGiven that the validator powers may change very often on the provider chain (e.g., the Cosmos Hub), this approach results in a large workload for the relayers.\nAlthough the validator powers may change very often, these changes are usually small and have an insignificant impact on the chain's security.\nIn other words, the valset on the consumers can be slightly outdated without affecting security.\nAs a matter of fact, this already happens due to relaying delays."]}),"\n",(0,i.jsxs)(n.p,{children:["As a solution, this ADR introduces the concept of ",(0,i.jsx)(n.em,{children:"epochs"}),".\nAn epoch consists of multiple blocks.\nThe provider sends ",(0,i.jsx)(n.code,{children:"VSCPacket"}),"s once per epoch.\nA ",(0,i.jsx)(n.code,{children:"VSCPacket"})," contains all the validator updates that are needed by a consumer chain."]}),"\n",(0,i.jsx)(n.h2,{id:"decision",children:"Decision"}),"\n",(0,i.jsx)(n.p,{children:"The implementation of epochs requires the following changes:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"For each consumer chain, we store the consumer validator set that is currently (i.e., in this epoch) validating the\nconsumer chain. For each validator in the set we store i) its voting power, and ii) the public key that it is\nusing on the consumer chain during the current (i.e., ongoing) epoch.\nThe initial consumer validator set for a chain is set during the creation of the consumer genesis."}),"\n",(0,i.jsxs)(n.li,{children:["We introduce the ",(0,i.jsx)(n.code,{children:"BlocksPerEpoch"})," param that sets the number of blocks in an epoch. By default, ",(0,i.jsx)(n.code,{children:"BlocksPerEpoch"})," is\nset to be 600 which corresponds to 1 hour, assuming 6 seconds per block. This param can be changed through\na ",(0,i.jsx)(n.em,{children:"governance proposal"}),". In the provider ",(0,i.jsx)(n.code,{children:"EndBlock"})," we check ",(0,i.jsx)(n.code,{children:"BlockHeight() % BlocksPerEpoch() == 0"}),"\nto decide when an epoch has ended."]}),"\n",(0,i.jsxs)(n.li,{children:["At the end of every epoch, if there were validator set changes on the provider, then for every consumer chain, we\nconstruct a ",(0,i.jsx)(n.code,{children:"VSCPacket"})," with all the validator updates and add it to the list of ",(0,i.jsx)(n.code,{children:"PendingVSCPackets"}),". We compute the\nvalidator updates needed by a consumer chain by comparing the stored list of consumer validators with the current\nbonded validators on the provider, with something similar to this:"]}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-go",children:"// get the valset that has been validating the consumer chain during this epoch \ncurrentValidators := GetConsumerValSet(consumerChain)\n// generate the validator updates needed to be sent through a `VSCPacket` by comparing the current validators \n// in the epoch with the latest bonded validators\nvalUpdates := DiffValidators(currentValidators, stakingmodule.GetBondedValidators())\n// update the current validators set for the upcoming epoch to be the latest bonded validators instead\nSetConsumerValSet(stakingmodule.GetBondedValidators())\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Note that a validator can change its consumer public key for a specific consumer chain an arbitrary amount of times during\na block and during an epoch. Then, when we generate the validator updates in ",(0,i.jsx)(n.code,{children:"DiffValidators"}),", we have to check whether\nthe current consumer public key (retrieved by calling ",(0,i.jsx)(n.code,{children:"GetValidatorConsumerPubKey"}),") is different from the consumer public\nkey the validator was using in the current epoch."]}),"\n",(0,i.jsx)(n.h2,{id:"consequences",children:"Consequences"}),"\n",(0,i.jsx)(n.h3,{id:"positive",children:"Positive"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Reduce the cost of relaying."}),"\n",(0,i.jsx)(n.li,{children:"Reduce the amount of IBC packets needed for ICS."}),"\n",(0,i.jsxs)(n.li,{children:["Simplifies ",(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-001-key-assignment.md",children:"key-assignment code"})," because\nwe only need to check if the ",(0,i.jsx)(n.code,{children:"consumer_public_key"})," has been modified since the last epoch to generate an update."]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"negative",children:"Negative"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Increase the delay in the propagation of validator set changes (but for reasonable epoch lengths on the order of ~hours or less, this is unlikely to be significant)."}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"neutral",children:"Neutral"}),"\n",(0,i.jsx)(n.p,{children:"N/A"}),"\n",(0,i.jsx)(n.h2,{id:"references",children:"References"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/cosmos/interchain-security/issues/1087",children:"EPIC"})}),"\n"]})]})}function l(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>a,a:()=>r});var i=t(7294);const s={},o=i.createContext(s);function r(e){const n=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),i.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/main.11e71de7.js b/assets/js/main.11e71de7.js new file mode 100644 index 0000000000..5a2aefc146 --- /dev/null +++ b/assets/js/main.11e71de7.js @@ -0,0 +1,2 @@ +/*! For license information please see main.11e71de7.js.LICENSE.txt */ +(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[179],{723:(e,t,n)=>{"use strict";n.d(t,{Z:()=>p});n(7294);var r=n(8356),a=n.n(r),i=n(6887);const o={"00147ff4":[()=>n.e(2110).then(n.bind(n,9075)),"@site/docs/frequently-asked-questions.md",9075],"06b45df8":[()=>n.e(9599).then(n.t.bind(n,4562,19)),"~docs/default/version-v-5-0-0-metadata-prop-841.json",4562],"07d76e7d":[()=>n.e(2189).then(n.bind(n,7488)),"@site/docs/features/key-assignment.md",7488],"0cb1d302":[()=>n.e(1085).then(n.bind(n,5398)),"@site/docs/validators/joining-neutron.md",5398],"1097399d":[()=>n.e(6548).then(n.bind(n,5191)),"@site/versioned_docs/version-v5.0.0/adrs/adr-011-improving-test-confidence.md",5191],"16d4e57d":[()=>n.e(5387).then(n.bind(n,1258)),"@site/versioned_docs/version-v5.0.0/introduction/terminology.md",1258],17896441:[()=>Promise.all([n.e(532),n.e(7918)]).then(n.bind(n,7078)),"@theme/DocItem",7078],"1ae81764":[()=>n.e(2262).then(n.bind(n,9436)),"@site/versioned_docs/version-v4.2.0-docs/introduction/terminology.md",9436],"1ca82e41":[()=>n.e(7617).then(n.bind(n,1343)),"@site/versioned_docs/version-v5.0.0/consumer-development/consumer-genesis-transformation.md",1343],"21cfc626":[()=>n.e(52).then(n.bind(n,964)),"@site/versioned_docs/version-v5.0.0/index.mdx",964],"21dfdb60":[()=>n.e(5932).then(n.bind(n,2702)),"@site/versioned_docs/version-v5.0.0/adrs/adr-template.md",2702],"2510f7b4":[()=>n.e(2558).then(n.bind(n,6250)),"@site/versioned_docs/version-v4.2.0-docs/validators/joining-neutron.md",6250],"26981f24":[()=>n.e(1483).then(n.bind(n,5183)),"@site/versioned_docs/version-v5.0.0/consumer-development/changeover-procedure.md",5183],"287de311":[()=>n.e(7184).then(n.bind(n,3879)),"@site/versioned_docs/version-v4.2.0-docs/validators/overview.md",3879],"2a9fa04d":[()=>n.e(3670).then(n.bind(n,8328)),"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-008-throttle-retries.md",8328],"2c92eef1":[()=>n.e(3158).then(n.bind(n,6386)),"@site/versioned_docs/version-v5.0.0/introduction/technical-specification.md",6386],"2ed06975":[()=>n.e(1038).then(n.bind(n,439)),"@site/versioned_docs/version-v5.0.0/adrs/intro.md",439],"3672b5b7":[()=>n.e(320).then(n.bind(n,9873)),"@site/docs/introduction/params.md",9873],"3ec9db48":[()=>n.e(8233).then(n.bind(n,4554)),"@site/versioned_docs/version-v4.2.0-docs/features/reward-distribution.md",4554],"3f3637cb":[()=>n.e(3596).then(n.bind(n,9529)),"@site/versioned_docs/version-v4.2.0-docs/introduction/overview.md",9529],"3f869ff5":[()=>n.e(4470).then(n.bind(n,4522)),"@site/versioned_docs/version-v4.2.0-docs/features/power-shaping.md",4522],"405e8773":[()=>n.e(5180).then(n.bind(n,1912)),"@site/versioned_docs/version-v4.2.0-docs/validators/joining-testnet.md",1912],"4106f1c5":[()=>n.e(842).then(n.bind(n,7049)),"@site/docs/features/slashing.md",7049],"4179ee03":[()=>n.e(6073).then(n.bind(n,2069)),"@site/docs/upgrading/migrate_v4_v5.md",2069],"425bba28":[()=>n.e(1118).then(n.bind(n,737)),"@site/docs/consumer-development/consumer-genesis-transformation.md",737],"434502c4":[()=>n.e(411).then(n.bind(n,854)),"@site/versioned_docs/version-v5.0.0/features/slashing.md",854],"46057b98":[()=>n.e(3159).then(n.bind(n,8812)),"@site/docs/adrs/adr-003-equivocation-gov-proposal.md",8812],"491e9485":[()=>n.e(6784).then(n.bind(n,953)),"@site/versioned_docs/version-v5.0.0/adrs/adr-008-throttle-retries.md",953],"4c7d82ee":[()=>n.e(7649).then(n.bind(n,1915)),"@site/docs/adrs/adr-005-cryptographic-equivocation-verification.md",1915],"4edc808e":[()=>n.e(4173).then(n.bind(n,7559)),"@site/docs/index.mdx",7559],"4edefe03":[()=>n.e(918).then(n.bind(n,7168)),"@site/versioned_docs/version-v5.0.0/adrs/adr-005-cryptographic-equivocation-verification.md",7168],"4f50acdf":[()=>n.e(9815).then(n.bind(n,7125)),"@site/docs/validators/joining-testnet.md",7125],53123775:[()=>n.e(2234).then(n.bind(n,8621)),"@site/versioned_docs/version-v5.0.0/upgrading/migrate_v4_v5.md",8621],"536acd9c":[()=>n.e(4279).then(n.bind(n,8276)),"@site/versioned_docs/version-v4.2.0-docs/validators/changeover-procedure.md",8276],"54e4400b":[()=>n.e(2344).then(n.bind(n,6064)),"@site/docs/adrs/adr-001-key-assignment.md",6064],"578fb1aa":[()=>n.e(2323).then(n.bind(n,8522)),"@site/docs/features/reward-distribution.md",8522],"5cdffc34":[()=>n.e(4895).then(n.bind(n,8961)),"@site/versioned_docs/version-v5.0.0/validators/overview.md",8961],"5cee3276":[()=>n.e(1996).then(n.bind(n,434)),"@site/versioned_docs/version-v5.0.0/introduction/overview.md",434],"5e95c892":[()=>n.e(9661).then(n.bind(n,1892)),"@theme/DocsRoot",1892],"5fa9786a":[()=>n.e(2341).then(n.bind(n,5370)),"@site/versioned_docs/version-v4.2.0-docs/consumer-development/consumer-genesis-transformation.md",5370],"61e9b0fd":[()=>n.e(5402).then(n.bind(n,5615)),"@site/versioned_docs/version-v5.0.0/frequently-asked-questions.md",5615],"624b8b53":[()=>n.e(9709).then(n.bind(n,1461)),"@site/versioned_docs/version-v5.0.0/adrs/adr-012-separate-releasing.md",1461],"6382e28e":[()=>n.e(1660).then(n.bind(n,3501)),"@site/versioned_docs/version-v4.2.0-docs/consumer-development/offboarding.md",3501],"68191a78":[()=>n.e(4438).then(n.bind(n,266)),"@site/docs/adrs/adr-011-improving-test-confidence.md",266],69416719:[()=>n.e(6873).then(n.bind(n,5911)),"@site/docs/features/democracy-modules.md",5911],"6b52739c":[()=>n.e(9419).then(n.bind(n,6319)),"@site/docs/adrs/adr-015-partial-set-security.md",6319],"6b8df643":[()=>n.e(4335).then(n.bind(n,8355)),"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-014-epochs.md",8355],"6cc1db80":[()=>n.e(8714).then(n.bind(n,6187)),"@site/versioned_docs/version-v5.0.0/validators/joining-neutron.md",6187],"6df65b06":[()=>n.e(4366).then(n.bind(n,4878)),"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-002-throttle.md",4878],"6f71328c":[()=>n.e(8560).then(n.bind(n,9371)),"@site/docs/adrs/adr-013-equivocation-slashing.md",9371],"700b5f22":[()=>n.e(5612).then(n.bind(n,8734)),"@site/docs/validators/partial-set-security-for-validators.md",8734],"70938a03":[()=>n.e(5457).then(n.bind(n,5610)),"@site/docs/consumer-development/changeover-procedure.md",5610],"72e9af3b":[()=>n.e(903).then(n.bind(n,8161)),"@site/versioned_docs/version-v5.0.0/adrs/adr-009-soft-opt-out.md",8161],"7380b9fa":[()=>n.e(1877).then(n.bind(n,6263)),"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-003-equivocation-gov-proposal.md",6263],"758625d4":[()=>n.e(321).then(n.bind(n,5477)),"@site/docs/validators/withdraw_rewards.md",5477],"75f9ba63":[()=>n.e(5296).then(n.bind(n,2372)),"@site/versioned_docs/version-v4.2.0-docs/validators/partial-set-security-for-validators.md",2372],"7616f23a":[()=>n.e(2247).then(n.bind(n,1422)),"@site/docs/introduction/overview.md",1422],"775e2592":[()=>n.e(7375).then(n.bind(n,6180)),"@site/docs/adrs/adr-008-throttle-retries.md",6180],"7aa430a8":[()=>n.e(7506).then(n.bind(n,6525)),"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-007-pause-unbonding-on-eqv-prop.md",6525],"829e00bf":[()=>n.e(8718).then(n.bind(n,1118)),"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-004-denom-dos-fixes.md",1118],"83f6d28d":[()=>n.e(7534).then(n.bind(n,7915)),"@site/versioned_docs/version-v5.0.0/validators/joining-stride.md",7915],"852eba87":[()=>n.e(2473).then(n.bind(n,8939)),"@site/versioned_docs/version-v4.2.0-docs/introduction/params.md",8939],"867425db":[()=>n.e(8477).then(n.bind(n,5024)),"@site/versioned_docs/version-v4.2.0-docs/frequently-asked-questions.md",5024],"8a86a05c":[()=>n.e(5938).then(n.bind(n,8380)),"@site/versioned_docs/version-v5.0.0/consumer-development/onboarding.md",8380],"8d3b6fe8":[()=>n.e(1163).then(n.bind(n,6216)),"@site/versioned_docs/version-v4.2.0-docs/consumer-development/consumer-chain-governance.md",6216],"903c2771":[()=>n.e(6054).then(n.bind(n,461)),"@site/docs/adrs/adr-009-soft-opt-out.md",461],"935f2afb":[()=>n.e(53).then(n.t.bind(n,1109,19)),"~docs/default/version-current-metadata-prop-751.json",1109],"94b74966":[()=>n.e(6673).then(n.bind(n,2546)),"@site/versioned_docs/version-v4.2.0-docs/consumer-development/changeover-procedure.md",2546],"95875ea0":[()=>n.e(3813).then(n.bind(n,2180)),"@site/docs/consumer-development/onboarding.md",2180],"97662a95":[()=>n.e(3859).then(n.bind(n,9541)),"@site/versioned_docs/version-v4.2.0-docs/validators/withdraw_rewards.md",9541],98891868:[()=>n.e(4964).then(n.bind(n,2177)),"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-001-key-assignment.md",2177],99394557:[()=>n.e(9897).then(n.bind(n,3347)),"@site/versioned_docs/version-v4.2.0-docs/index.mdx",3347],"99c91eb8":[()=>n.e(5112).then(n.bind(n,9697)),"@site/versioned_docs/version-v5.0.0/validators/joining-testnet.md",9697],"9b334c7f":[()=>n.e(5118).then(n.bind(n,9651)),"@site/versioned_docs/version-v5.0.0/consumer-development/offboarding.md",9651],"9be59c75":[()=>n.e(6420).then(n.bind(n,4408)),"@site/docs/features/power-shaping.md",4408],"9c202c81":[()=>n.e(6625).then(n.bind(n,5626)),"@site/versioned_docs/version-v5.0.0/features/reward-distribution.md",5626],"9fa21ee5":[()=>n.e(3500).then(n.bind(n,7809)),"@site/versioned_docs/version-v5.0.0/validators/changeover-procedure.md",7809],a088363e:[()=>n.e(6530).then(n.bind(n,6682)),"@site/versioned_docs/version-v4.2.0-docs/features/proposals.md",6682],a09d3327:[()=>n.e(8270).then(n.bind(n,3696)),"@site/docs/adrs/adr-014-epochs.md",3696],a2707102:[()=>n.e(457).then(n.bind(n,5077)),"@site/docs/adrs/intro.md",5077],a6888f58:[()=>n.e(7487).then(n.bind(n,4753)),"@site/versioned_docs/version-v5.0.0/adrs/adr-001-key-assignment.md",4753],a7bd4aaa:[()=>n.e(8518).then(n.bind(n,8564)),"@theme/DocVersionRoot",8564],a8cc50aa:[()=>n.e(787).then(n.bind(n,2973)),"@site/versioned_docs/version-v5.0.0/adrs/adr-002-throttle.md",2973],a94703ab:[()=>Promise.all([n.e(532),n.e(4368)]).then(n.bind(n,2674)),"@theme/DocRoot",2674],a95292b9:[()=>n.e(5474).then(n.bind(n,3623)),"@site/versioned_docs/version-v4.2.0-docs/consumer-development/app-integration.md",3623],aa5e9d52:[()=>n.e(4244).then(n.bind(n,9950)),"@site/versioned_docs/version-v5.0.0/adrs/adr-010-standalone-changeover.md",9950],ab367a53:[()=>n.e(3784).then(n.t.bind(n,5003,19)),"~docs/default/version-v-4-2-0-docs-metadata-prop-633.json",5003],ac4ec955:[()=>n.e(3297).then(n.bind(n,6114)),"@site/docs/adrs/adr-004-denom-dos-fixes.md",6114],ae015673:[()=>n.e(2108).then(n.bind(n,2165)),"@site/versioned_docs/version-v4.2.0-docs/validators/joining-stride.md",2165],ae63551b:[()=>n.e(5056).then(n.bind(n,6873)),"@site/docs/validators/joining-stride.md",6873],af3e09f2:[()=>n.e(4440).then(n.bind(n,8501)),"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-012-separate-releasing.md",8501],b22483fb:[()=>n.e(4533).then(n.bind(n,4875)),"@site/versioned_docs/version-v4.2.0-docs/introduction/technical-specification.md",4875],b2a29569:[()=>n.e(8864).then(n.bind(n,3567)),"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-013-equivocation-slashing.md",3567],b8d345cd:[()=>n.e(4341).then(n.bind(n,186)),"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-011-improving-test-confidence.md",186],b8e16dc5:[()=>n.e(6705).then(n.bind(n,1528)),"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-010-standalone-changeover.md",1528],b93225b7:[()=>n.e(7144).then(n.bind(n,8304)),"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-015-partial-set-security.md",8304],bbea31d2:[()=>n.e(109).then(n.bind(n,662)),"@site/docs/adrs/adr-002-throttle.md",662],bc8b8418:[()=>n.e(4704).then(n.bind(n,1824)),"@site/docs/introduction/terminology.md",1824],bdf2101f:[()=>n.e(7943).then(n.bind(n,3644)),"@site/versioned_docs/version-v5.0.0/features/proposals.md",3644],bfc97f30:[()=>n.e(9253).then(n.bind(n,3473)),"@site/docs/features/partial-set-security.md",3473],c1444bce:[()=>n.e(5776).then(n.bind(n,7258)),"@site/versioned_docs/version-v5.0.0/adrs/adr-015-partial-set-security.md",7258],c2cfb320:[()=>n.e(1429).then(n.bind(n,6639)),"@site/docs/validators/changeover-procedure.md",6639],c3827980:[()=>n.e(5032).then(n.bind(n,5082)),"@site/versioned_docs/version-v5.0.0/consumer-development/consumer-chain-governance.md",5082],c551d695:[()=>n.e(4635).then(n.bind(n,5414)),"@site/versioned_docs/version-v4.2.0-docs/features/key-assignment.md",5414],caea946b:[()=>n.e(3713).then(n.bind(n,5483)),"@site/versioned_docs/version-v5.0.0/adrs/adr-004-denom-dos-fixes.md",5483],cf411473:[()=>n.e(3153).then(n.bind(n,511)),"@site/docs/introduction/technical-specification.md",511],d0088cb9:[()=>n.e(709).then(n.bind(n,7015)),"@site/versioned_docs/version-v5.0.0/adrs/adr-013-equivocation-slashing.md",7015],d0d0ba0d:[()=>n.e(8772).then(n.bind(n,9133)),"@site/docs/adrs/adr-010-standalone-changeover.md",9133],d0d80f5c:[()=>n.e(9982).then(n.bind(n,2543)),"@site/versioned_docs/version-v5.0.0/features/key-assignment.md",2543],d1daeca6:[()=>n.e(3845).then(n.bind(n,6142)),"@site/docs/features/proposals.md",6142],d21f9ede:[()=>n.e(4932).then(n.bind(n,4330)),"@site/docs/adrs/adr-012-separate-releasing.md",4330],d2e13769:[()=>n.e(8382).then(n.bind(n,3396)),"@site/versioned_docs/version-v5.0.0/adrs/adr-007-pause-unbonding-on-eqv-prop.md",3396],d784d738:[()=>n.e(7333).then(n.bind(n,5093)),"@site/docs/consumer-development/app-integration.md",5093],da448d6e:[()=>n.e(4744).then(n.bind(n,1974)),"@site/versioned_docs/version-v5.0.0/adrs/adr-003-equivocation-gov-proposal.md",1974],dc9efaba:[()=>n.e(1324).then(n.bind(n,38)),"@site/docs/consumer-development/offboarding.md",38],ded36896:[()=>n.e(7429).then(n.bind(n,2030)),"@site/docs/adrs/adr-007-pause-unbonding-on-eqv-prop.md",2030],ded5fac2:[()=>n.e(2383).then(n.bind(n,4249)),"@site/versioned_docs/version-v4.2.0-docs/features/partial-set-security.md",4249],e005c37e:[()=>n.e(2883).then(n.bind(n,5837)),"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-005-cryptographic-equivocation-verification.md",5837],e0ad375d:[()=>n.e(1840).then(n.bind(n,3978)),"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-009-soft-opt-out.md",3978],e2ddbbfd:[()=>n.e(8892).then(n.bind(n,2005)),"@site/docs/adrs/adr-017-allowing-inactive-validators.md",2005],e50733a4:[()=>n.e(1937).then(n.bind(n,1370)),"@site/versioned_docs/version-v4.2.0-docs/features/slashing.md",1370],e5b5a87b:[()=>n.e(5313).then(n.bind(n,6407)),"@site/versioned_docs/version-v4.2.0-docs/consumer-development/onboarding.md",6407],e69e9c61:[()=>n.e(6882).then(n.bind(n,2489)),"@site/docs/adrs/adr-016-securityaggregation.md",2489],ea42cb80:[()=>n.e(4117).then(n.bind(n,5956)),"@site/versioned_docs/version-v4.2.0-docs/adrs/intro.md",5956],ed5b9256:[()=>n.e(8081).then(n.bind(n,8297)),"@site/versioned_docs/version-v5.0.0/consumer-development/app-integration.md",8297],f0745980:[()=>n.e(7143).then(n.bind(n,7134)),"@site/versioned_docs/version-v5.0.0/introduction/params.md",7134],f5589540:[()=>n.e(6499).then(n.bind(n,5573)),"@site/docs/consumer-development/consumer-chain-governance.md",5573],f6addb2b:[()=>n.e(35).then(n.bind(n,279)),"@site/docs/validators/overview.md",279],f8a7cbf6:[()=>n.e(2527).then(n.bind(n,4097)),"@site/versioned_docs/version-v5.0.0/validators/withdraw_rewards.md",4097],fc26cd25:[()=>n.e(9198).then(n.bind(n,6801)),"@site/versioned_docs/version-v4.2.0-docs/adrs/adr-template.md",6801],ff0782b1:[()=>n.e(7540).then(n.t.bind(n,3769,19)),"/home/runner/work/interchain-security/interchain-security/docs/.docusaurus/docusaurus-plugin-content-docs/default/plugin-route-context-module-100.json",3769],ff9311cc:[()=>n.e(5051).then(n.bind(n,151)),"@site/versioned_docs/version-v5.0.0/adrs/adr-014-epochs.md",151]};var s=n(5893);function l(e){let{error:t,retry:n,pastDelay:r}=e;return t?(0,s.jsxs)("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"},children:[(0,s.jsx)("p",{children:String(t)}),(0,s.jsx)("div",{children:(0,s.jsx)("button",{type:"button",onClick:n,children:"Retry"})})]}):r?(0,s.jsx)("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"},children:(0,s.jsx)("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb",children:(0,s.jsxs)("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2",children:[(0,s.jsxs)("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0",children:[(0,s.jsx)("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),(0,s.jsx)("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),(0,s.jsx)("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})]}),(0,s.jsxs)("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0",children:[(0,s.jsx)("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),(0,s.jsx)("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),(0,s.jsx)("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})]}),(0,s.jsx)("circle",{cx:"22",cy:"22",r:"8",children:(0,s.jsx)("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"})})]})})}):null}var c=n(9670),u=n(226);function d(e,t){if("*"===e)return a()({loading:l,loader:()=>n.e(1772).then(n.bind(n,1772)),modules:["@theme/NotFound"],webpack:()=>[1772],render(e,t){const n=e.default;return(0,s.jsx)(u.z,{value:{plugin:{name:"native",id:"default"}},children:(0,s.jsx)(n,{...t})})}});const r=i[`${e}-${t}`],d={},p=[],f=[],h=(0,c.Z)(r);return Object.entries(h).forEach((e=>{let[t,n]=e;const r=o[n];r&&(d[t]=r[0],p.push(r[1]),f.push(r[2]))})),a().Map({loading:l,loader:d,modules:p,webpack:()=>f,render(t,n){const a=JSON.parse(JSON.stringify(r));Object.entries(t).forEach((t=>{let[n,r]=t;const i=r.default;if(!i)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof i&&"function"!=typeof i||Object.keys(r).filter((e=>"default"!==e)).forEach((e=>{i[e]=r[e]}));let o=a;const s=n.split(".");s.slice(0,-1).forEach((e=>{o=o[e]})),o[s[s.length-1]]=i}));const i=a.__comp;delete a.__comp;const o=a.__context;return delete a.__context,(0,s.jsx)(u.z,{value:o,children:(0,s.jsx)(i,{...a,...n})})}})}const p=[{path:"/interchain-security/",component:d("/interchain-security/","a71"),routes:[{path:"/interchain-security/v4.2.0",component:d("/interchain-security/v4.2.0","03e"),routes:[{path:"/interchain-security/v4.2.0",component:d("/interchain-security/v4.2.0","c06"),routes:[{path:"/interchain-security/v4.2.0",component:d("/interchain-security/v4.2.0","c8a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/adrs/adr-001-key-assignment",component:d("/interchain-security/v4.2.0/adrs/adr-001-key-assignment","c79"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/adrs/adr-002-throttle",component:d("/interchain-security/v4.2.0/adrs/adr-002-throttle","ec7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/adrs/adr-003-equivocation-gov-proposal",component:d("/interchain-security/v4.2.0/adrs/adr-003-equivocation-gov-proposal","a0f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/adrs/adr-004-denom-dos-fixes",component:d("/interchain-security/v4.2.0/adrs/adr-004-denom-dos-fixes","ba0"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/adrs/adr-005-cryptographic-equivocation-verification",component:d("/interchain-security/v4.2.0/adrs/adr-005-cryptographic-equivocation-verification","74f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop",component:d("/interchain-security/v4.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop","83c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/adrs/adr-008-throttle-retries",component:d("/interchain-security/v4.2.0/adrs/adr-008-throttle-retries","e78"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/adrs/adr-009-soft-opt-out",component:d("/interchain-security/v4.2.0/adrs/adr-009-soft-opt-out","24f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/adrs/adr-010-standalone-changeover",component:d("/interchain-security/v4.2.0/adrs/adr-010-standalone-changeover","854"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/adrs/adr-011-improving-test-confidence",component:d("/interchain-security/v4.2.0/adrs/adr-011-improving-test-confidence","5cf"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/adrs/adr-012-separate-releasing",component:d("/interchain-security/v4.2.0/adrs/adr-012-separate-releasing","448"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/adrs/adr-013-equivocation-slashing",component:d("/interchain-security/v4.2.0/adrs/adr-013-equivocation-slashing","0de"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/adrs/adr-014-epochs",component:d("/interchain-security/v4.2.0/adrs/adr-014-epochs","1d2"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/adrs/adr-015-partial-set-security",component:d("/interchain-security/v4.2.0/adrs/adr-015-partial-set-security","0f9"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/adrs/adr-template",component:d("/interchain-security/v4.2.0/adrs/adr-template","83a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/adrs/intro",component:d("/interchain-security/v4.2.0/adrs/intro","cf8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/consumer-development/app-integration",component:d("/interchain-security/v4.2.0/consumer-development/app-integration","3ff"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/consumer-development/changeover-procedure",component:d("/interchain-security/v4.2.0/consumer-development/changeover-procedure","05c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/consumer-development/consumer-chain-governance",component:d("/interchain-security/v4.2.0/consumer-development/consumer-chain-governance","04a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/consumer-development/consumer-genesis-transformation",component:d("/interchain-security/v4.2.0/consumer-development/consumer-genesis-transformation","70d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/consumer-development/offboarding",component:d("/interchain-security/v4.2.0/consumer-development/offboarding","5bb"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/consumer-development/onboarding",component:d("/interchain-security/v4.2.0/consumer-development/onboarding","9f8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/faq",component:d("/interchain-security/v4.2.0/faq","45b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/features/key-assignment",component:d("/interchain-security/v4.2.0/features/key-assignment","42d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/features/partial-set-security",component:d("/interchain-security/v4.2.0/features/partial-set-security","be3"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/features/power-shaping",component:d("/interchain-security/v4.2.0/features/power-shaping","71f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/features/proposals",component:d("/interchain-security/v4.2.0/features/proposals","3b6"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/features/reward-distribution",component:d("/interchain-security/v4.2.0/features/reward-distribution","f4c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/features/slashing",component:d("/interchain-security/v4.2.0/features/slashing","ad1"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/introduction/overview",component:d("/interchain-security/v4.2.0/introduction/overview","348"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/introduction/params",component:d("/interchain-security/v4.2.0/introduction/params","432"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/introduction/technical-specification",component:d("/interchain-security/v4.2.0/introduction/technical-specification","77c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/introduction/terminology",component:d("/interchain-security/v4.2.0/introduction/terminology","de3"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/validators/changeover-procedure",component:d("/interchain-security/v4.2.0/validators/changeover-procedure","e1e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/validators/joining-neutron",component:d("/interchain-security/v4.2.0/validators/joining-neutron","402"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/validators/joining-stride",component:d("/interchain-security/v4.2.0/validators/joining-stride","63b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/validators/joining-testnet",component:d("/interchain-security/v4.2.0/validators/joining-testnet","476"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/validators/overview",component:d("/interchain-security/v4.2.0/validators/overview","689"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/validators/partial-set-security-for-validators",component:d("/interchain-security/v4.2.0/validators/partial-set-security-for-validators","1d8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v4.2.0/validators/withdraw_rewards",component:d("/interchain-security/v4.2.0/validators/withdraw_rewards","cbb"),exact:!0,sidebar:"tutorialSidebar"}]}]},{path:"/interchain-security/v5.0.0",component:d("/interchain-security/v5.0.0","49c"),routes:[{path:"/interchain-security/v5.0.0",component:d("/interchain-security/v5.0.0","8b2"),routes:[{path:"/interchain-security/v5.0.0",component:d("/interchain-security/v5.0.0","77d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/adrs/adr-001-key-assignment",component:d("/interchain-security/v5.0.0/adrs/adr-001-key-assignment","2b0"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/adrs/adr-002-throttle",component:d("/interchain-security/v5.0.0/adrs/adr-002-throttle","f23"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/adrs/adr-003-equivocation-gov-proposal",component:d("/interchain-security/v5.0.0/adrs/adr-003-equivocation-gov-proposal","32c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/adrs/adr-004-denom-dos-fixes",component:d("/interchain-security/v5.0.0/adrs/adr-004-denom-dos-fixes","329"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/adrs/adr-005-cryptographic-equivocation-verification",component:d("/interchain-security/v5.0.0/adrs/adr-005-cryptographic-equivocation-verification","284"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/adrs/adr-007-pause-unbonding-on-eqv-prop",component:d("/interchain-security/v5.0.0/adrs/adr-007-pause-unbonding-on-eqv-prop","652"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/adrs/adr-008-throttle-retries",component:d("/interchain-security/v5.0.0/adrs/adr-008-throttle-retries","212"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/adrs/adr-009-soft-opt-out",component:d("/interchain-security/v5.0.0/adrs/adr-009-soft-opt-out","d57"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/adrs/adr-010-standalone-changeover",component:d("/interchain-security/v5.0.0/adrs/adr-010-standalone-changeover","542"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/adrs/adr-011-improving-test-confidence",component:d("/interchain-security/v5.0.0/adrs/adr-011-improving-test-confidence","9a5"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/adrs/adr-012-separate-releasing",component:d("/interchain-security/v5.0.0/adrs/adr-012-separate-releasing","be6"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/adrs/adr-013-equivocation-slashing",component:d("/interchain-security/v5.0.0/adrs/adr-013-equivocation-slashing","2b3"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/adrs/adr-014-epochs",component:d("/interchain-security/v5.0.0/adrs/adr-014-epochs","d93"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/adrs/adr-015-partial-set-security",component:d("/interchain-security/v5.0.0/adrs/adr-015-partial-set-security","641"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/adrs/adr-template",component:d("/interchain-security/v5.0.0/adrs/adr-template","f5d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/adrs/intro",component:d("/interchain-security/v5.0.0/adrs/intro","374"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/consumer-development/app-integration",component:d("/interchain-security/v5.0.0/consumer-development/app-integration","117"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/consumer-development/changeover-procedure",component:d("/interchain-security/v5.0.0/consumer-development/changeover-procedure","afb"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/consumer-development/consumer-chain-governance",component:d("/interchain-security/v5.0.0/consumer-development/consumer-chain-governance","4f4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/consumer-development/consumer-genesis-transformation",component:d("/interchain-security/v5.0.0/consumer-development/consumer-genesis-transformation","a7a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/consumer-development/offboarding",component:d("/interchain-security/v5.0.0/consumer-development/offboarding","f26"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/consumer-development/onboarding",component:d("/interchain-security/v5.0.0/consumer-development/onboarding","834"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/faq",component:d("/interchain-security/v5.0.0/faq","8d9"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/features/key-assignment",component:d("/interchain-security/v5.0.0/features/key-assignment","cf8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/features/proposals",component:d("/interchain-security/v5.0.0/features/proposals","873"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/features/reward-distribution",component:d("/interchain-security/v5.0.0/features/reward-distribution","66f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/features/slashing",component:d("/interchain-security/v5.0.0/features/slashing","ed3"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/introduction/overview",component:d("/interchain-security/v5.0.0/introduction/overview","caf"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/introduction/params",component:d("/interchain-security/v5.0.0/introduction/params","ace"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/introduction/technical-specification",component:d("/interchain-security/v5.0.0/introduction/technical-specification","0bb"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/introduction/terminology",component:d("/interchain-security/v5.0.0/introduction/terminology","b9d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/upgrading/migrate_v4_v5",component:d("/interchain-security/v5.0.0/upgrading/migrate_v4_v5","197"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/validators/changeover-procedure",component:d("/interchain-security/v5.0.0/validators/changeover-procedure","3fc"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/validators/joining-neutron",component:d("/interchain-security/v5.0.0/validators/joining-neutron","668"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/validators/joining-stride",component:d("/interchain-security/v5.0.0/validators/joining-stride","6dd"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/validators/joining-testnet",component:d("/interchain-security/v5.0.0/validators/joining-testnet","e66"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/validators/overview",component:d("/interchain-security/v5.0.0/validators/overview","943"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/v5.0.0/validators/withdraw_rewards",component:d("/interchain-security/v5.0.0/validators/withdraw_rewards","f93"),exact:!0,sidebar:"tutorialSidebar"}]}]},{path:"/interchain-security/",component:d("/interchain-security/","e1b"),routes:[{path:"/interchain-security/",component:d("/interchain-security/","255"),routes:[{path:"/interchain-security/adrs/adr-001-key-assignment",component:d("/interchain-security/adrs/adr-001-key-assignment","b01"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/adrs/adr-002-throttle",component:d("/interchain-security/adrs/adr-002-throttle","049"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/adrs/adr-003-equivocation-gov-proposal",component:d("/interchain-security/adrs/adr-003-equivocation-gov-proposal","d6f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/adrs/adr-004-denom-dos-fixes",component:d("/interchain-security/adrs/adr-004-denom-dos-fixes","9f0"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/adrs/adr-005-cryptographic-equivocation-verification",component:d("/interchain-security/adrs/adr-005-cryptographic-equivocation-verification","97a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/adrs/adr-007-pause-unbonding-on-eqv-prop",component:d("/interchain-security/adrs/adr-007-pause-unbonding-on-eqv-prop","309"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/adrs/adr-008-throttle-retries",component:d("/interchain-security/adrs/adr-008-throttle-retries","cde"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/adrs/adr-009-soft-opt-out",component:d("/interchain-security/adrs/adr-009-soft-opt-out","126"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/adrs/adr-010-standalone-changeover",component:d("/interchain-security/adrs/adr-010-standalone-changeover","8ee"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/adrs/adr-011-improving-test-confidence",component:d("/interchain-security/adrs/adr-011-improving-test-confidence","6de"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/adrs/adr-012-separate-releasing",component:d("/interchain-security/adrs/adr-012-separate-releasing","711"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/adrs/adr-013-equivocation-slashing",component:d("/interchain-security/adrs/adr-013-equivocation-slashing","f62"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/adrs/adr-014-epochs",component:d("/interchain-security/adrs/adr-014-epochs","4bf"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/adrs/adr-015-partial-set-security",component:d("/interchain-security/adrs/adr-015-partial-set-security","638"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/adrs/adr-016-securityaggregation",component:d("/interchain-security/adrs/adr-016-securityaggregation","5e9"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/adrs/adr-017-allowing-inactive-validators",component:d("/interchain-security/adrs/adr-017-allowing-inactive-validators","0eb"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/adrs/intro",component:d("/interchain-security/adrs/intro","130"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/consumer-development/app-integration",component:d("/interchain-security/consumer-development/app-integration","634"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/consumer-development/changeover-procedure",component:d("/interchain-security/consumer-development/changeover-procedure","39d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/consumer-development/consumer-chain-governance",component:d("/interchain-security/consumer-development/consumer-chain-governance","f51"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/consumer-development/consumer-genesis-transformation",component:d("/interchain-security/consumer-development/consumer-genesis-transformation","491"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/consumer-development/offboarding",component:d("/interchain-security/consumer-development/offboarding","b9a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/consumer-development/onboarding",component:d("/interchain-security/consumer-development/onboarding","81f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/faq",component:d("/interchain-security/faq","e46"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/features/democracy-modules",component:d("/interchain-security/features/democracy-modules","0d1"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/features/key-assignment",component:d("/interchain-security/features/key-assignment","6a8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/features/partial-set-security",component:d("/interchain-security/features/partial-set-security","15b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/features/power-shaping",component:d("/interchain-security/features/power-shaping","157"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/features/proposals",component:d("/interchain-security/features/proposals","85e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/features/reward-distribution",component:d("/interchain-security/features/reward-distribution","133"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/features/slashing",component:d("/interchain-security/features/slashing","e4f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/introduction/overview",component:d("/interchain-security/introduction/overview","287"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/introduction/params",component:d("/interchain-security/introduction/params","aae"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/introduction/technical-specification",component:d("/interchain-security/introduction/technical-specification","e7d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/introduction/terminology",component:d("/interchain-security/introduction/terminology","11e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/upgrading/migrate_v4_v5",component:d("/interchain-security/upgrading/migrate_v4_v5","578"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/validators/changeover-procedure",component:d("/interchain-security/validators/changeover-procedure","e7d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/validators/joining-neutron",component:d("/interchain-security/validators/joining-neutron","3d1"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/validators/joining-stride",component:d("/interchain-security/validators/joining-stride","b1f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/validators/joining-testnet",component:d("/interchain-security/validators/joining-testnet","82d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/validators/overview",component:d("/interchain-security/validators/overview","ccb"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/validators/partial-set-security-for-validators",component:d("/interchain-security/validators/partial-set-security-for-validators","a1e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/validators/withdraw_rewards",component:d("/interchain-security/validators/withdraw_rewards","2b7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/",component:d("/interchain-security/","725"),exact:!0,sidebar:"tutorialSidebar"}]}]}]},{path:"*",component:d("*")}]},8934:(e,t,n)=>{"use strict";n.d(t,{_:()=>i,t:()=>o});var r=n(7294),a=n(5893);const i=r.createContext(!1);function o(e){let{children:t}=e;const[n,o]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{o(!0)}),[]),(0,a.jsx)(i.Provider,{value:n,children:t})}},7221:(e,t,n)=>{"use strict";var r=n(7294),a=n(745),i=n(3727),o=n(405),s=n(412);const l=[n(2497),n(3310),n(8320),n(2295)];var c=n(723),u=n(6550),d=n(8790),p=n(5893);function f(e){let{children:t}=e;return(0,p.jsx)(p.Fragment,{children:t})}var h=n(5742),m=n(2263),g=n(4996),v=n(6668),y=n(1944),b=n(4711),w=n(9727),k=n(3320),x=n(8780),S=n(197);function _(){const{i18n:{currentLocale:e,defaultLocale:t,localeConfigs:n}}=(0,m.Z)(),r=(0,b.l)(),a=n[e].htmlLang,i=e=>e.replace("-","_");return(0,p.jsxs)(h.Z,{children:[Object.entries(n).map((e=>{let[t,{htmlLang:n}]=e;return(0,p.jsx)("link",{rel:"alternate",href:r.createUrl({locale:t,fullyQualified:!0}),hrefLang:n},t)})),(0,p.jsx)("link",{rel:"alternate",href:r.createUrl({locale:t,fullyQualified:!0}),hrefLang:"x-default"}),(0,p.jsx)("meta",{property:"og:locale",content:i(a)}),Object.values(n).filter((e=>a!==e.htmlLang)).map((e=>(0,p.jsx)("meta",{property:"og:locale:alternate",content:i(e.htmlLang)},`meta-og-${e.htmlLang}`)))]})}function E(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,m.Z)(),r=function(){const{siteConfig:{url:e,baseUrl:t,trailingSlash:n}}=(0,m.Z)(),{pathname:r}=(0,u.TH)();return e+(0,x.applyTrailingSlash)((0,g.Z)(r),{trailingSlash:n,baseUrl:t})}(),a=t?`${n}${t}`:r;return(0,p.jsxs)(h.Z,{children:[(0,p.jsx)("meta",{property:"og:url",content:a}),(0,p.jsx)("link",{rel:"canonical",href:a})]})}function C(){const{i18n:{currentLocale:e}}=(0,m.Z)(),{metadata:t,image:n}=(0,v.L)();return(0,p.jsxs)(p.Fragment,{children:[(0,p.jsxs)(h.Z,{children:[(0,p.jsx)("meta",{name:"twitter:card",content:"summary_large_image"}),(0,p.jsx)("body",{className:w.h})]}),n&&(0,p.jsx)(y.d,{image:n}),(0,p.jsx)(E,{}),(0,p.jsx)(_,{}),(0,p.jsx)(S.Z,{tag:k.HX,locale:e}),(0,p.jsx)(h.Z,{children:t.map(((e,t)=>(0,p.jsx)("meta",{...e},t)))})]})}const T=new Map;function j(e){if(T.has(e.pathname))return{...e,pathname:T.get(e.pathname)};if((0,d.f)(c.Z,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return T.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return T.set(e.pathname,t),{...e,pathname:t}}var N=n(8934),L=n(8940),A=n(469);function P(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r<t;r++)n[r-1]=arguments[r];const a=l.map((t=>{const r=t.default?.[e]??t[e];return r?.(...n)}));return()=>a.forEach((e=>e?.()))}const O=function(e){let{children:t,location:n,previousLocation:r}=e;return(0,A.Z)((()=>{r!==n&&(!function(e){let{location:t,previousLocation:n}=e;if(!n)return;const r=t.pathname===n.pathname,a=t.hash===n.hash,i=t.search===n.search;if(r&&a&&!i)return;const{hash:o}=t;if(o){const e=decodeURIComponent(o.substring(1)),t=document.getElementById(e);t?.scrollIntoView()}else window.scrollTo(0,0)}({location:n,previousLocation:r}),P("onRouteDidUpdate",{previousLocation:r,location:n}))}),[r,n]),t};function R(e){const t=Array.from(new Set([e,decodeURI(e)])).map((e=>(0,d.f)(c.Z,e))).flat();return Promise.all(t.map((e=>e.route.component.preload?.())))}class I extends r.Component{previousLocation;routeUpdateCleanupCb;constructor(e){super(e),this.previousLocation=null,this.routeUpdateCleanupCb=s.Z.canUseDOM?P("onRouteUpdate",{previousLocation:null,location:this.props.location}):()=>{},this.state={nextRouteHasLoaded:!0}}shouldComponentUpdate(e,t){if(e.location===this.props.location)return t.nextRouteHasLoaded;const n=e.location;return this.previousLocation=this.props.location,this.setState({nextRouteHasLoaded:!1}),this.routeUpdateCleanupCb=P("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),R(n.pathname).then((()=>{this.routeUpdateCleanupCb(),this.setState({nextRouteHasLoaded:!0})})).catch((e=>{console.warn(e),window.location.reload()})),!1}render(){const{children:e,location:t}=this.props;return(0,p.jsx)(O,{previousLocation:this.previousLocation,location:t,children:(0,p.jsx)(u.AW,{location:t,render:()=>e})})}}const F=I,D="__docusaurus-base-url-issue-banner-container",M="__docusaurus-base-url-issue-banner",z="__docusaurus-base-url-issue-banner-suggestion-container";function B(e){return`\ndocument.addEventListener('DOMContentLoaded', function maybeInsertBanner() {\n var shouldInsert = typeof window['docusaurus'] === 'undefined';\n shouldInsert && insertBanner();\n});\n\nfunction insertBanner() {\n var bannerContainer = document.createElement('div');\n bannerContainer.id = '${D}';\n var bannerHtml = ${JSON.stringify(function(e){return`\n<div id="${M}" style="border: thick solid red; background-color: rgb(255, 230, 179); margin: 20px; padding: 20px; font-size: 20px;">\n <p style="font-weight: bold; font-size: 30px;">Your Docusaurus site did not load properly.</p>\n <p>A very common reason is a wrong site <a href="https://docusaurus.io/docs/docusaurus.config.js/#baseUrl" style="font-weight: bold;">baseUrl configuration</a>.</p>\n <p>Current configured baseUrl = <span style="font-weight: bold; color: red;">${e}</span> ${"/"===e?" (default value)":""}</p>\n <p>We suggest trying baseUrl = <span id="${z}" style="font-weight: bold; color: green;"></span></p>\n</div>\n`}(e)).replace(/</g,"\\<")};\n bannerContainer.innerHTML = bannerHtml;\n document.body.prepend(bannerContainer);\n var suggestionContainer = document.getElementById('${z}');\n var actualHomePagePath = window.location.pathname;\n var suggestedBaseUrl = actualHomePagePath.substr(-1) === '/'\n ? actualHomePagePath\n : actualHomePagePath + '/';\n suggestionContainer.innerHTML = suggestedBaseUrl;\n}\n`}function $(){const{siteConfig:{baseUrl:e}}=(0,m.Z)();return(0,p.jsx)(p.Fragment,{children:!s.Z.canUseDOM&&(0,p.jsx)(h.Z,{children:(0,p.jsx)("script",{children:B(e)})})})}function U(){const{siteConfig:{baseUrl:e,baseUrlIssueBanner:t}}=(0,m.Z)(),{pathname:n}=(0,u.TH)();return t&&n===e?(0,p.jsx)($,{}):null}function Z(){const{siteConfig:{favicon:e,title:t,noIndex:n},i18n:{currentLocale:r,localeConfigs:a}}=(0,m.Z)(),i=(0,g.Z)(e),{htmlLang:o,direction:s}=a[r];return(0,p.jsxs)(h.Z,{children:[(0,p.jsx)("html",{lang:o,dir:s}),(0,p.jsx)("title",{children:t}),(0,p.jsx)("meta",{property:"og:title",content:t}),(0,p.jsx)("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0"}),n&&(0,p.jsx)("meta",{name:"robots",content:"noindex, nofollow"}),e&&(0,p.jsx)("link",{rel:"icon",href:i})]})}var H=n(4763),q=n(2389);function V(){const e=(0,q.Z)();return(0,p.jsx)(h.Z,{children:(0,p.jsx)("html",{"data-has-hydrated":e})})}function W(){const e=(0,d.H)(c.Z),t=(0,u.TH)();return(0,p.jsx)(H.Z,{children:(0,p.jsx)(L.M,{children:(0,p.jsxs)(N.t,{children:[(0,p.jsxs)(f,{children:[(0,p.jsx)(Z,{}),(0,p.jsx)(C,{}),(0,p.jsx)(U,{}),(0,p.jsx)(F,{location:j(t),children:e})]}),(0,p.jsx)(V,{})]})})})}var G=n(6887);const Y=function(e){try{return document.createElement("link").relList.supports(e)}catch{return!1}}("prefetch")?function(e){return new Promise(((t,n)=>{if("undefined"==typeof document)return void n();const r=document.createElement("link");r.setAttribute("rel","prefetch"),r.setAttribute("href",e),r.onload=()=>t(),r.onerror=()=>n();const a=document.getElementsByTagName("head")[0]??document.getElementsByName("script")[0]?.parentNode;a?.appendChild(r)}))}:function(e){return new Promise(((t,n)=>{const r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=()=>{200===r.status?t():n()},r.send(null)}))};var Q=n(9670);const K=new Set,X=new Set,J=()=>navigator.connection?.effectiveType.includes("2g")||navigator.connection?.saveData,ee={prefetch(e){if(!(e=>!J()&&!X.has(e)&&!K.has(e))(e))return!1;K.add(e);const t=(0,d.f)(c.Z,e).flatMap((e=>{return t=e.route.path,Object.entries(G).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,Q.Z)(t))}));var t}));return Promise.all(t.map((e=>{const t=n.gca(e);return t&&!t.includes("undefined")?Y(t).catch((()=>{})):Promise.resolve()})))},preload:e=>!!(e=>!J()&&!X.has(e))(e)&&(X.add(e),R(e))},te=Object.freeze(ee),ne=Boolean(!0);if(s.Z.canUseDOM){window.docusaurus=te;const e=document.getElementById("__docusaurus"),t=(0,p.jsx)(o.B6,{children:(0,p.jsx)(i.VK,{children:(0,p.jsx)(W,{})})}),n=(e,t)=>{console.error("Docusaurus React Root onRecoverableError:",e,t)},s=()=>{if(ne)r.startTransition((()=>{a.hydrateRoot(e,t,{onRecoverableError:n})}));else{const i=a.createRoot(e,{onRecoverableError:n});r.startTransition((()=>{i.render(t)}))}};R(window.location.pathname).then(s)}},8940:(e,t,n)=>{"use strict";n.d(t,{_:()=>d,M:()=>p});var r=n(7294),a=n(6809);const i=JSON.parse('{"docusaurus-plugin-content-docs":{"default":{"path":"/interchain-security/","versions":[{"name":"current","label":"main","isLast":false,"path":"/interchain-security/","mainDocId":"index","docs":[{"id":"adrs/adr-001-key-assignment","path":"/interchain-security/adrs/adr-001-key-assignment","sidebar":"tutorialSidebar"},{"id":"adrs/adr-002-throttle","path":"/interchain-security/adrs/adr-002-throttle","sidebar":"tutorialSidebar"},{"id":"adrs/adr-003-equivocation-gov-proposal","path":"/interchain-security/adrs/adr-003-equivocation-gov-proposal","sidebar":"tutorialSidebar"},{"id":"adrs/adr-004-denom-dos-fixes","path":"/interchain-security/adrs/adr-004-denom-dos-fixes","sidebar":"tutorialSidebar"},{"id":"adrs/adr-005-cryptographic-equivocation-verification","path":"/interchain-security/adrs/adr-005-cryptographic-equivocation-verification","sidebar":"tutorialSidebar"},{"id":"adrs/adr-007-pause-unbonding-on-eqv-prop","path":"/interchain-security/adrs/adr-007-pause-unbonding-on-eqv-prop","sidebar":"tutorialSidebar"},{"id":"adrs/adr-008-throttle-retries","path":"/interchain-security/adrs/adr-008-throttle-retries","sidebar":"tutorialSidebar"},{"id":"adrs/adr-009-soft-opt-out","path":"/interchain-security/adrs/adr-009-soft-opt-out","sidebar":"tutorialSidebar"},{"id":"adrs/adr-010-standalone-changeover","path":"/interchain-security/adrs/adr-010-standalone-changeover","sidebar":"tutorialSidebar"},{"id":"adrs/adr-011-improving-test-confidence","path":"/interchain-security/adrs/adr-011-improving-test-confidence","sidebar":"tutorialSidebar"},{"id":"adrs/adr-012-separate-releasing","path":"/interchain-security/adrs/adr-012-separate-releasing","sidebar":"tutorialSidebar"},{"id":"adrs/adr-013-equivocation-slashing","path":"/interchain-security/adrs/adr-013-equivocation-slashing","sidebar":"tutorialSidebar"},{"id":"adrs/adr-014-epochs","path":"/interchain-security/adrs/adr-014-epochs","sidebar":"tutorialSidebar"},{"id":"adrs/adr-015-partial-set-security","path":"/interchain-security/adrs/adr-015-partial-set-security","sidebar":"tutorialSidebar"},{"id":"adrs/adr-016-securityaggregation","path":"/interchain-security/adrs/adr-016-securityaggregation","sidebar":"tutorialSidebar"},{"id":"adrs/adr-017-allowing-inactive-validators","path":"/interchain-security/adrs/adr-017-allowing-inactive-validators","sidebar":"tutorialSidebar"},{"id":"adrs/intro","path":"/interchain-security/adrs/intro","sidebar":"tutorialSidebar"},{"id":"consumer-development/app-integration","path":"/interchain-security/consumer-development/app-integration","sidebar":"tutorialSidebar"},{"id":"consumer-development/changeover-procedure","path":"/interchain-security/consumer-development/changeover-procedure","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-chain-governance","path":"/interchain-security/consumer-development/consumer-chain-governance","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-genesis-transformation","path":"/interchain-security/consumer-development/consumer-genesis-transformation","sidebar":"tutorialSidebar"},{"id":"consumer-development/offboarding","path":"/interchain-security/consumer-development/offboarding","sidebar":"tutorialSidebar"},{"id":"consumer-development/onboarding","path":"/interchain-security/consumer-development/onboarding","sidebar":"tutorialSidebar"},{"id":"features/democracy-modules","path":"/interchain-security/features/democracy-modules","sidebar":"tutorialSidebar"},{"id":"features/key-assignment","path":"/interchain-security/features/key-assignment","sidebar":"tutorialSidebar"},{"id":"features/partial-set-security","path":"/interchain-security/features/partial-set-security","sidebar":"tutorialSidebar"},{"id":"features/power-shaping","path":"/interchain-security/features/power-shaping","sidebar":"tutorialSidebar"},{"id":"features/proposals","path":"/interchain-security/features/proposals","sidebar":"tutorialSidebar"},{"id":"features/reward-distribution","path":"/interchain-security/features/reward-distribution","sidebar":"tutorialSidebar"},{"id":"features/slashing","path":"/interchain-security/features/slashing","sidebar":"tutorialSidebar"},{"id":"frequently-asked-questions","path":"/interchain-security/faq","sidebar":"tutorialSidebar"},{"id":"index","path":"/interchain-security/","sidebar":"tutorialSidebar"},{"id":"introduction/overview","path":"/interchain-security/introduction/overview","sidebar":"tutorialSidebar"},{"id":"introduction/params","path":"/interchain-security/introduction/params","sidebar":"tutorialSidebar"},{"id":"introduction/technical-specification","path":"/interchain-security/introduction/technical-specification","sidebar":"tutorialSidebar"},{"id":"introduction/terminology","path":"/interchain-security/introduction/terminology","sidebar":"tutorialSidebar"},{"id":"upgrading/migrate_v4_v5","path":"/interchain-security/upgrading/migrate_v4_v5","sidebar":"tutorialSidebar"},{"id":"validators/changeover-procedure","path":"/interchain-security/validators/changeover-procedure","sidebar":"tutorialSidebar"},{"id":"validators/joining-neutron","path":"/interchain-security/validators/joining-neutron","sidebar":"tutorialSidebar"},{"id":"validators/joining-stride","path":"/interchain-security/validators/joining-stride","sidebar":"tutorialSidebar"},{"id":"validators/joining-testnet","path":"/interchain-security/validators/joining-testnet","sidebar":"tutorialSidebar"},{"id":"validators/overview","path":"/interchain-security/validators/overview","sidebar":"tutorialSidebar"},{"id":"validators/partial-set-security-for-validators","path":"/interchain-security/validators/partial-set-security-for-validators","sidebar":"tutorialSidebar"},{"id":"validators/withdraw_rewards","path":"/interchain-security/validators/withdraw_rewards","sidebar":"tutorialSidebar"}],"draftIds":[],"sidebars":{"tutorialSidebar":{"link":{"path":"/interchain-security/","label":"index"}}}},{"name":"v4.2.0-docs","label":"v4.2.0","isLast":true,"path":"/interchain-security/v4.2.0/","mainDocId":"index","docs":[{"id":"adrs/adr-001-key-assignment","path":"/interchain-security/v4.2.0/adrs/adr-001-key-assignment","sidebar":"tutorialSidebar"},{"id":"adrs/adr-002-throttle","path":"/interchain-security/v4.2.0/adrs/adr-002-throttle","sidebar":"tutorialSidebar"},{"id":"adrs/adr-003-equivocation-gov-proposal","path":"/interchain-security/v4.2.0/adrs/adr-003-equivocation-gov-proposal","sidebar":"tutorialSidebar"},{"id":"adrs/adr-004-denom-dos-fixes","path":"/interchain-security/v4.2.0/adrs/adr-004-denom-dos-fixes","sidebar":"tutorialSidebar"},{"id":"adrs/adr-005-cryptographic-equivocation-verification","path":"/interchain-security/v4.2.0/adrs/adr-005-cryptographic-equivocation-verification","sidebar":"tutorialSidebar"},{"id":"adrs/adr-007-pause-unbonding-on-eqv-prop","path":"/interchain-security/v4.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop","sidebar":"tutorialSidebar"},{"id":"adrs/adr-008-throttle-retries","path":"/interchain-security/v4.2.0/adrs/adr-008-throttle-retries","sidebar":"tutorialSidebar"},{"id":"adrs/adr-009-soft-opt-out","path":"/interchain-security/v4.2.0/adrs/adr-009-soft-opt-out","sidebar":"tutorialSidebar"},{"id":"adrs/adr-010-standalone-changeover","path":"/interchain-security/v4.2.0/adrs/adr-010-standalone-changeover","sidebar":"tutorialSidebar"},{"id":"adrs/adr-011-improving-test-confidence","path":"/interchain-security/v4.2.0/adrs/adr-011-improving-test-confidence","sidebar":"tutorialSidebar"},{"id":"adrs/adr-012-separate-releasing","path":"/interchain-security/v4.2.0/adrs/adr-012-separate-releasing","sidebar":"tutorialSidebar"},{"id":"adrs/adr-013-equivocation-slashing","path":"/interchain-security/v4.2.0/adrs/adr-013-equivocation-slashing","sidebar":"tutorialSidebar"},{"id":"adrs/adr-014-epochs","path":"/interchain-security/v4.2.0/adrs/adr-014-epochs","sidebar":"tutorialSidebar"},{"id":"adrs/adr-015-partial-set-security","path":"/interchain-security/v4.2.0/adrs/adr-015-partial-set-security","sidebar":"tutorialSidebar"},{"id":"adrs/adr-template","path":"/interchain-security/v4.2.0/adrs/adr-template","sidebar":"tutorialSidebar"},{"id":"adrs/intro","path":"/interchain-security/v4.2.0/adrs/intro","sidebar":"tutorialSidebar"},{"id":"consumer-development/app-integration","path":"/interchain-security/v4.2.0/consumer-development/app-integration","sidebar":"tutorialSidebar"},{"id":"consumer-development/changeover-procedure","path":"/interchain-security/v4.2.0/consumer-development/changeover-procedure","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-chain-governance","path":"/interchain-security/v4.2.0/consumer-development/consumer-chain-governance","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-genesis-transformation","path":"/interchain-security/v4.2.0/consumer-development/consumer-genesis-transformation","sidebar":"tutorialSidebar"},{"id":"consumer-development/offboarding","path":"/interchain-security/v4.2.0/consumer-development/offboarding","sidebar":"tutorialSidebar"},{"id":"consumer-development/onboarding","path":"/interchain-security/v4.2.0/consumer-development/onboarding","sidebar":"tutorialSidebar"},{"id":"features/key-assignment","path":"/interchain-security/v4.2.0/features/key-assignment","sidebar":"tutorialSidebar"},{"id":"features/partial-set-security","path":"/interchain-security/v4.2.0/features/partial-set-security","sidebar":"tutorialSidebar"},{"id":"features/power-shaping","path":"/interchain-security/v4.2.0/features/power-shaping","sidebar":"tutorialSidebar"},{"id":"features/proposals","path":"/interchain-security/v4.2.0/features/proposals","sidebar":"tutorialSidebar"},{"id":"features/reward-distribution","path":"/interchain-security/v4.2.0/features/reward-distribution","sidebar":"tutorialSidebar"},{"id":"features/slashing","path":"/interchain-security/v4.2.0/features/slashing","sidebar":"tutorialSidebar"},{"id":"frequently-asked-questions","path":"/interchain-security/v4.2.0/faq","sidebar":"tutorialSidebar"},{"id":"index","path":"/interchain-security/v4.2.0/","sidebar":"tutorialSidebar"},{"id":"introduction/overview","path":"/interchain-security/v4.2.0/introduction/overview","sidebar":"tutorialSidebar"},{"id":"introduction/params","path":"/interchain-security/v4.2.0/introduction/params","sidebar":"tutorialSidebar"},{"id":"introduction/technical-specification","path":"/interchain-security/v4.2.0/introduction/technical-specification","sidebar":"tutorialSidebar"},{"id":"introduction/terminology","path":"/interchain-security/v4.2.0/introduction/terminology","sidebar":"tutorialSidebar"},{"id":"validators/changeover-procedure","path":"/interchain-security/v4.2.0/validators/changeover-procedure","sidebar":"tutorialSidebar"},{"id":"validators/joining-neutron","path":"/interchain-security/v4.2.0/validators/joining-neutron","sidebar":"tutorialSidebar"},{"id":"validators/joining-stride","path":"/interchain-security/v4.2.0/validators/joining-stride","sidebar":"tutorialSidebar"},{"id":"validators/joining-testnet","path":"/interchain-security/v4.2.0/validators/joining-testnet","sidebar":"tutorialSidebar"},{"id":"validators/overview","path":"/interchain-security/v4.2.0/validators/overview","sidebar":"tutorialSidebar"},{"id":"validators/partial-set-security-for-validators","path":"/interchain-security/v4.2.0/validators/partial-set-security-for-validators","sidebar":"tutorialSidebar"},{"id":"validators/withdraw_rewards","path":"/interchain-security/v4.2.0/validators/withdraw_rewards","sidebar":"tutorialSidebar"}],"draftIds":[],"sidebars":{"tutorialSidebar":{"link":{"path":"/interchain-security/v4.2.0/","label":"index"}}}},{"name":"v5.0.0","label":"v5.0.0","isLast":false,"path":"/interchain-security/v5.0.0","mainDocId":"index","docs":[{"id":"adrs/adr-001-key-assignment","path":"/interchain-security/v5.0.0/adrs/adr-001-key-assignment","sidebar":"tutorialSidebar"},{"id":"adrs/adr-002-throttle","path":"/interchain-security/v5.0.0/adrs/adr-002-throttle","sidebar":"tutorialSidebar"},{"id":"adrs/adr-003-equivocation-gov-proposal","path":"/interchain-security/v5.0.0/adrs/adr-003-equivocation-gov-proposal","sidebar":"tutorialSidebar"},{"id":"adrs/adr-004-denom-dos-fixes","path":"/interchain-security/v5.0.0/adrs/adr-004-denom-dos-fixes","sidebar":"tutorialSidebar"},{"id":"adrs/adr-005-cryptographic-equivocation-verification","path":"/interchain-security/v5.0.0/adrs/adr-005-cryptographic-equivocation-verification","sidebar":"tutorialSidebar"},{"id":"adrs/adr-007-pause-unbonding-on-eqv-prop","path":"/interchain-security/v5.0.0/adrs/adr-007-pause-unbonding-on-eqv-prop","sidebar":"tutorialSidebar"},{"id":"adrs/adr-008-throttle-retries","path":"/interchain-security/v5.0.0/adrs/adr-008-throttle-retries","sidebar":"tutorialSidebar"},{"id":"adrs/adr-009-soft-opt-out","path":"/interchain-security/v5.0.0/adrs/adr-009-soft-opt-out","sidebar":"tutorialSidebar"},{"id":"adrs/adr-010-standalone-changeover","path":"/interchain-security/v5.0.0/adrs/adr-010-standalone-changeover","sidebar":"tutorialSidebar"},{"id":"adrs/adr-011-improving-test-confidence","path":"/interchain-security/v5.0.0/adrs/adr-011-improving-test-confidence","sidebar":"tutorialSidebar"},{"id":"adrs/adr-012-separate-releasing","path":"/interchain-security/v5.0.0/adrs/adr-012-separate-releasing","sidebar":"tutorialSidebar"},{"id":"adrs/adr-013-equivocation-slashing","path":"/interchain-security/v5.0.0/adrs/adr-013-equivocation-slashing","sidebar":"tutorialSidebar"},{"id":"adrs/adr-014-epochs","path":"/interchain-security/v5.0.0/adrs/adr-014-epochs","sidebar":"tutorialSidebar"},{"id":"adrs/adr-015-partial-set-security","path":"/interchain-security/v5.0.0/adrs/adr-015-partial-set-security","sidebar":"tutorialSidebar"},{"id":"adrs/adr-template","path":"/interchain-security/v5.0.0/adrs/adr-template","sidebar":"tutorialSidebar"},{"id":"adrs/intro","path":"/interchain-security/v5.0.0/adrs/intro","sidebar":"tutorialSidebar"},{"id":"consumer-development/app-integration","path":"/interchain-security/v5.0.0/consumer-development/app-integration","sidebar":"tutorialSidebar"},{"id":"consumer-development/changeover-procedure","path":"/interchain-security/v5.0.0/consumer-development/changeover-procedure","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-chain-governance","path":"/interchain-security/v5.0.0/consumer-development/consumer-chain-governance","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-genesis-transformation","path":"/interchain-security/v5.0.0/consumer-development/consumer-genesis-transformation","sidebar":"tutorialSidebar"},{"id":"consumer-development/offboarding","path":"/interchain-security/v5.0.0/consumer-development/offboarding","sidebar":"tutorialSidebar"},{"id":"consumer-development/onboarding","path":"/interchain-security/v5.0.0/consumer-development/onboarding","sidebar":"tutorialSidebar"},{"id":"features/key-assignment","path":"/interchain-security/v5.0.0/features/key-assignment","sidebar":"tutorialSidebar"},{"id":"features/proposals","path":"/interchain-security/v5.0.0/features/proposals","sidebar":"tutorialSidebar"},{"id":"features/reward-distribution","path":"/interchain-security/v5.0.0/features/reward-distribution","sidebar":"tutorialSidebar"},{"id":"features/slashing","path":"/interchain-security/v5.0.0/features/slashing","sidebar":"tutorialSidebar"},{"id":"frequently-asked-questions","path":"/interchain-security/v5.0.0/faq","sidebar":"tutorialSidebar"},{"id":"index","path":"/interchain-security/v5.0.0/","sidebar":"tutorialSidebar"},{"id":"introduction/overview","path":"/interchain-security/v5.0.0/introduction/overview","sidebar":"tutorialSidebar"},{"id":"introduction/params","path":"/interchain-security/v5.0.0/introduction/params","sidebar":"tutorialSidebar"},{"id":"introduction/technical-specification","path":"/interchain-security/v5.0.0/introduction/technical-specification","sidebar":"tutorialSidebar"},{"id":"introduction/terminology","path":"/interchain-security/v5.0.0/introduction/terminology","sidebar":"tutorialSidebar"},{"id":"upgrading/migrate_v4_v5","path":"/interchain-security/v5.0.0/upgrading/migrate_v4_v5","sidebar":"tutorialSidebar"},{"id":"validators/changeover-procedure","path":"/interchain-security/v5.0.0/validators/changeover-procedure","sidebar":"tutorialSidebar"},{"id":"validators/joining-neutron","path":"/interchain-security/v5.0.0/validators/joining-neutron","sidebar":"tutorialSidebar"},{"id":"validators/joining-stride","path":"/interchain-security/v5.0.0/validators/joining-stride","sidebar":"tutorialSidebar"},{"id":"validators/joining-testnet","path":"/interchain-security/v5.0.0/validators/joining-testnet","sidebar":"tutorialSidebar"},{"id":"validators/overview","path":"/interchain-security/v5.0.0/validators/overview","sidebar":"tutorialSidebar"},{"id":"validators/withdraw_rewards","path":"/interchain-security/v5.0.0/validators/withdraw_rewards","sidebar":"tutorialSidebar"}],"draftIds":[],"sidebars":{"tutorialSidebar":{"link":{"path":"/interchain-security/v5.0.0/","label":"index"}}}}],"breadcrumbs":true}}}'),o=JSON.parse('{"defaultLocale":"en","locales":["en"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"}}}');var s=n(7529);const l=JSON.parse('{"docusaurusVersion":"3.0.1","siteVersion":"0.0.0","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"3.0.1"},"docusaurus-plugin-content-blog":{"type":"package","name":"@docusaurus/plugin-content-blog","version":"3.0.1"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"3.0.1"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"3.0.1"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"3.0.1"},"docusaurus-tailwindcss":{"type":"local"},"docusaurus-plugin-client-redirects":{"type":"package","name":"@docusaurus/plugin-client-redirects","version":"3.0.1"},"docusaurus-theme-github-codeblock":{"type":"package","name":"@you54f/theme-github-codeblock","version":"0.1.1"}}}');var c=n(5893);const u={siteConfig:a.default,siteMetadata:l,globalData:i,i18n:o,codeTranslations:s},d=r.createContext(u);function p(e){let{children:t}=e;return(0,c.jsx)(d.Provider,{value:u,children:t})}},4763:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(7294),a=n(412),i=n(5742),o=n(8780),s=n(6040),l=n(5893);function c(e){let{error:t,tryAgain:n}=e;return(0,l.jsxs)("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"flex-start",minHeight:"100vh",width:"100%",maxWidth:"80ch",fontSize:"20px",margin:"0 auto",padding:"1rem"},children:[(0,l.jsx)("h1",{style:{fontSize:"3rem"},children:"This page crashed"}),(0,l.jsx)("button",{type:"button",onClick:n,style:{margin:"1rem 0",fontSize:"2rem",cursor:"pointer",borderRadius:20,padding:"1rem"},children:"Try again"}),(0,l.jsx)(u,{error:t})]})}function u(e){let{error:t}=e;const n=(0,o.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return(0,l.jsx)("p",{style:{whiteSpace:"pre-wrap"},children:n})}function d(e){let{error:t,tryAgain:n}=e;return(0,l.jsxs)(f,{fallback:()=>(0,l.jsx)(c,{error:t,tryAgain:n}),children:[(0,l.jsx)(i.Z,{children:(0,l.jsx)("title",{children:"Page Error"})}),(0,l.jsx)(s.Z,{children:(0,l.jsx)(c,{error:t,tryAgain:n})})]})}const p=e=>(0,l.jsx)(d,{...e});class f extends r.Component{constructor(e){super(e),this.state={error:null}}componentDidCatch(e){a.Z.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){const e={error:t,tryAgain:()=>this.setState({error:null})};return(this.props.fallback??p)(e)}return e??null}}},412:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,a={canUseDOM:r,canUseEventListeners:r&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:r&&"IntersectionObserver"in window,canUseViewport:r&&"screen"in window}},5742:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});n(7294);var r=n(405),a=n(5893);function i(e){return(0,a.jsx)(r.ql,{...e})}},9960:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(7294),a=n(3727),i=n(8780),o=n(2263),s=n(3919),l=n(412),c=n(5893);const u=r.createContext({collectLink:()=>{}});var d=n(4996);function p(e,t){let{isNavLink:n,to:p,href:f,activeClassName:h,isActive:m,"data-noBrokenLinkCheck":g,autoAddBaseUrl:v=!0,...y}=e;const{siteConfig:{trailingSlash:b,baseUrl:w}}=(0,o.Z)(),{withBaseUrl:k}=(0,d.C)(),x=(0,r.useContext)(u),S=(0,r.useRef)(null);(0,r.useImperativeHandle)(t,(()=>S.current));const _=p||f;const E=(0,s.Z)(_),C=_?.replace("pathname://","");let T=void 0!==C?(j=C,v&&(e=>e.startsWith("/"))(j)?k(j):j):void 0;var j;T&&E&&(T=(0,i.applyTrailingSlash)(T,{trailingSlash:b,baseUrl:w}));const N=(0,r.useRef)(!1),L=n?a.OL:a.rU,A=l.Z.canUseIntersectionObserver,P=(0,r.useRef)(),O=()=>{N.current||null==T||(window.docusaurus.preload(T),N.current=!0)};(0,r.useEffect)((()=>(!A&&E&&null!=T&&window.docusaurus.prefetch(T),()=>{A&&P.current&&P.current.disconnect()})),[P,T,A,E]);const R=T?.startsWith("#")??!1,I=!T||!E||R;return I||g||x.collectLink(T),I?(0,c.jsx)("a",{ref:S,href:T,..._&&!E&&{target:"_blank",rel:"noopener noreferrer"},...y}):(0,c.jsx)(L,{...y,onMouseEnter:O,onTouchStart:O,innerRef:e=>{S.current=e,A&&e&&E&&(P.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(P.current.unobserve(e),P.current.disconnect(),null!=T&&window.docusaurus.prefetch(T))}))})),P.current.observe(e))},to:T,...n&&{isActive:m,activeClassName:h}})}const f=r.forwardRef(p)},1875:(e,t,n)=>{"use strict";n.d(t,{Z:()=>r});const r=()=>null},5999:(e,t,n)=>{"use strict";n.d(t,{Z:()=>c,I:()=>l});var r=n(7294),a=n(5893);function i(e,t){const n=e.split(/(\{\w+\})/).map(((e,n)=>{if(n%2==1){const n=t?.[e.slice(1,-1)];if(void 0!==n)return n}return e}));return n.some((e=>(0,r.isValidElement)(e)))?n.map(((e,t)=>(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e)).filter((e=>""!==e)):n.join("")}var o=n(7529);function s(e){let{id:t,message:n}=e;if(void 0===t&&void 0===n)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return o[t??n]??n??t}function l(e,t){let{message:n,id:r}=e;return i(s({message:n,id:r}),t)}function c(e){let{children:t,id:n,values:r}=e;if(t&&"string"!=typeof t)throw console.warn("Illegal <Translate> children",t),new Error("The Docusaurus <Translate> component only accept simple string values");const o=s({message:t,id:n});return(0,a.jsx)(a.Fragment,{children:i(o,r)})}},9935:(e,t,n)=>{"use strict";n.d(t,{m:()=>r});const r="default"},3919:(e,t,n)=>{"use strict";function r(e){return/^(?:\w*:|\/\/)/.test(e)}function a(e){return void 0!==e&&!r(e)}n.d(t,{Z:()=>a,b:()=>r})},4996:(e,t,n)=>{"use strict";n.d(t,{C:()=>o,Z:()=>s});var r=n(7294),a=n(2263),i=n(3919);function o(){const{siteConfig:{baseUrl:e,url:t}}=(0,a.Z)(),n=(0,r.useCallback)(((n,r)=>function(e,t,n,r){let{forcePrependBaseUrl:a=!1,absolute:o=!1}=void 0===r?{}:r;if(!n||n.startsWith("#")||(0,i.b)(n))return n;if(a)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;const s=n.startsWith(t)?n:t+n.replace(/^\//,"");return o?e+s:s}(t,e,n,r)),[t,e]);return{withBaseUrl:n}}function s(e,t){void 0===t&&(t={});const{withBaseUrl:n}=o();return n(e,t)}},2263:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=n(7294),a=n(8940);function i(){return(0,r.useContext)(a._)}},2389:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=n(7294),a=n(8934);function i(){return(0,r.useContext)(a._)}},469:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});var r=n(7294);const a=n(412).Z.canUseDOM?r.useLayoutEffect:r.useEffect},9670:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r=e=>"object"==typeof e&&!!e&&Object.keys(e).length>0;function a(e){const t={};return function e(n,a){Object.entries(n).forEach((n=>{let[i,o]=n;const s=a?`${a}.${i}`:i;r(o)?e(o,s):t[s]=o}))}(e),t}},226:(e,t,n)=>{"use strict";n.d(t,{_:()=>i,z:()=>o});var r=n(7294),a=n(5893);const i=r.createContext(null);function o(e){let{children:t,value:n}=e;const o=r.useContext(i),s=(0,r.useMemo)((()=>function(e){let{parent:t,value:n}=e;if(!t){if(!n)throw new Error("Unexpected: no Docusaurus route context found");if(!("plugin"in n))throw new Error("Unexpected: Docusaurus topmost route context has no `plugin` attribute");return n}const r={...t.data,...n?.data};return{plugin:t.plugin,data:r}}({parent:o,value:n})),[o,n]);return(0,a.jsx)(i.Provider,{value:s,children:t})}},143:(e,t,n)=>{"use strict";n.d(t,{Iw:()=>m,gA:()=>p,_r:()=>u,Jo:()=>g,zh:()=>d,yW:()=>h,gB:()=>f});var r=n(6550),a=n(2263),i=n(9935);function o(e,t){void 0===t&&(t={});const n=function(){const{globalData:e}=(0,a.Z)();return e}()[e];if(!n&&t.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin.`);return n}const s=e=>e.versions.find((e=>e.isLast));function l(e,t){const n=function(e,t){const n=s(e);return[...e.versions.filter((e=>e!==n)),n].find((e=>!!(0,r.LX)(t,{path:e.path,exact:!1,strict:!1})))}(e,t),a=n?.docs.find((e=>!!(0,r.LX)(t,{path:e.path,exact:!0,strict:!1})));return{activeVersion:n,activeDoc:a,alternateDocVersions:a?function(t){const n={};return e.versions.forEach((e=>{e.docs.forEach((r=>{r.id===t&&(n[e.name]=r)}))})),n}(a.id):{}}}const c={},u=()=>o("docusaurus-plugin-content-docs")??c,d=e=>function(e,t,n){void 0===t&&(t=i.m),void 0===n&&(n={});const r=o(e),a=r?.[t];if(!a&&n.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin with id "${t}".`);return a}("docusaurus-plugin-content-docs",e,{failfast:!0});function p(e){void 0===e&&(e={});const t=u(),{pathname:n}=(0,r.TH)();return function(e,t,n){void 0===n&&(n={});const a=Object.entries(e).sort(((e,t)=>t[1].path.localeCompare(e[1].path))).find((e=>{let[,n]=e;return!!(0,r.LX)(t,{path:n.path,exact:!1,strict:!1})})),i=a?{pluginId:a[0],pluginData:a[1]}:void 0;if(!i&&n.failfast)throw new Error(`Can't find active docs plugin for "${t}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(e).map((e=>e.path)).join(", ")}`);return i}(t,n,e)}function f(e){return d(e).versions}function h(e){const t=d(e);return s(t)}function m(e){const t=d(e),{pathname:n}=(0,r.TH)();return l(t,n)}function g(e){const t=d(e),{pathname:n}=(0,r.TH)();return function(e,t){const n=s(e);return{latestDocSuggestion:l(e,t).alternateDocVersions[n.name],latestVersionSuggestion:n}}(t,n)}},8320:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>i});var r=n(4865),a=n.n(r);a().configure({showSpinner:!1});const i={onRouteUpdate(e){let{location:t,previousLocation:n}=e;if(n&&t.pathname!==n.pathname){const e=window.setTimeout((()=>{a().start()}),200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){a().done()}}},3310:(e,t,n)=>{"use strict";n.r(t);var r=n(2573),a=n(6809);!function(e){const{themeConfig:{prism:t}}=a.default,{additionalLanguages:r}=t;globalThis.Prism=e,r.forEach((e=>{"php"===e&&n(6854),n(7244)(`./prism-${e}`)})),delete globalThis.Prism}(r.p1)},2503:(e,t,n)=>{"use strict";n.d(t,{Z:()=>c});n(7294);var r=n(512),a=n(5999),i=n(6668),o=n(9960);const s={anchorWithStickyNavbar:"anchorWithStickyNavbar_LWe7",anchorWithHideOnScrollNavbar:"anchorWithHideOnScrollNavbar_WYt5"};var l=n(5893);function c(e){let{as:t,id:n,...c}=e;const{navbar:{hideOnScroll:u}}=(0,i.L)();if("h1"===t||!n)return(0,l.jsx)(t,{...c,id:void 0});const d=(0,a.I)({id:"theme.common.headingLinkTitle",message:"Direct link to {heading}",description:"Title for link to heading"},{heading:"string"==typeof c.children?c.children:n});return(0,l.jsxs)(t,{...c,className:(0,r.Z)("anchor",u?s.anchorWithHideOnScrollNavbar:s.anchorWithStickyNavbar,c.className),id:n,children:[c.children,(0,l.jsx)(o.Z,{className:"hash-link",to:`#${n}`,"aria-label":d,title:d,children:"\u200b"})]})}},9471:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});n(7294);const r={iconExternalLink:"iconExternalLink_nPIU"};var a=n(5893);function i(e){let{width:t=13.5,height:n=13.5}=e;return(0,a.jsx)("svg",{width:t,height:n,"aria-hidden":"true",viewBox:"0 0 24 24",className:r.iconExternalLink,children:(0,a.jsx)("path",{fill:"currentColor",d:"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"})})}},6040:(e,t,n)=>{"use strict";n.d(t,{Z:()=>ft});var r=n(7294),a=n(512),i=n(4763),o=n(1944),s=n(6550),l=n(5999),c=n(5936),u=n(5893);const d="__docusaurus_skipToContent_fallback";function p(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function f(){const e=(0,r.useRef)(null),{action:t}=(0,s.k6)(),n=(0,r.useCallback)((e=>{e.preventDefault();const t=document.querySelector("main:first-of-type")??document.getElementById(d);t&&p(t)}),[]);return(0,c.S)((n=>{let{location:r}=n;e.current&&!r.hash&&"PUSH"===t&&p(e.current)})),{containerRef:e,onClick:n}}const h=(0,l.I)({id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation",message:"Skip to main content"});function m(e){const t=e.children??h,{containerRef:n,onClick:r}=f();return(0,u.jsx)("div",{ref:n,role:"region","aria-label":h,children:(0,u.jsx)("a",{...e,href:`#${d}`,onClick:r,children:t})})}var g=n(5281),v=n(9727);const y={skipToContent:"skipToContent_fXgn"};function b(){return(0,u.jsx)(m,{className:y.skipToContent})}var w=n(6668),k=n(9689);function x(e){let{width:t=21,height:n=21,color:r="currentColor",strokeWidth:a=1.2,className:i,...o}=e;return(0,u.jsx)("svg",{viewBox:"0 0 15 15",width:t,height:n,...o,children:(0,u.jsx)("g",{stroke:r,strokeWidth:a,children:(0,u.jsx)("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})})})}const S={closeButton:"closeButton_CVFx"};function _(e){return(0,u.jsx)("button",{type:"button","aria-label":(0,l.I)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"}),...e,className:(0,a.Z)("clean-btn close",S.closeButton,e.className),children:(0,u.jsx)(x,{width:14,height:14,strokeWidth:3.1})})}const E={content:"content_knG7"};function C(e){const{announcementBar:t}=(0,w.L)(),{content:n}=t;return(0,u.jsx)("div",{...e,className:(0,a.Z)(E.content,e.className),dangerouslySetInnerHTML:{__html:n}})}const T={announcementBar:"announcementBar_mb4j",announcementBarPlaceholder:"announcementBarPlaceholder_vyr4",announcementBarClose:"announcementBarClose_gvF7",announcementBarContent:"announcementBarContent_xLdY"};function j(){const{announcementBar:e}=(0,w.L)(),{isActive:t,close:n}=(0,k.nT)();if(!t)return null;const{backgroundColor:r,textColor:a,isCloseable:i}=e;return(0,u.jsxs)("div",{className:T.announcementBar,style:{backgroundColor:r,color:a},role:"banner",children:[i&&(0,u.jsx)("div",{className:T.announcementBarPlaceholder}),(0,u.jsx)(C,{className:T.announcementBarContent}),i&&(0,u.jsx)(_,{onClick:n,className:T.announcementBarClose})]})}var N=n(2961),L=n(2466);var A=n(902),P=n(3102);const O=r.createContext(null);function R(e){let{children:t}=e;const n=function(){const e=(0,N.e)(),t=(0,P.HY)(),[n,a]=(0,r.useState)(!1),i=null!==t.component,o=(0,A.D9)(i);return(0,r.useEffect)((()=>{i&&!o&&a(!0)}),[i,o]),(0,r.useEffect)((()=>{i?e.shown||a(!0):a(!1)}),[e.shown,i]),(0,r.useMemo)((()=>[n,a]),[n])}();return(0,u.jsx)(O.Provider,{value:n,children:t})}function I(e){if(e.component){const t=e.component;return(0,u.jsx)(t,{...e.props})}}function F(){const e=(0,r.useContext)(O);if(!e)throw new A.i6("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,a=(0,r.useCallback)((()=>n(!1)),[n]),i=(0,P.HY)();return(0,r.useMemo)((()=>({shown:t,hide:a,content:I(i)})),[a,i,t])}function D(e){let{header:t,primaryMenu:n,secondaryMenu:r}=e;const{shown:i}=F();return(0,u.jsxs)("div",{className:"navbar-sidebar",children:[t,(0,u.jsxs)("div",{className:(0,a.Z)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":i}),children:[(0,u.jsx)("div",{className:"navbar-sidebar__item menu",children:n}),(0,u.jsx)("div",{className:"navbar-sidebar__item menu",children:r})]})]})}var M=n(2949),z=n(2389);function B(e){return(0,u.jsx)("svg",{viewBox:"0 0 24 24",width:24,height:24,...e,children:(0,u.jsx)("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"})})}function $(e){return(0,u.jsx)("svg",{viewBox:"0 0 24 24",width:24,height:24,...e,children:(0,u.jsx)("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"})})}const U={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function Z(e){let{className:t,buttonClassName:n,value:r,onChange:i}=e;const o=(0,z.Z)(),s=(0,l.I)({message:"Switch between dark and light mode (currently {mode})",id:"theme.colorToggle.ariaLabel",description:"The ARIA label for the navbar color mode toggle"},{mode:"dark"===r?(0,l.I)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,l.I)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return(0,u.jsx)("div",{className:(0,a.Z)(U.toggle,t),children:(0,u.jsxs)("button",{className:(0,a.Z)("clean-btn",U.toggleButton,!o&&U.toggleButtonDisabled,n),type:"button",onClick:()=>i("dark"===r?"light":"dark"),disabled:!o,title:s,"aria-label":s,"aria-live":"polite",children:[(0,u.jsx)(B,{className:(0,a.Z)(U.toggleIcon,U.lightToggleIcon)}),(0,u.jsx)($,{className:(0,a.Z)(U.toggleIcon,U.darkToggleIcon)})]})})}const H=r.memo(Z),q={darkNavbarColorModeToggle:"darkNavbarColorModeToggle_X3D1"};function V(e){let{className:t}=e;const n=(0,w.L)().navbar.style,r=(0,w.L)().colorMode.disableSwitch,{colorMode:a,setColorMode:i}=(0,M.I)();return r?null:(0,u.jsx)(H,{className:t,buttonClassName:"dark"===n?q.darkNavbarColorModeToggle:void 0,value:a,onChange:i})}var W=n(1327);function G(){return(0,u.jsx)(W.Z,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function Y(){const e=(0,N.e)();return(0,u.jsx)("button",{type:"button","aria-label":(0,l.I)({id:"theme.docs.sidebar.closeSidebarButtonAriaLabel",message:"Close navigation bar",description:"The ARIA label for close button of mobile sidebar"}),className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle(),children:(0,u.jsx)(x,{color:"var(--ifm-color-emphasis-600)"})})}function Q(){return(0,u.jsxs)("div",{className:"navbar-sidebar__brand",children:[(0,u.jsx)(G,{}),(0,u.jsx)(V,{className:"margin-right--md"}),(0,u.jsx)(Y,{})]})}var K=n(9960),X=n(4996),J=n(3919);function ee(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}var te=n(9471);function ne(e){let{activeBasePath:t,activeBaseRegex:n,to:r,href:a,label:i,html:o,isDropdownLink:s,prependBaseUrlToHref:l,...c}=e;const d=(0,X.Z)(r),p=(0,X.Z)(t),f=(0,X.Z)(a,{forcePrependBaseUrl:!0}),h=i&&a&&!(0,J.Z)(a),m=o?{dangerouslySetInnerHTML:{__html:o}}:{children:(0,u.jsxs)(u.Fragment,{children:[i,h&&(0,u.jsx)(te.Z,{...s&&{width:12,height:12}})]})};return a?(0,u.jsx)(K.Z,{href:l?f:a,...c,...m}):(0,u.jsx)(K.Z,{to:d,isNavLink:!0,...(t||n)&&{isActive:(e,t)=>n?ee(n,t.pathname):t.pathname.startsWith(p)},...c,...m})}function re(e){let{className:t,isDropdownItem:n=!1,...r}=e;const i=(0,u.jsx)(ne,{className:(0,a.Z)(n?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:n,...r});return n?(0,u.jsx)("li",{children:i}):i}function ae(e){let{className:t,isDropdownItem:n,...r}=e;return(0,u.jsx)("li",{className:"menu__list-item",children:(0,u.jsx)(ne,{className:(0,a.Z)("menu__link",t),...r})})}function ie(e){let{mobile:t=!1,position:n,...r}=e;const a=t?ae:re;return(0,u.jsx)(a,{...r,activeClassName:r.activeClassName??(t?"menu__link--active":"navbar__link--active")})}var oe=n(6043),se=n(8596),le=n(2263);const ce={dropdownNavbarItemMobile:"dropdownNavbarItemMobile_S0Fm"};function ue(e,t){return e.some((e=>function(e,t){return!!(0,se.Mg)(e.to,t)||!!ee(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function de(e){let{items:t,position:n,className:i,onClick:o,...s}=e;const l=(0,r.useRef)(null),[c,d]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{const e=e=>{l.current&&!l.current.contains(e.target)&&d(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),document.addEventListener("focusin",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e),document.removeEventListener("focusin",e)}}),[l]),(0,u.jsxs)("div",{ref:l,className:(0,a.Z)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":c}),children:[(0,u.jsx)(ne,{"aria-haspopup":"true","aria-expanded":c,role:"button",href:s.to?void 0:"#",className:(0,a.Z)("navbar__link",i),...s,onClick:s.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),d(!c))},children:s.children??s.label}),(0,u.jsx)("ul",{className:"dropdown__menu",children:t.map(((e,t)=>(0,r.createElement)(Ee,{isDropdownItem:!0,activeClassName:"dropdown__link--active",...e,key:t})))})]})}function pe(e){let{items:t,className:n,position:i,onClick:o,...l}=e;const c=function(){const{siteConfig:{baseUrl:e}}=(0,le.Z)(),{pathname:t}=(0,s.TH)();return t.replace(e,"/")}(),d=ue(t,c),{collapsed:p,toggleCollapsed:f,setCollapsed:h}=(0,oe.u)({initialState:()=>!d});return(0,r.useEffect)((()=>{d&&h(!d)}),[c,d,h]),(0,u.jsxs)("li",{className:(0,a.Z)("menu__list-item",{"menu__list-item--collapsed":p}),children:[(0,u.jsx)(ne,{role:"button",className:(0,a.Z)(ce.dropdownNavbarItemMobile,"menu__link menu__link--sublist menu__link--sublist-caret",n),...l,onClick:e=>{e.preventDefault(),f()},children:l.children??l.label}),(0,u.jsx)(oe.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:p,children:t.map(((e,t)=>(0,r.createElement)(Ee,{mobile:!0,isDropdownItem:!0,onClick:o,activeClassName:"menu__link--active",...e,key:t})))})]})}function fe(e){let{mobile:t=!1,...n}=e;const r=t?pe:de;return(0,u.jsx)(r,{...n})}var he=n(4711);function me(e){let{width:t=20,height:n=20,...r}=e;return(0,u.jsx)("svg",{viewBox:"0 0 24 24",width:t,height:n,"aria-hidden":!0,...r,children:(0,u.jsx)("path",{fill:"currentColor",d:"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"})})}const ge="iconLanguage_nlXk";var ve=n(1875);const ye={navbarSearchContainer:"navbarSearchContainer_Bca1"};function be(e){let{children:t,className:n}=e;return(0,u.jsx)("div",{className:(0,a.Z)(n,ye.navbarSearchContainer),children:t})}var we=n(143),ke=n(2802);var xe=n(373);const Se=e=>e.docs.find((t=>t.id===e.mainDocId));const _e={default:ie,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:r,queryString:a="",...i}=e;const{i18n:{currentLocale:o,locales:c,localeConfigs:d}}=(0,le.Z)(),p=(0,he.l)(),{search:f,hash:h}=(0,s.TH)(),m=[...n,...c.map((e=>{const n=`${`pathname://${p.createUrl({locale:e,fullyQualified:!1})}`}${f}${h}${a}`;return{label:d[e].label,lang:d[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===o?t?"menu__link--active":"dropdown__link--active":""}})),...r],g=t?(0,l.I)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):d[o].label;return(0,u.jsx)(fe,{...i,mobile:t,label:(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(me,{className:ge}),g]}),items:m})},search:function(e){let{mobile:t,className:n}=e;return t?null:(0,u.jsx)(be,{className:n,children:(0,u.jsx)(ve.Z,{})})},dropdown:fe,html:function(e){let{value:t,className:n,mobile:r=!1,isDropdownItem:i=!1}=e;const o=i?"li":"div";return(0,u.jsx)(o,{className:(0,a.Z)({navbar__item:!r&&!i,"menu__list-item":r},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){let{docId:t,label:n,docsPluginId:r,...a}=e;const{activeDoc:i}=(0,we.Iw)(r),o=(0,ke.vY)(t,r),s=i?.path===o?.path;return null===o||o.unlisted&&!s?null:(0,u.jsx)(ie,{exact:!0,...a,isActive:()=>s||!!i?.sidebar&&i.sidebar===o.sidebar,label:n??o.id,to:o.path})},docSidebar:function(e){let{sidebarId:t,label:n,docsPluginId:r,...a}=e;const{activeDoc:i}=(0,we.Iw)(r),o=(0,ke.oz)(t,r).link;if(!o)throw new Error(`DocSidebarNavbarItem: Sidebar with ID "${t}" doesn't have anything to be linked to.`);return(0,u.jsx)(ie,{exact:!0,...a,isActive:()=>i?.sidebar===t,label:n??o.label,to:o.path})},docsVersion:function(e){let{label:t,to:n,docsPluginId:r,...a}=e;const i=(0,ke.lO)(r)[0],o=t??i.label,s=n??(e=>e.docs.find((t=>t.id===e.mainDocId)))(i).path;return(0,u.jsx)(ie,{...a,label:o,to:s})},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:r,dropdownItemsBefore:a,dropdownItemsAfter:i,...o}=e;const{search:c,hash:d}=(0,s.TH)(),p=(0,we.Iw)(n),f=(0,we.gB)(n),{savePreferredVersionName:h}=(0,xe.J)(n),m=[...a,...f.map((e=>{const t=p.alternateDocVersions[e.name]??Se(e);return{label:e.label,to:`${t.path}${c}${d}`,isActive:()=>e===p.activeVersion,onClick:()=>h(e.name)}})),...i],g=(0,ke.lO)(n)[0],v=t&&m.length>1?(0,l.I)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):g.label,y=t&&m.length>1?void 0:Se(g).path;return m.length<=1?(0,u.jsx)(ie,{...o,mobile:t,label:v,to:y,isActive:r?()=>!1:void 0}):(0,u.jsx)(fe,{...o,mobile:t,label:v,to:y,items:m,isActive:r?()=>!1:void 0})}};function Ee(e){let{type:t,...n}=e;const r=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),a=_e[r];if(!a)throw new Error(`No NavbarItem component found for type "${t}".`);return(0,u.jsx)(a,{...n})}function Ce(){const e=(0,N.e)(),t=(0,w.L)().navbar.items;return(0,u.jsx)("ul",{className:"menu__list",children:t.map(((t,n)=>(0,r.createElement)(Ee,{mobile:!0,...t,onClick:()=>e.toggle(),key:n})))})}function Te(e){return(0,u.jsx)("button",{...e,type:"button",className:"clean-btn navbar-sidebar__back",children:(0,u.jsx)(l.Z,{id:"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel",description:"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)",children:"\u2190 Back to main menu"})})}function je(){const e=0===(0,w.L)().navbar.items.length,t=F();return(0,u.jsxs)(u.Fragment,{children:[!e&&(0,u.jsx)(Te,{onClick:()=>t.hide()}),t.content]})}function Ne(){const e=(0,N.e)();var t;return void 0===(t=e.shown)&&(t=!0),(0,r.useEffect)((()=>(document.body.style.overflow=t?"hidden":"visible",()=>{document.body.style.overflow="visible"})),[t]),e.shouldRender?(0,u.jsx)(D,{header:(0,u.jsx)(Q,{}),primaryMenu:(0,u.jsx)(Ce,{}),secondaryMenu:(0,u.jsx)(je,{})}):null}const Le={navbarHideable:"navbarHideable_m1mJ",navbarHidden:"navbarHidden_jGov"};function Ae(e){return(0,u.jsx)("div",{role:"presentation",...e,className:(0,a.Z)("navbar-sidebar__backdrop",e.className)})}function Pe(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:i}}=(0,w.L)(),o=(0,N.e)(),{navbarRef:s,isNavbarVisible:d}=function(e){const[t,n]=(0,r.useState)(e),a=(0,r.useRef)(!1),i=(0,r.useRef)(0),o=(0,r.useCallback)((e=>{null!==e&&(i.current=e.getBoundingClientRect().height)}),[]);return(0,L.RF)(((t,r)=>{let{scrollY:o}=t;if(!e)return;if(o<i.current)return void n(!0);if(a.current)return void(a.current=!1);const s=r?.scrollY,l=document.documentElement.scrollHeight-i.current,c=window.innerHeight;s&&o>=s?n(!1):o+c<l&&n(!0)})),(0,c.S)((t=>{if(!e)return;const r=t.location.hash;if(r?document.getElementById(r.substring(1)):void 0)return a.current=!0,void n(!1);n(!0)})),{navbarRef:o,isNavbarVisible:t}}(n);return(0,u.jsxs)("nav",{ref:s,"aria-label":(0,l.I)({id:"theme.NavBar.navAriaLabel",message:"Main",description:"The ARIA label for the main navigation"}),className:(0,a.Z)("navbar","navbar--fixed-top",n&&[Le.navbarHideable,!d&&Le.navbarHidden],{"navbar--dark":"dark"===i,"navbar--primary":"primary"===i,"navbar-sidebar--show":o.shown}),children:[t,(0,u.jsx)(Ae,{onClick:o.toggle}),(0,u.jsx)(Ne,{})]})}var Oe=n(8780);const Re={errorBoundaryError:"errorBoundaryError_a6uf",errorBoundaryFallback:"errorBoundaryFallback_VBag"};function Ie(e){return(0,u.jsx)("button",{type:"button",...e,children:(0,u.jsx)(l.Z,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again rendering when the React error boundary captures an error",children:"Try again"})})}function Fe(e){let{error:t}=e;const n=(0,Oe.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return(0,u.jsx)("p",{className:Re.errorBoundaryError,children:n})}class De extends r.Component{componentDidCatch(e,t){throw this.props.onError(e,t)}render(){return this.props.children}}const Me="right";function ze(e){let{width:t=30,height:n=30,className:r,...a}=e;return(0,u.jsx)("svg",{className:r,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true",...a,children:(0,u.jsx)("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"})})}function Be(){const{toggle:e,shown:t}=(0,N.e)();return(0,u.jsx)("button",{onClick:e,"aria-label":(0,l.I)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button",children:(0,u.jsx)(ze,{})})}const $e={colorModeToggle:"colorModeToggle_DEke"};function Ue(e){let{items:t}=e;return(0,u.jsx)(u.Fragment,{children:t.map(((e,t)=>(0,u.jsx)(De,{onError:t=>new Error(`A theme navbar item failed to render.\nPlease double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:\n${JSON.stringify(e,null,2)}`,{cause:t}),children:(0,u.jsx)(Ee,{...e})},t)))})}function Ze(e){let{left:t,right:n}=e;return(0,u.jsxs)("div",{className:"navbar__inner",children:[(0,u.jsx)("div",{className:"navbar__items",children:t}),(0,u.jsx)("div",{className:"navbar__items navbar__items--right",children:n})]})}function He(){const e=(0,N.e)(),t=(0,w.L)().navbar.items,[n,r]=function(e){function t(e){return"left"===(e.position??Me)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),a=t.find((e=>"search"===e.type));return(0,u.jsx)(Ze,{left:(0,u.jsxs)(u.Fragment,{children:[!e.disabled&&(0,u.jsx)(Be,{}),(0,u.jsx)(G,{}),(0,u.jsx)(Ue,{items:n})]}),right:(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(Ue,{items:r}),(0,u.jsx)(V,{className:$e.colorModeToggle}),!a&&(0,u.jsx)(be,{children:(0,u.jsx)(ve.Z,{})})]})})}function qe(){return(0,u.jsx)(Pe,{children:(0,u.jsx)(He,{})})}function Ve(e){let{item:t}=e;const{to:n,href:r,label:a,prependBaseUrlToHref:i,...o}=t,s=(0,X.Z)(n),l=(0,X.Z)(r,{forcePrependBaseUrl:!0});return(0,u.jsxs)(K.Z,{className:"footer__link-item",...r?{href:i?l:r}:{to:s},...o,children:[a,r&&!(0,J.Z)(r)&&(0,u.jsx)(te.Z,{})]})}function We(e){let{item:t}=e;return t.html?(0,u.jsx)("li",{className:"footer__item",dangerouslySetInnerHTML:{__html:t.html}}):(0,u.jsx)("li",{className:"footer__item",children:(0,u.jsx)(Ve,{item:t})},t.href??t.to)}function Ge(e){let{column:t}=e;return(0,u.jsxs)("div",{className:"col footer__col",children:[(0,u.jsx)("div",{className:"footer__title",children:t.title}),(0,u.jsx)("ul",{className:"footer__items clean-list",children:t.items.map(((e,t)=>(0,u.jsx)(We,{item:e},t)))})]})}function Ye(e){let{columns:t}=e;return(0,u.jsx)("div",{className:"row footer__links",children:t.map(((e,t)=>(0,u.jsx)(Ge,{column:e},t)))})}function Qe(){return(0,u.jsx)("span",{className:"footer__link-separator",children:"\xb7"})}function Ke(e){let{item:t}=e;return t.html?(0,u.jsx)("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):(0,u.jsx)(Ve,{item:t})}function Xe(e){let{links:t}=e;return(0,u.jsx)("div",{className:"footer__links text--center",children:(0,u.jsx)("div",{className:"footer__links",children:t.map(((e,n)=>(0,u.jsxs)(r.Fragment,{children:[(0,u.jsx)(Ke,{item:e}),t.length!==n+1&&(0,u.jsx)(Qe,{})]},n)))})})}function Je(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?(0,u.jsx)(Ye,{columns:t}):(0,u.jsx)(Xe,{links:t})}var et=n(9965);const tt={footerLogoLink:"footerLogoLink_BH7S"};function nt(e){let{logo:t}=e;const{withBaseUrl:n}=(0,X.C)(),r={light:n(t.src),dark:n(t.srcDark??t.src)};return(0,u.jsx)(et.Z,{className:(0,a.Z)("footer__logo",t.className),alt:t.alt,sources:r,width:t.width,height:t.height,style:t.style})}function rt(e){let{logo:t}=e;return t.href?(0,u.jsx)(K.Z,{href:t.href,className:tt.footerLogoLink,target:t.target,children:(0,u.jsx)(nt,{logo:t})}):(0,u.jsx)(nt,{logo:t})}function at(e){let{copyright:t}=e;return(0,u.jsx)("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function it(e){let{style:t,links:n,logo:r,copyright:i}=e;return(0,u.jsx)("footer",{className:(0,a.Z)("footer",{"footer--dark":"dark"===t}),children:(0,u.jsxs)("div",{className:"container container-fluid",children:[n,(r||i)&&(0,u.jsxs)("div",{className:"footer__bottom text--center",children:[r&&(0,u.jsx)("div",{className:"margin-bottom--sm",children:r}),i]})]})})}function ot(){const{footer:e}=(0,w.L)();if(!e)return null;const{copyright:t,links:n,logo:r,style:a}=e;return(0,u.jsx)(it,{style:a,links:n&&n.length>0&&(0,u.jsx)(Je,{links:n}),logo:r&&(0,u.jsx)(rt,{logo:r}),copyright:t&&(0,u.jsx)(at,{copyright:t})})}const st=r.memo(ot),lt=(0,A.Qc)([M.S,k.pl,L.OC,xe.L5,o.VC,function(e){let{children:t}=e;return(0,u.jsx)(P.n2,{children:(0,u.jsx)(N.M,{children:(0,u.jsx)(R,{children:t})})})}]);function ct(e){let{children:t}=e;return(0,u.jsx)(lt,{children:t})}var ut=n(2503);function dt(e){let{error:t,tryAgain:n}=e;return(0,u.jsx)("main",{className:"container margin-vert--xl",children:(0,u.jsx)("div",{className:"row",children:(0,u.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,u.jsx)(ut.Z,{as:"h1",className:"hero__title",children:(0,u.jsx)(l.Z,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed",children:"This page crashed."})}),(0,u.jsx)("div",{className:"margin-vert--lg",children:(0,u.jsx)(Ie,{onClick:n,className:"button button--primary shadow--lw"})}),(0,u.jsx)("hr",{}),(0,u.jsx)("div",{className:"margin-vert--md",children:(0,u.jsx)(Fe,{error:t})})]})})})}const pt={mainWrapper:"mainWrapper_z2l0"};function ft(e){const{children:t,noFooter:n,wrapperClassName:r,title:s,description:l}=e;return(0,v.t)(),(0,u.jsxs)(ct,{children:[(0,u.jsx)(o.d,{title:s,description:l}),(0,u.jsx)(b,{}),(0,u.jsx)(j,{}),(0,u.jsx)(qe,{}),(0,u.jsx)("div",{id:d,className:(0,a.Z)(g.k.wrapper.main,pt.mainWrapper,r),children:(0,u.jsx)(i.Z,{fallback:e=>(0,u.jsx)(dt,{...e}),children:t})}),!n&&(0,u.jsx)(st,{})]})}},1327:(e,t,n)=>{"use strict";n.d(t,{Z:()=>u});n(7294);var r=n(9960),a=n(4996),i=n(2263),o=n(6668),s=n(9965),l=n(5893);function c(e){let{logo:t,alt:n,imageClassName:r}=e;const i={light:(0,a.Z)(t.src),dark:(0,a.Z)(t.srcDark||t.src)},o=(0,l.jsx)(s.Z,{className:t.className,sources:i,height:t.height,width:t.width,alt:n,style:t.style});return r?(0,l.jsx)("div",{className:r,children:o}):o}function u(e){const{siteConfig:{title:t}}=(0,i.Z)(),{navbar:{title:n,logo:s}}=(0,o.L)(),{imageClassName:u,titleClassName:d,...p}=e,f=(0,a.Z)(s?.href||"/"),h=n?"":t,m=s?.alt??h;return(0,l.jsxs)(r.Z,{to:f,...p,...s?.target&&{target:s.target},children:[s&&(0,l.jsx)(c,{logo:s,alt:m,imageClassName:u}),null!=n&&(0,l.jsx)("b",{className:d,children:n})]})}},197:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});n(7294);var r=n(5742),a=n(5893);function i(e){let{locale:t,version:n,tag:i}=e;const o=t;return(0,a.jsxs)(r.Z,{children:[t&&(0,a.jsx)("meta",{name:"docusaurus_locale",content:t}),n&&(0,a.jsx)("meta",{name:"docusaurus_version",content:n}),i&&(0,a.jsx)("meta",{name:"docusaurus_tag",content:i}),o&&(0,a.jsx)("meta",{name:"docsearch:language",content:o}),n&&(0,a.jsx)("meta",{name:"docsearch:version",content:n}),i&&(0,a.jsx)("meta",{name:"docsearch:docusaurus_tag",content:i})]})}},9965:(e,t,n)=>{"use strict";n.d(t,{Z:()=>u});var r=n(7294),a=n(512),i=n(2389),o=n(2949);const s={themedComponent:"themedComponent_mlkZ","themedComponent--light":"themedComponent--light_NVdE","themedComponent--dark":"themedComponent--dark_xIcU"};var l=n(5893);function c(e){let{className:t,children:n}=e;const c=(0,i.Z)(),{colorMode:u}=(0,o.I)();return(0,l.jsx)(l.Fragment,{children:(c?"dark"===u?["dark"]:["light"]:["light","dark"]).map((e=>{const i=n({theme:e,className:(0,a.Z)(t,s.themedComponent,s[`themedComponent--${e}`])});return(0,l.jsx)(r.Fragment,{children:i},e)}))})}function u(e){const{sources:t,className:n,alt:r,...a}=e;return(0,l.jsx)(c,{className:n,children:e=>{let{theme:n,className:i}=e;return(0,l.jsx)("img",{src:t[n],alt:r,className:i,...a})}})}},6043:(e,t,n)=>{"use strict";n.d(t,{u:()=>c,z:()=>v});var r=n(7294),a=n(412),i=n(469),o=n(1442),s=n(5893);const l="ease-in-out";function c(e){let{initialState:t}=e;const[n,a]=(0,r.useState)(t??!1),i=(0,r.useCallback)((()=>{a((e=>!e))}),[]);return{collapsed:n,setCollapsed:a,toggleCollapsed:i}}const u={display:"none",overflow:"hidden",height:"0px"},d={display:"block",overflow:"visible",height:"auto"};function p(e,t){const n=t?u:d;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function f(e){let{collapsibleRef:t,collapsed:n,animation:a}=e;const i=(0,r.useRef)(!1);(0,r.useEffect)((()=>{const e=t.current;function r(){const t=e.scrollHeight,n=a?.duration??function(e){if((0,o.n)())return 1;const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(t);return{transition:`height ${n}ms ${a?.easing??l}`,height:`${t}px`}}function s(){const t=r();e.style.transition=t.transition,e.style.height=t.height}if(!i.current)return p(e,n),void(i.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(s(),requestAnimationFrame((()=>{e.style.height=u.height,e.style.overflow=u.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{s()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,a])}function h(e){if(!a.Z.canUseDOM)return e?u:d}function m(e){let{as:t="div",collapsed:n,children:a,animation:i,onCollapseTransitionEnd:o,className:l,disableSSRStyle:c}=e;const u=(0,r.useRef)(null);return f({collapsibleRef:u,collapsed:n,animation:i}),(0,s.jsx)(t,{ref:u,style:c?void 0:h(n),onTransitionEnd:e=>{"height"===e.propertyName&&(p(u.current,n),o?.(n))},className:l,children:a})}function g(e){let{collapsed:t,...n}=e;const[a,o]=(0,r.useState)(!t),[l,c]=(0,r.useState)(t);return(0,i.Z)((()=>{t||o(!0)}),[t]),(0,i.Z)((()=>{a&&c(t)}),[a,t]),a?(0,s.jsx)(m,{...n,collapsed:l}):null}function v(e){let{lazy:t,...n}=e;const r=t?g:m;return(0,s.jsx)(r,{...n})}},9689:(e,t,n)=>{"use strict";n.d(t,{nT:()=>m,pl:()=>h});var r=n(7294),a=n(2389),i=n(12),o=n(902),s=n(6668),l=n(5893);const c=(0,i.WA)("docusaurus.announcement.dismiss"),u=(0,i.WA)("docusaurus.announcement.id"),d=()=>"true"===c.get(),p=e=>c.set(String(e)),f=r.createContext(null);function h(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,s.L)(),t=(0,a.Z)(),[n,i]=(0,r.useState)((()=>!!t&&d()));(0,r.useEffect)((()=>{i(d())}),[]);const o=(0,r.useCallback)((()=>{p(!0),i(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=u.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;u.set(t),r&&p(!1),!r&&d()||i(!1)}),[e]),(0,r.useMemo)((()=>({isActive:!!e&&!n,close:o})),[e,n,o])}();return(0,l.jsx)(f.Provider,{value:n,children:t})}function m(){const e=(0,r.useContext)(f);if(!e)throw new o.i6("AnnouncementBarProvider");return e}},2949:(e,t,n)=>{"use strict";n.d(t,{I:()=>v,S:()=>g});var r=n(7294),a=n(412),i=n(902),o=n(12),s=n(6668),l=n(5893);const c=r.createContext(void 0),u="theme",d=(0,o.WA)(u),p={light:"light",dark:"dark"},f=e=>e===p.dark?p.dark:p.light,h=e=>a.Z.canUseDOM?f(document.documentElement.getAttribute("data-theme")):f(e),m=e=>{d.set(f(e))};function g(e){let{children:t}=e;const n=function(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,s.L)(),[a,i]=(0,r.useState)(h(e));(0,r.useEffect)((()=>{t&&d.del()}),[t]);const o=(0,r.useCallback)((function(t,r){void 0===r&&(r={});const{persist:a=!0}=r;t?(i(t),a&&m(t)):(i(n?window.matchMedia("(prefers-color-scheme: dark)").matches?p.dark:p.light:e),d.del())}),[n,e]);(0,r.useEffect)((()=>{document.documentElement.setAttribute("data-theme",f(a))}),[a]),(0,r.useEffect)((()=>{if(t)return;const e=e=>{if(e.key!==u)return;const t=d.get();null!==t&&o(f(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,o]);const l=(0,r.useRef)(!1);return(0,r.useEffect)((()=>{if(t&&!n)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),r=()=>{window.matchMedia("print").matches||l.current?l.current=window.matchMedia("print").matches:o(null)};return e.addListener(r),()=>e.removeListener(r)}),[o,t,n]),(0,r.useMemo)((()=>({colorMode:a,setColorMode:o,get isDarkTheme(){return a===p.dark},setLightTheme(){o(p.light)},setDarkTheme(){o(p.dark)}})),[a,o])}();return(0,l.jsx)(c.Provider,{value:n,children:t})}function v(){const e=(0,r.useContext)(c);if(null==e)throw new i.i6("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},373:(e,t,n)=>{"use strict";n.d(t,{J:()=>b,L5:()=>v});var r=n(7294),a=n(143),i=n(9935),o=n(6668),s=n(2802),l=n(902),c=n(12),u=n(5893);const d=e=>`docs-preferred-version-${e}`,p={save:(e,t,n)=>{(0,c.WA)(d(e),{persistence:t}).set(n)},read:(e,t)=>(0,c.WA)(d(e),{persistence:t}).get(),clear:(e,t)=>{(0,c.WA)(d(e),{persistence:t}).del()}},f=e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}])));const h=r.createContext(null);function m(){const e=(0,a._r)(),t=(0,o.L)().docs.versionPersistence,n=(0,r.useMemo)((()=>Object.keys(e)),[e]),[i,s]=(0,r.useState)((()=>f(n)));(0,r.useEffect)((()=>{s(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:r}=e;function a(e){const t=p.read(e,n);return r[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(p.clear(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,a(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[i,(0,r.useMemo)((()=>({savePreferredVersion:function(e,n){p.save(e,t,n),s((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function g(e){let{children:t}=e;const n=m();return(0,u.jsx)(h.Provider,{value:n,children:t})}function v(e){let{children:t}=e;return s.cE?(0,u.jsx)(g,{children:t}):(0,u.jsx)(u.Fragment,{children:t})}function y(){const e=(0,r.useContext)(h);if(!e)throw new l.i6("DocsPreferredVersionContextProvider");return e}function b(e){void 0===e&&(e=i.m);const t=(0,a.zh)(e),[n,o]=y(),{preferredVersionName:s}=n[e];return{preferredVersion:t.versions.find((e=>e.name===s))??null,savePreferredVersionName:(0,r.useCallback)((t=>{o.savePreferredVersion(e,t)}),[o,e])}}},1116:(e,t,n)=>{"use strict";n.d(t,{V:()=>c,b:()=>l});var r=n(7294),a=n(902),i=n(5893);const o=Symbol("EmptyContext"),s=r.createContext(o);function l(e){let{children:t,name:n,items:a}=e;const o=(0,r.useMemo)((()=>n&&a?{name:n,items:a}:null),[n,a]);return(0,i.jsx)(s.Provider,{value:o,children:t})}function c(){const e=(0,r.useContext)(s);if(e===o)throw new a.i6("DocsSidebarProvider");return e}},4477:(e,t,n)=>{"use strict";n.d(t,{E:()=>l,q:()=>s});var r=n(7294),a=n(902),i=n(5893);const o=r.createContext(null);function s(e){let{children:t,version:n}=e;return(0,i.jsx)(o.Provider,{value:n,children:t})}function l(){const e=(0,r.useContext)(o);if(null===e)throw new a.i6("DocsVersionProvider");return e}},2961:(e,t,n)=>{"use strict";n.d(t,{M:()=>f,e:()=>h});var r=n(7294),a=n(3102),i=n(7524),o=n(6550),s=n(902);function l(e){!function(e){const t=(0,o.k6)(),n=(0,s.zX)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}var c=n(6668),u=n(5893);const d=r.createContext(void 0);function p(){const e=function(){const e=(0,a.HY)(),{items:t}=(0,c.L)().navbar;return 0===t.length&&!e.component}(),t=(0,i.i)(),n=!e&&"mobile"===t,[o,s]=(0,r.useState)(!1);l((()=>{if(o)return s(!1),!1}));const u=(0,r.useCallback)((()=>{s((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&s(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:u,shown:o})),[e,n,u,o])}function f(e){let{children:t}=e;const n=p();return(0,u.jsx)(d.Provider,{value:n,children:t})}function h(){const e=r.useContext(d);if(void 0===e)throw new s.i6("NavbarMobileSidebarProvider");return e}},3102:(e,t,n)=>{"use strict";n.d(t,{HY:()=>l,Zo:()=>c,n2:()=>s});var r=n(7294),a=n(902),i=n(5893);const o=r.createContext(null);function s(e){let{children:t}=e;const n=(0,r.useState)({component:null,props:null});return(0,i.jsx)(o.Provider,{value:n,children:t})}function l(){const e=(0,r.useContext)(o);if(!e)throw new a.i6("NavbarSecondaryMenuContentProvider");return e[0]}function c(e){let{component:t,props:n}=e;const i=(0,r.useContext)(o);if(!i)throw new a.i6("NavbarSecondaryMenuContentProvider");const[,s]=i,l=(0,a.Ql)(n);return(0,r.useEffect)((()=>{s({component:t,props:l})}),[s,t,l]),(0,r.useEffect)((()=>()=>s({component:null,props:null})),[s]),null}},9727:(e,t,n)=>{"use strict";n.d(t,{h:()=>a,t:()=>i});var r=n(7294);const a="navigation-with-keyboard";function i(){(0,r.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(a),"mousedown"===e.type&&document.body.classList.remove(a)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(a),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},7524:(e,t,n)=>{"use strict";n.d(t,{i:()=>s});var r=n(7294),a=n(412);const i={desktop:"desktop",mobile:"mobile",ssr:"ssr"},o=996;function s(){const[e,t]=(0,r.useState)((()=>"ssr"));return(0,r.useEffect)((()=>{function e(){t(function(){if(!a.Z.canUseDOM)throw new Error("getWindowSize() should only be called after React hydration");return window.innerWidth>o?i.desktop:i.mobile}())}return e(),window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e)}}),[]),e}},5281:(e,t,n)=>{"use strict";n.d(t,{k:()=>r});const r={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",unlistedBanner:"theme-unlisted-banner",admonitionType:e=>`theme-admonition-${e}`},layout:{},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{}}},1442:(e,t,n)=>{"use strict";function r(){return window.matchMedia("(prefers-reduced-motion: reduce)").matches}n.d(t,{n:()=>r})},2802:(e,t,n)=>{"use strict";n.d(t,{LM:()=>f,_F:()=>g,cE:()=>p,SN:()=>_,lO:()=>k,vY:()=>S,oz:()=>x,s1:()=>w,f:()=>y});var r=n(7294),a=n(6550),i=n(8790),o=n(143),s=n(373),l=n(4477),c=n(1116);function u(e){return Array.from(new Set(e))}var d=n(8596);const p=!!o._r;function f(e){return"link"!==e.type||e.unlisted?"category"===e.type?function(e){if(e.href&&!e.linkUnlisted)return e.href;for(const t of e.items){const e=f(t);if(e)return e}}(e):void 0:e.href}const h=(e,t)=>void 0!==e&&(0,d.Mg)(e,t),m=(e,t)=>e.some((e=>g(e,t)));function g(e,t){return"link"===e.type?h(e.href,t):"category"===e.type&&(h(e.href,t)||m(e.items,t))}function v(e,t){switch(e.type){case"category":return g(e,t)||e.items.some((e=>v(e,t)));case"link":return!e.unlisted||g(e,t);default:return!0}}function y(e,t){return(0,r.useMemo)((()=>e.filter((e=>v(e,t)))),[e,t])}function b(e){let{sidebarItems:t,pathname:n,onlyCategories:r=!1}=e;const a=[];return function e(t){for(const i of t)if("category"===i.type&&((0,d.Mg)(i.href,n)||e(i.items))||"link"===i.type&&(0,d.Mg)(i.href,n)){return r&&"category"!==i.type||a.unshift(i),!0}return!1}(t),a}function w(){const e=(0,c.V)(),{pathname:t}=(0,a.TH)(),n=(0,o.gA)()?.pluginData.breadcrumbs;return!1!==n&&e?b({sidebarItems:e.items,pathname:t}):null}function k(e){const{activeVersion:t}=(0,o.Iw)(e),{preferredVersion:n}=(0,s.J)(e),a=(0,o.yW)(e);return(0,r.useMemo)((()=>u([t,n,a].filter(Boolean))),[t,n,a])}function x(e,t){const n=k(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),r=t.find((t=>t[0]===e));if(!r)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable sidebar ids are:\n- ${t.map((e=>e[0])).join("\n- ")}`);return r[1]}),[e,n])}function S(e,t){const n=k(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),r=t.find((t=>t.id===e));if(!r){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`Couldn't find any doc with id "${e}" in version${n.length>1?"s":""} "${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${u(t.map((e=>e.id))).join("\n- ")}`)}return r}),[e,n])}function _(e){let{route:t}=e;const n=(0,a.TH)(),r=(0,l.E)(),o=t.routes,s=o.find((e=>(0,a.LX)(n.pathname,e)));if(!s)return null;const c=s.sidebar,u=c?r.docsSidebars[c]:void 0;return{docElement:(0,i.H)(o),sidebarName:c,sidebarItems:u}}},1944:(e,t,n)=>{"use strict";n.d(t,{FG:()=>f,d:()=>d,VC:()=>h});var r=n(7294),a=n(512),i=n(5742),o=n(226);function s(){const e=r.useContext(o._);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var l=n(4996),c=n(2263);var u=n(5893);function d(e){let{title:t,description:n,keywords:r,image:a,children:o}=e;const s=function(e){const{siteConfig:t}=(0,c.Z)(),{title:n,titleDelimiter:r}=t;return e?.trim().length?`${e.trim()} ${r} ${n}`:n}(t),{withBaseUrl:d}=(0,l.C)(),p=a?d(a,{absolute:!0}):void 0;return(0,u.jsxs)(i.Z,{children:[t&&(0,u.jsx)("title",{children:s}),t&&(0,u.jsx)("meta",{property:"og:title",content:s}),n&&(0,u.jsx)("meta",{name:"description",content:n}),n&&(0,u.jsx)("meta",{property:"og:description",content:n}),r&&(0,u.jsx)("meta",{name:"keywords",content:Array.isArray(r)?r.join(","):r}),p&&(0,u.jsx)("meta",{property:"og:image",content:p}),p&&(0,u.jsx)("meta",{name:"twitter:image",content:p}),o]})}const p=r.createContext(void 0);function f(e){let{className:t,children:n}=e;const o=r.useContext(p),s=(0,a.Z)(o,t);return(0,u.jsxs)(p.Provider,{value:s,children:[(0,u.jsx)(i.Z,{children:(0,u.jsx)("html",{className:s})}),n]})}function h(e){let{children:t}=e;const n=s(),r=`plugin-${n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const i=`plugin-id-${n.plugin.id}`;return(0,u.jsx)(f,{className:(0,a.Z)(r,i),children:t})}},902:(e,t,n)=>{"use strict";n.d(t,{D9:()=>s,Qc:()=>u,Ql:()=>c,i6:()=>l,zX:()=>o});var r=n(7294),a=n(469),i=n(5893);function o(e){const t=(0,r.useRef)(e);return(0,a.Z)((()=>{t.current=e}),[e]),(0,r.useCallback)((function(){return t.current(...arguments)}),[])}function s(e){const t=(0,r.useRef)();return(0,a.Z)((()=>{t.current=e})),t.current}class l extends Error{constructor(e,t){super(),this.name="ReactContextError",this.message=`Hook ${this.stack?.split("\n")[1]?.match(/at (?:\w+\.)?(?<name>\w+)/)?.groups.name??""} is called outside the <${e}>. ${t??""}`}}function c(e){const t=Object.entries(e);return t.sort(((e,t)=>e[0].localeCompare(t[0]))),(0,r.useMemo)((()=>e),t.flat())}function u(e){return t=>{let{children:n}=t;return(0,i.jsx)(i.Fragment,{children:e.reduceRight(((e,t)=>(0,i.jsx)(t,{children:e})),n)})}}},8596:(e,t,n)=>{"use strict";n.d(t,{Mg:()=>o,Ns:()=>s});var r=n(7294),a=n(723),i=n(2263);function o(e,t){const n=e=>(!e||e.endsWith("/")?e:`${e}/`)?.toLowerCase();return n(e)===n(t)}function s(){const{baseUrl:e}=(0,i.Z)().siteConfig;return(0,r.useMemo)((()=>function(e){let{baseUrl:t,routes:n}=e;function r(e){return e.path===t&&!0===e.exact}function a(e){return e.path===t&&!e.exact}return function e(t){if(0===t.length)return;return t.find(r)||e(t.filter(a).flatMap((e=>e.routes??[])))}(n)}({routes:a.Z,baseUrl:e})),[e])}},2466:(e,t,n)=>{"use strict";n.d(t,{Ct:()=>f,OC:()=>c,RF:()=>p});var r=n(7294),a=n(412),i=n(2389),o=(n(469),n(902)),s=n(5893);const l=r.createContext(void 0);function c(e){let{children:t}=e;const n=function(){const e=(0,r.useRef)(!0);return(0,r.useMemo)((()=>({scrollEventsEnabledRef:e,enableScrollEvents:()=>{e.current=!0},disableScrollEvents:()=>{e.current=!1}})),[])}();return(0,s.jsx)(l.Provider,{value:n,children:t})}function u(){const e=(0,r.useContext)(l);if(null==e)throw new o.i6("ScrollControllerProvider");return e}const d=()=>a.Z.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function p(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=u(),a=(0,r.useRef)(d()),i=(0,o.zX)(e);(0,r.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=d();i(e,a.current),a.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)}),[i,n,...t])}function f(){const e=(0,r.useRef)(null),t=(0,i.Z)()&&"smooth"===getComputedStyle(document.documentElement).scrollBehavior;return{startScroll:n=>{e.current=t?function(e){return window.scrollTo({top:e,behavior:"smooth"}),()=>{}}(n):function(e){let t=null;const n=document.documentElement.scrollTop>e;return function r(){const a=document.documentElement.scrollTop;(n&&a>e||!n&&a<e)&&(t=requestAnimationFrame(r),window.scrollTo(0,Math.floor(.85*(a-e))+e))}(),()=>t&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>e.current?.()}}},3320:(e,t,n)=>{"use strict";n.d(t,{HX:()=>r,os:()=>a});n(2263);const r="default";function a(e,t){return`docs-${e}-${t}`}},12:(e,t,n)=>{"use strict";n.d(t,{WA:()=>l});n(7294);const r="localStorage";function a(e){let{key:t,oldValue:n,newValue:r,storage:a}=e;if(n===r)return;const i=document.createEvent("StorageEvent");i.initStorageEvent("storage",!1,!1,t,n,r,window.location.href,a),window.dispatchEvent(i)}function i(e){if(void 0===e&&(e=r),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,o||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),o=!0),null}var t}let o=!1;const s={get:()=>null,set:()=>{},del:()=>{},listen:()=>()=>{}};function l(e,t){if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t,listen:t}}(e);const n=i(t?.persistence);return null===n?s:{get:()=>{try{return n.getItem(e)}catch(t){return console.error(`Docusaurus storage error, can't get key=${e}`,t),null}},set:t=>{try{const r=n.getItem(e);n.setItem(e,t),a({key:e,oldValue:r,newValue:t,storage:n})}catch(r){console.error(`Docusaurus storage error, can't set ${e}=${t}`,r)}},del:()=>{try{const t=n.getItem(e);n.removeItem(e),a({key:e,oldValue:t,newValue:null,storage:n})}catch(t){console.error(`Docusaurus storage error, can't delete key=${e}`,t)}},listen:t=>{try{const r=r=>{r.storageArea===n&&r.key===e&&t(r)};return window.addEventListener("storage",r),()=>window.removeEventListener("storage",r)}catch(r){return console.error(`Docusaurus storage error, can't listen for changes of key=${e}`,r),()=>{}}}}}},4711:(e,t,n)=>{"use strict";n.d(t,{l:()=>o});var r=n(2263),a=n(6550),i=n(8780);function o(){const{siteConfig:{baseUrl:e,url:t,trailingSlash:n},i18n:{defaultLocale:o,currentLocale:s}}=(0,r.Z)(),{pathname:l}=(0,a.TH)(),c=(0,i.applyTrailingSlash)(l,{trailingSlash:n,baseUrl:e}),u=s===o?e:e.replace(`/${s}/`,"/"),d=c.replace(e,"");return{createUrl:function(e){let{locale:n,fullyQualified:r}=e;return`${r?t:""}${function(e){return e===o?`${u}`:`${u}${e}/`}(n)}${d}`}}}},5936:(e,t,n)=>{"use strict";n.d(t,{S:()=>o});var r=n(7294),a=n(6550),i=n(902);function o(e){const t=(0,a.TH)(),n=(0,i.D9)(t),o=(0,i.zX)(e);(0,r.useEffect)((()=>{n&&t!==n&&o({location:t,previousLocation:n})}),[o,t,n])}},6668:(e,t,n)=>{"use strict";n.d(t,{L:()=>a});var r=n(2263);function a(){return(0,r.Z)().siteConfig.themeConfig}},8802:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){const{trailingSlash:n,baseUrl:r}=t;if(e.startsWith("#"))return e;if(void 0===n)return e;const[a]=e.split(/[#?]/),i="/"===a||a===r?a:(o=a,n?function(e){return e.endsWith("/")?e:`${e}/`}(o):function(e){return e.endsWith("/")?e.slice(0,-1):e}(o));var o;return e.replace(a,i)}},4143:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=void 0,t.getErrorCausalChain=function e(t){return t.cause?[t,...e(t.cause)]:[t]}},8780:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=t.applyTrailingSlash=t.blogPostContainerID=void 0,t.blogPostContainerID="__blog-post-container";var a=n(8802);Object.defineProperty(t,"applyTrailingSlash",{enumerable:!0,get:function(){return r(a).default}});var i=n(4143);Object.defineProperty(t,"getErrorCausalChain",{enumerable:!0,get:function(){return i.getErrorCausalChain}})},9318:(e,t,n)=>{"use strict";n.d(t,{lX:()=>w,q_:()=>C,ob:()=>f,PP:()=>j,Ep:()=>p});var r=n(7462);function a(e){return"/"===e.charAt(0)}function i(e,t){for(var n=t,r=n+1,a=e.length;r<a;n+=1,r+=1)e[n]=e[r];e.pop()}const o=function(e,t){void 0===t&&(t="");var n,r=e&&e.split("/")||[],o=t&&t.split("/")||[],s=e&&a(e),l=t&&a(t),c=s||l;if(e&&a(e)?o=r:r.length&&(o.pop(),o=o.concat(r)),!o.length)return"/";if(o.length){var u=o[o.length-1];n="."===u||".."===u||""===u}else n=!1;for(var d=0,p=o.length;p>=0;p--){var f=o[p];"."===f?i(o,p):".."===f?(i(o,p),d++):d&&(i(o,p),d--)}if(!c)for(;d--;d)o.unshift("..");!c||""===o[0]||o[0]&&a(o[0])||o.unshift("");var h=o.join("/");return n&&"/"!==h.substr(-1)&&(h+="/"),h};var s=n(8776);function l(e){return"/"===e.charAt(0)?e:"/"+e}function c(e){return"/"===e.charAt(0)?e.substr(1):e}function u(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function d(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function p(e){var t=e.pathname,n=e.search,r=e.hash,a=t||"/";return n&&"?"!==n&&(a+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(a+="#"===r.charAt(0)?r:"#"+r),a}function f(e,t,n,a){var i;"string"==typeof e?(i=function(e){var t=e||"/",n="",r="",a=t.indexOf("#");-1!==a&&(r=t.substr(a),t=t.substr(0,a));var i=t.indexOf("?");return-1!==i&&(n=t.substr(i),t=t.substr(0,i)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),i.state=t):(void 0===(i=(0,r.Z)({},e)).pathname&&(i.pathname=""),i.search?"?"!==i.search.charAt(0)&&(i.search="?"+i.search):i.search="",i.hash?"#"!==i.hash.charAt(0)&&(i.hash="#"+i.hash):i.hash="",void 0!==t&&void 0===i.state&&(i.state=t));try{i.pathname=decodeURI(i.pathname)}catch(s){throw s instanceof URIError?new URIError('Pathname "'+i.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):s}return n&&(i.key=n),a?i.pathname?"/"!==i.pathname.charAt(0)&&(i.pathname=o(i.pathname,a.pathname)):i.pathname=a.pathname:i.pathname||(i.pathname="/"),i}function h(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,a){if(null!=e){var i="function"==typeof e?e(t,n):e;"string"==typeof i?"function"==typeof r?r(i,a):a(!0):a(!1!==i)}else a(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter((function(e){return e!==r}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;r<e;r++)n[r]=arguments[r];t.forEach((function(e){return e.apply(void 0,n)}))}}}var m=!("undefined"==typeof window||!window.document||!window.document.createElement);function g(e,t){t(window.confirm(e))}var v="popstate",y="hashchange";function b(){try{return window.history.state||{}}catch(e){return{}}}function w(e){void 0===e&&(e={}),m||(0,s.Z)(!1);var t,n=window.history,a=(-1===(t=window.navigator.userAgent).indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone"))&&window.history&&"pushState"in window.history,i=!(-1===window.navigator.userAgent.indexOf("Trident")),o=e,c=o.forceRefresh,w=void 0!==c&&c,k=o.getUserConfirmation,x=void 0===k?g:k,S=o.keyLength,_=void 0===S?6:S,E=e.basename?d(l(e.basename)):"";function C(e){var t=e||{},n=t.key,r=t.state,a=window.location,i=a.pathname+a.search+a.hash;return E&&(i=u(i,E)),f(i,r,n)}function T(){return Math.random().toString(36).substr(2,_)}var j=h();function N(e){(0,r.Z)($,e),$.length=n.length,j.notifyListeners($.location,$.action)}function L(e){(function(e){return void 0===e.state&&-1===navigator.userAgent.indexOf("CriOS")})(e)||O(C(e.state))}function A(){O(C(b()))}var P=!1;function O(e){if(P)P=!1,N();else{j.confirmTransitionTo(e,"POP",x,(function(t){t?N({action:"POP",location:e}):function(e){var t=$.location,n=I.indexOf(t.key);-1===n&&(n=0);var r=I.indexOf(e.key);-1===r&&(r=0);var a=n-r;a&&(P=!0,D(a))}(e)}))}}var R=C(b()),I=[R.key];function F(e){return E+p(e)}function D(e){n.go(e)}var M=0;function z(e){1===(M+=e)&&1===e?(window.addEventListener(v,L),i&&window.addEventListener(y,A)):0===M&&(window.removeEventListener(v,L),i&&window.removeEventListener(y,A))}var B=!1;var $={length:n.length,action:"POP",location:R,createHref:F,push:function(e,t){var r="PUSH",i=f(e,t,T(),$.location);j.confirmTransitionTo(i,r,x,(function(e){if(e){var t=F(i),o=i.key,s=i.state;if(a)if(n.pushState({key:o,state:s},null,t),w)window.location.href=t;else{var l=I.indexOf($.location.key),c=I.slice(0,l+1);c.push(i.key),I=c,N({action:r,location:i})}else window.location.href=t}}))},replace:function(e,t){var r="REPLACE",i=f(e,t,T(),$.location);j.confirmTransitionTo(i,r,x,(function(e){if(e){var t=F(i),o=i.key,s=i.state;if(a)if(n.replaceState({key:o,state:s},null,t),w)window.location.replace(t);else{var l=I.indexOf($.location.key);-1!==l&&(I[l]=i.key),N({action:r,location:i})}else window.location.replace(t)}}))},go:D,goBack:function(){D(-1)},goForward:function(){D(1)},block:function(e){void 0===e&&(e=!1);var t=j.setPrompt(e);return B||(z(1),B=!0),function(){return B&&(B=!1,z(-1)),t()}},listen:function(e){var t=j.appendListener(e);return z(1),function(){z(-1),t()}}};return $}var k="hashchange",x={hashbang:{encodePath:function(e){return"!"===e.charAt(0)?e:"!/"+c(e)},decodePath:function(e){return"!"===e.charAt(0)?e.substr(1):e}},noslash:{encodePath:c,decodePath:l},slash:{encodePath:l,decodePath:l}};function S(e){var t=e.indexOf("#");return-1===t?e:e.slice(0,t)}function _(){var e=window.location.href,t=e.indexOf("#");return-1===t?"":e.substring(t+1)}function E(e){window.location.replace(S(window.location.href)+"#"+e)}function C(e){void 0===e&&(e={}),m||(0,s.Z)(!1);var t=window.history,n=(window.navigator.userAgent.indexOf("Firefox"),e),a=n.getUserConfirmation,i=void 0===a?g:a,o=n.hashType,c=void 0===o?"slash":o,v=e.basename?d(l(e.basename)):"",y=x[c],b=y.encodePath,w=y.decodePath;function C(){var e=w(_());return v&&(e=u(e,v)),f(e)}var T=h();function j(e){(0,r.Z)(B,e),B.length=t.length,T.notifyListeners(B.location,B.action)}var N=!1,L=null;function A(){var e,t,n=_(),r=b(n);if(n!==r)E(r);else{var a=C(),o=B.location;if(!N&&(t=a,(e=o).pathname===t.pathname&&e.search===t.search&&e.hash===t.hash))return;if(L===p(a))return;L=null,function(e){if(N)N=!1,j();else{var t="POP";T.confirmTransitionTo(e,t,i,(function(n){n?j({action:t,location:e}):function(e){var t=B.location,n=I.lastIndexOf(p(t));-1===n&&(n=0);var r=I.lastIndexOf(p(e));-1===r&&(r=0);var a=n-r;a&&(N=!0,F(a))}(e)}))}}(a)}}var P=_(),O=b(P);P!==O&&E(O);var R=C(),I=[p(R)];function F(e){t.go(e)}var D=0;function M(e){1===(D+=e)&&1===e?window.addEventListener(k,A):0===D&&window.removeEventListener(k,A)}var z=!1;var B={length:t.length,action:"POP",location:R,createHref:function(e){var t=document.querySelector("base"),n="";return t&&t.getAttribute("href")&&(n=S(window.location.href)),n+"#"+b(v+p(e))},push:function(e,t){var n="PUSH",r=f(e,void 0,void 0,B.location);T.confirmTransitionTo(r,n,i,(function(e){if(e){var t=p(r),a=b(v+t);if(_()!==a){L=t,function(e){window.location.hash=e}(a);var i=I.lastIndexOf(p(B.location)),o=I.slice(0,i+1);o.push(t),I=o,j({action:n,location:r})}else j()}}))},replace:function(e,t){var n="REPLACE",r=f(e,void 0,void 0,B.location);T.confirmTransitionTo(r,n,i,(function(e){if(e){var t=p(r),a=b(v+t);_()!==a&&(L=t,E(a));var i=I.indexOf(p(B.location));-1!==i&&(I[i]=t),j({action:n,location:r})}}))},go:F,goBack:function(){F(-1)},goForward:function(){F(1)},block:function(e){void 0===e&&(e=!1);var t=T.setPrompt(e);return z||(M(1),z=!0),function(){return z&&(z=!1,M(-1)),t()}},listen:function(e){var t=T.appendListener(e);return M(1),function(){M(-1),t()}}};return B}function T(e,t,n){return Math.min(Math.max(e,t),n)}function j(e){void 0===e&&(e={});var t=e,n=t.getUserConfirmation,a=t.initialEntries,i=void 0===a?["/"]:a,o=t.initialIndex,s=void 0===o?0:o,l=t.keyLength,c=void 0===l?6:l,u=h();function d(e){(0,r.Z)(w,e),w.length=w.entries.length,u.notifyListeners(w.location,w.action)}function m(){return Math.random().toString(36).substr(2,c)}var g=T(s,0,i.length-1),v=i.map((function(e){return f(e,void 0,"string"==typeof e?m():e.key||m())})),y=p;function b(e){var t=T(w.index+e,0,w.entries.length-1),r=w.entries[t];u.confirmTransitionTo(r,"POP",n,(function(e){e?d({action:"POP",location:r,index:t}):d()}))}var w={length:v.length,action:"POP",location:v[g],index:g,entries:v,createHref:y,push:function(e,t){var r="PUSH",a=f(e,t,m(),w.location);u.confirmTransitionTo(a,r,n,(function(e){if(e){var t=w.index+1,n=w.entries.slice(0);n.length>t?n.splice(t,n.length-t,a):n.push(a),d({action:r,location:a,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",a=f(e,t,m(),w.location);u.confirmTransitionTo(a,r,n,(function(e){e&&(w.entries[w.index]=a,d({action:r,location:a}))}))},go:b,goBack:function(){b(-1)},goForward:function(){b(1)},canGo:function(e){var t=w.index+e;return t>=0&&t<w.entries.length},block:function(e){return void 0===e&&(e=!1),u.setPrompt(e)},listen:function(e){return u.appendListener(e)}};return w}},8679:(e,t,n)=>{"use strict";var r=n(9864),a={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},i={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},o={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},s={};function l(e){return r.isMemo(e)?o:s[e.$$typeof]||a}s[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},s[r.Memo]=o;var c=Object.defineProperty,u=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,p=Object.getOwnPropertyDescriptor,f=Object.getPrototypeOf,h=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(h){var a=f(n);a&&a!==h&&e(t,a,r)}var o=u(n);d&&(o=o.concat(d(n)));for(var s=l(t),m=l(n),g=0;g<o.length;++g){var v=o[g];if(!(i[v]||r&&r[v]||m&&m[v]||s&&s[v])){var y=p(n,v);try{c(t,v,y)}catch(b){}}}}return t}},1143:e=>{"use strict";e.exports=function(e,t,n,r,a,i,o,s){if(!e){var l;if(void 0===t)l=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[n,r,a,i,o,s],u=0;(l=new Error(t.replace(/%s/g,(function(){return c[u++]})))).name="Invariant Violation"}throw l.framesToPop=1,l}}},5826:e=>{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},2497:(e,t,n)=>{"use strict";n.r(t)},2295:(e,t,n)=>{"use strict";n.r(t)},4865:function(e,t,n){var r,a;r=function(){var e,t,n={version:"0.2.0"},r=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'};function a(e,t,n){return e<t?t:e>n?n:e}function i(e){return 100*(-1+e)}function o(e,t,n){var a;return(a="translate3d"===r.positionUsing?{transform:"translate3d("+i(e)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+i(e)+"%,0)"}:{"margin-left":i(e)+"%"}).transition="all "+t+"ms "+n,a}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(r[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=a(e,r.minimum,1),n.status=1===e?null:e;var i=n.render(!t),c=i.querySelector(r.barSelector),u=r.speed,d=r.easing;return i.offsetWidth,s((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),l(c,o(e,u,d)),1===e?(l(i,{transition:"none",opacity:1}),i.offsetWidth,setTimeout((function(){l(i,{transition:"all "+u+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),u)}),u)):setTimeout(t,u)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*a(Math.random()*t,.1,.95)),t=a(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},e=0,t=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===t&&n.start(),e++,t++,r.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");u(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=r.template;var a,o=t.querySelector(r.barSelector),s=e?"-100":i(n.status||0),c=document.querySelector(r.parent);return l(o,{transition:"all 0 linear",transform:"translate3d("+s+"%,0,0)"}),r.showSpinner||(a=t.querySelector(r.spinnerSelector))&&f(a),c!=document.body&&u(c,"nprogress-custom-parent"),c.appendChild(t),t},n.remove=function(){d(document.documentElement,"nprogress-busy"),d(document.querySelector(r.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&f(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var s=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),l=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()}))}function r(t){var n=document.body.style;if(t in n)return t;for(var r,a=e.length,i=t.charAt(0).toUpperCase()+t.slice(1);a--;)if((r=e[a]+i)in n)return r;return t}function a(e){return e=n(e),t[e]||(t[e]=r(e))}function i(e,t,n){t=a(t),e.style[t]=n}return function(e,t){var n,r,a=arguments;if(2==a.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&i(e,n,r);else i(e,a[1],a[2])}}();function c(e,t){return("string"==typeof e?e:p(e)).indexOf(" "+t+" ")>=0}function u(e,t){var n=p(e),r=n+t;c(n,t)||(e.className=r.substring(1))}function d(e,t){var n,r=p(e);c(e,t)&&(n=r.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function p(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function f(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(a="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=a)},4779:(e,t,n)=>{var r=n(5826);e.exports=f,e.exports.parse=i,e.exports.compile=function(e,t){return s(i(e,t),t)},e.exports.tokensToFunction=s,e.exports.tokensToRegExp=p;var a=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");function i(e,t){for(var n,r=[],i=0,o=0,s="",u=t&&t.delimiter||"/";null!=(n=a.exec(e));){var d=n[0],p=n[1],f=n.index;if(s+=e.slice(o,f),o=f+d.length,p)s+=p[1];else{var h=e[o],m=n[2],g=n[3],v=n[4],y=n[5],b=n[6],w=n[7];s&&(r.push(s),s="");var k=null!=m&&null!=h&&h!==m,x="+"===b||"*"===b,S="?"===b||"*"===b,_=n[2]||u,E=v||y;r.push({name:g||i++,prefix:m||"",delimiter:_,optional:S,repeat:x,partial:k,asterisk:!!w,pattern:E?c(E):w?".*":"[^"+l(_)+"]+?"})}}return o<e.length&&(s+=e.substr(o)),s&&r.push(s),r}function o(e){return encodeURI(e).replace(/[\/?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}function s(e,t){for(var n=new Array(e.length),a=0;a<e.length;a++)"object"==typeof e[a]&&(n[a]=new RegExp("^(?:"+e[a].pattern+")$",d(t)));return function(t,a){for(var i="",s=t||{},l=(a||{}).pretty?o:encodeURIComponent,c=0;c<e.length;c++){var u=e[c];if("string"!=typeof u){var d,p=s[u.name];if(null==p){if(u.optional){u.partial&&(i+=u.prefix);continue}throw new TypeError('Expected "'+u.name+'" to be defined')}if(r(p)){if(!u.repeat)throw new TypeError('Expected "'+u.name+'" to not repeat, but received `'+JSON.stringify(p)+"`");if(0===p.length){if(u.optional)continue;throw new TypeError('Expected "'+u.name+'" to not be empty')}for(var f=0;f<p.length;f++){if(d=l(p[f]),!n[c].test(d))throw new TypeError('Expected all "'+u.name+'" to match "'+u.pattern+'", but received `'+JSON.stringify(d)+"`");i+=(0===f?u.prefix:u.delimiter)+d}}else{if(d=u.asterisk?encodeURI(p).replace(/[?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()})):l(p),!n[c].test(d))throw new TypeError('Expected "'+u.name+'" to match "'+u.pattern+'", but received "'+d+'"');i+=u.prefix+d}}else i+=u}return i}}function l(e){return e.replace(/([.+*?=^!:${}()[\]|\/\\])/g,"\\$1")}function c(e){return e.replace(/([=!:$\/()])/g,"\\$1")}function u(e,t){return e.keys=t,e}function d(e){return e&&e.sensitive?"":"i"}function p(e,t,n){r(t)||(n=t||n,t=[]);for(var a=(n=n||{}).strict,i=!1!==n.end,o="",s=0;s<e.length;s++){var c=e[s];if("string"==typeof c)o+=l(c);else{var p=l(c.prefix),f="(?:"+c.pattern+")";t.push(c),c.repeat&&(f+="(?:"+p+f+")*"),o+=f=c.optional?c.partial?p+"("+f+")?":"(?:"+p+"("+f+"))?":p+"("+f+")"}}var h=l(n.delimiter||"/"),m=o.slice(-h.length)===h;return a||(o=(m?o.slice(0,-h.length):o)+"(?:"+h+"(?=$))?"),o+=i?"$":a&&m?"":"(?="+h+"|$)",u(new RegExp("^"+o,d(n)),t)}function f(e,t,n){return r(t)||(n=t||n,t=[]),n=n||{},e instanceof RegExp?function(e,t){var n=e.source.match(/\((?!\?)/g);if(n)for(var r=0;r<n.length;r++)t.push({name:r,prefix:null,delimiter:null,optional:!1,repeat:!1,partial:!1,asterisk:!1,pattern:null});return u(e,t)}(e,t):r(e)?function(e,t,n){for(var r=[],a=0;a<e.length;a++)r.push(f(e[a],t,n).source);return u(new RegExp("(?:"+r.join("|")+")",d(n)),t)}(e,t,n):function(e,t,n){return p(i(e,n),t,n)}(e,t,n)}},728:()=>{!function(e){e.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d.*$/m]};var t={"deleted-sign":"-","deleted-arrow":"<","inserted-sign":"+","inserted-arrow":">",unchanged:" ",diff:"!"};Object.keys(t).forEach((function(n){var r=t[n],a=[];/^\w+$/.test(n)||a.push(/\w+/.exec(n)[0]),"diff"===n&&a.push("bold"),e.languages.diff[n]={pattern:RegExp("^(?:["+r+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:a,inside:{line:{pattern:/(.)(?=[\s\S]).*(?:\r\n?|\n)?/,lookbehind:!0},prefix:{pattern:/[\s\S]/,alias:/\w+/.exec(n)[0]}}}})),Object.defineProperty(e.languages.diff,"PREFIXES",{value:t})}(Prism)},7346:()=>{Prism.languages["go-mod"]=Prism.languages["go-module"]={comment:{pattern:/\/\/.*/,greedy:!0},version:{pattern:/(^|[\s()[\],])v\d+\.\d+\.\d+(?:[+-][-+.\w]*)?(?![^\s()[\],])/,lookbehind:!0,alias:"number"},"go-version":{pattern:/((?:^|\s)go\s+)\d+(?:\.\d+){1,2}/,lookbehind:!0,alias:"number"},keyword:{pattern:/^([ \t]*)(?:exclude|go|module|replace|require|retract)\b/m,lookbehind:!0},operator:/=>/,punctuation:/[()[\],]/}},7046:()=>{Prism.languages.go=Prism.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),Prism.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete Prism.languages.go["class-name"]},6854:()=>{!function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,a,i){if(n.language===r){var o=n.tokenStack=[];n.code=n.code.replace(a,(function(e){if("function"==typeof i&&!i(e))return e;for(var a,s=o.length;-1!==n.code.indexOf(a=t(r,s));)++s;return o[s]=e,a})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var a=0,i=Object.keys(n.tokenStack);!function o(s){for(var l=0;l<s.length&&!(a>=i.length);l++){var c=s[l];if("string"==typeof c||c.content&&"string"==typeof c.content){var u=i[a],d=n.tokenStack[u],p="string"==typeof c?c:c.content,f=t(r,u),h=p.indexOf(f);if(h>-1){++a;var m=p.substring(0,h),g=new e.Token(r,e.tokenize(d,n.grammar),"language-"+r,d),v=p.substring(h+f.length),y=[];m&&y.push.apply(y,o([m])),y.push(g),v&&y.push.apply(y,o([v])),"string"==typeof c?s.splice.apply(s,[l,1].concat(y)):c.content=y}}else c.content&&o(c.content)}return s}(n.tokens)}}}})}(Prism)},7345:()=>{!function(e){var t=/\b(?:bool|bytes|double|s?fixed(?:32|64)|float|[su]?int(?:32|64)|string)\b/;e.languages.protobuf=e.languages.extend("clike",{"class-name":[{pattern:/(\b(?:enum|extend|message|service)\s+)[A-Za-z_]\w*(?=\s*\{)/,lookbehind:!0},{pattern:/(\b(?:rpc\s+\w+|returns)\s*\(\s*(?:stream\s+)?)\.?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*(?=\s*\))/,lookbehind:!0}],keyword:/\b(?:enum|extend|extensions|import|message|oneof|option|optional|package|public|repeated|required|reserved|returns|rpc(?=\s+\w)|service|stream|syntax|to)\b(?!\s*=\s*\d)/,function:/\b[a-z_]\w*(?=\s*\()/i}),e.languages.insertBefore("protobuf","operator",{map:{pattern:/\bmap<\s*[\w.]+\s*,\s*[\w.]+\s*>(?=\s+[a-z_]\w*\s*[=;])/i,alias:"class-name",inside:{punctuation:/[<>.,]/,builtin:t}},builtin:t,"positional-class-name":{pattern:/(?:\b|\B\.)[a-z_]\w*(?:\.[a-z_]\w*)*(?=\s+[a-z_]\w*\s*[=;])/i,alias:"class-name",inside:{punctuation:/\./}},annotation:{pattern:/(\[\s*)[a-z_]\w*(?=\s*=)/i,lookbehind:!0}})}(Prism)},7244:(e,t,n)=>{var r={"./prism-diff":728,"./prism-go":7046,"./prism-go-module":7346,"./prism-protobuf":7345};function a(e){var t=i(e);return n(t)}function i(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=i,e.exports=a,a.id=7244},2703:(e,t,n)=>{"use strict";var r=n(414);function a(){}function i(){}i.resetWarningCache=a,e.exports=function(){function e(e,t,n,a,i,o){if(o!==r){var s=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw s.name="Invariant Violation",s}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:i,resetWarningCache:a};return n.PropTypes=n,n}},5697:(e,t,n)=>{e.exports=n(2703)()},414:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},4448:(e,t,n)=>{"use strict";var r=n(7294),a=n(3840);function i(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var o=new Set,s={};function l(e,t){c(e,t),c(e+"Capture",t)}function c(e,t){for(s[e]=t,e=0;e<t.length;e++)o.add(t[e])}var u=!("undefined"==typeof window||void 0===window.document||void 0===window.document.createElement),d=Object.prototype.hasOwnProperty,p=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,f={},h={};function m(e,t,n,r,a,i,o){this.acceptsBooleans=2===t||3===t||4===t,this.attributeName=r,this.attributeNamespace=a,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=o}var g={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach((function(e){g[e]=new m(e,0,!1,e,null,!1,!1)})),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach((function(e){var t=e[0];g[t]=new m(t,1,!1,e[1],null,!1,!1)})),["contentEditable","draggable","spellCheck","value"].forEach((function(e){g[e]=new m(e,2,!1,e.toLowerCase(),null,!1,!1)})),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach((function(e){g[e]=new m(e,2,!1,e,null,!1,!1)})),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach((function(e){g[e]=new m(e,3,!1,e.toLowerCase(),null,!1,!1)})),["checked","multiple","muted","selected"].forEach((function(e){g[e]=new m(e,3,!0,e,null,!1,!1)})),["capture","download"].forEach((function(e){g[e]=new m(e,4,!1,e,null,!1,!1)})),["cols","rows","size","span"].forEach((function(e){g[e]=new m(e,6,!1,e,null,!1,!1)})),["rowSpan","start"].forEach((function(e){g[e]=new m(e,5,!1,e.toLowerCase(),null,!1,!1)}));var v=/[\-:]([a-z])/g;function y(e){return e[1].toUpperCase()}function b(e,t,n,r){var a=g.hasOwnProperty(t)?g[t]:null;(null!==a?0!==a.type:r||!(2<t.length)||"o"!==t[0]&&"O"!==t[0]||"n"!==t[1]&&"N"!==t[1])&&(function(e,t,n,r){if(null==t||function(e,t,n,r){if(null!==n&&0===n.type)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return!r&&(null!==n?!n.acceptsBooleans:"data-"!==(e=e.toLowerCase().slice(0,5))&&"aria-"!==e);default:return!1}}(e,t,n,r))return!0;if(r)return!1;if(null!==n)switch(n.type){case 3:return!t;case 4:return!1===t;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}(t,n,a,r)&&(n=null),r||null===a?function(e){return!!d.call(h,e)||!d.call(f,e)&&(p.test(e)?h[e]=!0:(f[e]=!0,!1))}(t)&&(null===n?e.removeAttribute(t):e.setAttribute(t,""+n)):a.mustUseProperty?e[a.propertyName]=null===n?3!==a.type&&"":n:(t=a.attributeName,r=a.attributeNamespace,null===n?e.removeAttribute(t):(n=3===(a=a.type)||4===a&&!0===n?"":""+n,r?e.setAttributeNS(r,t,n):e.setAttribute(t,n))))}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach((function(e){var t=e.replace(v,y);g[t]=new m(t,1,!1,e,null,!1,!1)})),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach((function(e){var t=e.replace(v,y);g[t]=new m(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)})),["xml:base","xml:lang","xml:space"].forEach((function(e){var t=e.replace(v,y);g[t]=new m(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)})),["tabIndex","crossOrigin"].forEach((function(e){g[e]=new m(e,1,!1,e.toLowerCase(),null,!1,!1)})),g.xlinkHref=new m("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach((function(e){g[e]=new m(e,1,!1,e.toLowerCase(),null,!0,!0)}));var w=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,k=Symbol.for("react.element"),x=Symbol.for("react.portal"),S=Symbol.for("react.fragment"),_=Symbol.for("react.strict_mode"),E=Symbol.for("react.profiler"),C=Symbol.for("react.provider"),T=Symbol.for("react.context"),j=Symbol.for("react.forward_ref"),N=Symbol.for("react.suspense"),L=Symbol.for("react.suspense_list"),A=Symbol.for("react.memo"),P=Symbol.for("react.lazy");Symbol.for("react.scope"),Symbol.for("react.debug_trace_mode");var O=Symbol.for("react.offscreen");Symbol.for("react.legacy_hidden"),Symbol.for("react.cache"),Symbol.for("react.tracing_marker");var R=Symbol.iterator;function I(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=R&&e[R]||e["@@iterator"])?e:null}var F,D=Object.assign;function M(e){if(void 0===F)try{throw Error()}catch(n){var t=n.stack.trim().match(/\n( *(at )?)/);F=t&&t[1]||""}return"\n"+F+e}var z=!1;function B(e,t){if(!e||z)return"";z=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(t)if(t=function(){throw Error()},Object.defineProperty(t.prototype,"props",{set:function(){throw Error()}}),"object"==typeof Reflect&&Reflect.construct){try{Reflect.construct(t,[])}catch(c){var r=c}Reflect.construct(e,[],t)}else{try{t.call()}catch(c){r=c}e.call(t.prototype)}else{try{throw Error()}catch(c){r=c}e()}}catch(c){if(c&&r&&"string"==typeof c.stack){for(var a=c.stack.split("\n"),i=r.stack.split("\n"),o=a.length-1,s=i.length-1;1<=o&&0<=s&&a[o]!==i[s];)s--;for(;1<=o&&0<=s;o--,s--)if(a[o]!==i[s]){if(1!==o||1!==s)do{if(o--,0>--s||a[o]!==i[s]){var l="\n"+a[o].replace(" at new "," at ");return e.displayName&&l.includes("<anonymous>")&&(l=l.replace("<anonymous>",e.displayName)),l}}while(1<=o&&0<=s);break}}}finally{z=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?M(e):""}function $(e){switch(e.tag){case 5:return M(e.type);case 16:return M("Lazy");case 13:return M("Suspense");case 19:return M("SuspenseList");case 0:case 2:case 15:return e=B(e.type,!1);case 11:return e=B(e.type.render,!1);case 1:return e=B(e.type,!0);default:return""}}function U(e){if(null==e)return null;if("function"==typeof e)return e.displayName||e.name||null;if("string"==typeof e)return e;switch(e){case S:return"Fragment";case x:return"Portal";case E:return"Profiler";case _:return"StrictMode";case N:return"Suspense";case L:return"SuspenseList"}if("object"==typeof e)switch(e.$$typeof){case T:return(e.displayName||"Context")+".Consumer";case C:return(e._context.displayName||"Context")+".Provider";case j:var t=e.render;return(e=e.displayName)||(e=""!==(e=t.displayName||t.name||"")?"ForwardRef("+e+")":"ForwardRef"),e;case A:return null!==(t=e.displayName||null)?t:U(e.type)||"Memo";case P:t=e._payload,e=e._init;try{return U(e(t))}catch(n){}}return null}function Z(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=(e=t.render).displayName||e.name||"",t.displayName||(""!==e?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return U(t);case 8:return t===_?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if("function"==typeof t)return t.displayName||t.name||null;if("string"==typeof t)return t}return null}function H(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":case"object":return e;default:return""}}function q(e){var t=e.type;return(e=e.nodeName)&&"input"===e.toLowerCase()&&("checkbox"===t||"radio"===t)}function V(e){e._valueTracker||(e._valueTracker=function(e){var t=q(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&void 0!==n&&"function"==typeof n.get&&"function"==typeof n.set){var a=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return a.call(this)},set:function(e){r=""+e,i.call(this,e)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(e){r=""+e},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}(e))}function W(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=q(e)?e.checked?"true":"false":e.value),(e=r)!==n&&(t.setValue(e),!0)}function G(e){if(void 0===(e=e||("undefined"!=typeof document?document:void 0)))return null;try{return e.activeElement||e.body}catch(t){return e.body}}function Y(e,t){var n=t.checked;return D({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:null!=n?n:e._wrapperState.initialChecked})}function Q(e,t){var n=null==t.defaultValue?"":t.defaultValue,r=null!=t.checked?t.checked:t.defaultChecked;n=H(null!=t.value?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:"checkbox"===t.type||"radio"===t.type?null!=t.checked:null!=t.value}}function K(e,t){null!=(t=t.checked)&&b(e,"checked",t,!1)}function X(e,t){K(e,t);var n=H(t.value),r=t.type;if(null!=n)"number"===r?(0===n&&""===e.value||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if("submit"===r||"reset"===r)return void e.removeAttribute("value");t.hasOwnProperty("value")?ee(e,t.type,n):t.hasOwnProperty("defaultValue")&&ee(e,t.type,H(t.defaultValue)),null==t.checked&&null!=t.defaultChecked&&(e.defaultChecked=!!t.defaultChecked)}function J(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!("submit"!==r&&"reset"!==r||void 0!==t.value&&null!==t.value))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}""!==(n=e.name)&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,""!==n&&(e.name=n)}function ee(e,t,n){"number"===t&&G(e.ownerDocument)===e||(null==n?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var te=Array.isArray;function ne(e,t,n,r){if(e=e.options,t){t={};for(var a=0;a<n.length;a++)t["$"+n[a]]=!0;for(n=0;n<e.length;n++)a=t.hasOwnProperty("$"+e[n].value),e[n].selected!==a&&(e[n].selected=a),a&&r&&(e[n].defaultSelected=!0)}else{for(n=""+H(n),t=null,a=0;a<e.length;a++){if(e[a].value===n)return e[a].selected=!0,void(r&&(e[a].defaultSelected=!0));null!==t||e[a].disabled||(t=e[a])}null!==t&&(t.selected=!0)}}function re(e,t){if(null!=t.dangerouslySetInnerHTML)throw Error(i(91));return D({},t,{value:void 0,defaultValue:void 0,children:""+e._wrapperState.initialValue})}function ae(e,t){var n=t.value;if(null==n){if(n=t.children,t=t.defaultValue,null!=n){if(null!=t)throw Error(i(92));if(te(n)){if(1<n.length)throw Error(i(93));n=n[0]}t=n}null==t&&(t=""),n=t}e._wrapperState={initialValue:H(n)}}function ie(e,t){var n=H(t.value),r=H(t.defaultValue);null!=n&&((n=""+n)!==e.value&&(e.value=n),null==t.defaultValue&&e.defaultValue!==n&&(e.defaultValue=n)),null!=r&&(e.defaultValue=""+r)}function oe(e){var t=e.textContent;t===e._wrapperState.initialValue&&""!==t&&null!==t&&(e.value=t)}function se(e){switch(e){case"svg":return"http://www.w3.org/2000/svg";case"math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function le(e,t){return null==e||"http://www.w3.org/1999/xhtml"===e?se(t):"http://www.w3.org/2000/svg"===e&&"foreignObject"===t?"http://www.w3.org/1999/xhtml":e}var ce,ue,de=(ue=function(e,t){if("http://www.w3.org/2000/svg"!==e.namespaceURI||"innerHTML"in e)e.innerHTML=t;else{for((ce=ce||document.createElement("div")).innerHTML="<svg>"+t.valueOf().toString()+"</svg>",t=ce.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}},"undefined"!=typeof MSApp&&MSApp.execUnsafeLocalFunction?function(e,t,n,r){MSApp.execUnsafeLocalFunction((function(){return ue(e,t)}))}:ue);function pe(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&3===n.nodeType)return void(n.nodeValue=t)}e.textContent=t}var fe={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},he=["Webkit","ms","Moz","O"];function me(e,t,n){return null==t||"boolean"==typeof t||""===t?"":n||"number"!=typeof t||0===t||fe.hasOwnProperty(e)&&fe[e]?(""+t).trim():t+"px"}function ge(e,t){for(var n in e=e.style,t)if(t.hasOwnProperty(n)){var r=0===n.indexOf("--"),a=me(n,t[n],r);"float"===n&&(n="cssFloat"),r?e.setProperty(n,a):e[n]=a}}Object.keys(fe).forEach((function(e){he.forEach((function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),fe[t]=fe[e]}))}));var ve=D({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function ye(e,t){if(t){if(ve[e]&&(null!=t.children||null!=t.dangerouslySetInnerHTML))throw Error(i(137,e));if(null!=t.dangerouslySetInnerHTML){if(null!=t.children)throw Error(i(60));if("object"!=typeof t.dangerouslySetInnerHTML||!("__html"in t.dangerouslySetInnerHTML))throw Error(i(61))}if(null!=t.style&&"object"!=typeof t.style)throw Error(i(62))}}function be(e,t){if(-1===e.indexOf("-"))return"string"==typeof t.is;switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var we=null;function ke(e){return(e=e.target||e.srcElement||window).correspondingUseElement&&(e=e.correspondingUseElement),3===e.nodeType?e.parentNode:e}var xe=null,Se=null,_e=null;function Ee(e){if(e=ba(e)){if("function"!=typeof xe)throw Error(i(280));var t=e.stateNode;t&&(t=ka(t),xe(e.stateNode,e.type,t))}}function Ce(e){Se?_e?_e.push(e):_e=[e]:Se=e}function Te(){if(Se){var e=Se,t=_e;if(_e=Se=null,Ee(e),t)for(e=0;e<t.length;e++)Ee(t[e])}}function je(e,t){return e(t)}function Ne(){}var Le=!1;function Ae(e,t,n){if(Le)return e(t,n);Le=!0;try{return je(e,t,n)}finally{Le=!1,(null!==Se||null!==_e)&&(Ne(),Te())}}function Pe(e,t){var n=e.stateNode;if(null===n)return null;var r=ka(n);if(null===r)return null;n=r[t];e:switch(t){case"onClick":case"onClickCapture":case"onDoubleClick":case"onDoubleClickCapture":case"onMouseDown":case"onMouseDownCapture":case"onMouseMove":case"onMouseMoveCapture":case"onMouseUp":case"onMouseUpCapture":case"onMouseEnter":(r=!r.disabled)||(r=!("button"===(e=e.type)||"input"===e||"select"===e||"textarea"===e)),e=!r;break e;default:e=!1}if(e)return null;if(n&&"function"!=typeof n)throw Error(i(231,t,typeof n));return n}var Oe=!1;if(u)try{var Re={};Object.defineProperty(Re,"passive",{get:function(){Oe=!0}}),window.addEventListener("test",Re,Re),window.removeEventListener("test",Re,Re)}catch(ue){Oe=!1}function Ie(e,t,n,r,a,i,o,s,l){var c=Array.prototype.slice.call(arguments,3);try{t.apply(n,c)}catch(u){this.onError(u)}}var Fe=!1,De=null,Me=!1,ze=null,Be={onError:function(e){Fe=!0,De=e}};function $e(e,t,n,r,a,i,o,s,l){Fe=!1,De=null,Ie.apply(Be,arguments)}function Ue(e){var t=e,n=e;if(e.alternate)for(;t.return;)t=t.return;else{e=t;do{0!=(4098&(t=e).flags)&&(n=t.return),e=t.return}while(e)}return 3===t.tag?n:null}function Ze(e){if(13===e.tag){var t=e.memoizedState;if(null===t&&(null!==(e=e.alternate)&&(t=e.memoizedState)),null!==t)return t.dehydrated}return null}function He(e){if(Ue(e)!==e)throw Error(i(188))}function qe(e){return null!==(e=function(e){var t=e.alternate;if(!t){if(null===(t=Ue(e)))throw Error(i(188));return t!==e?null:e}for(var n=e,r=t;;){var a=n.return;if(null===a)break;var o=a.alternate;if(null===o){if(null!==(r=a.return)){n=r;continue}break}if(a.child===o.child){for(o=a.child;o;){if(o===n)return He(a),e;if(o===r)return He(a),t;o=o.sibling}throw Error(i(188))}if(n.return!==r.return)n=a,r=o;else{for(var s=!1,l=a.child;l;){if(l===n){s=!0,n=a,r=o;break}if(l===r){s=!0,r=a,n=o;break}l=l.sibling}if(!s){for(l=o.child;l;){if(l===n){s=!0,n=o,r=a;break}if(l===r){s=!0,r=o,n=a;break}l=l.sibling}if(!s)throw Error(i(189))}}if(n.alternate!==r)throw Error(i(190))}if(3!==n.tag)throw Error(i(188));return n.stateNode.current===n?e:t}(e))?Ve(e):null}function Ve(e){if(5===e.tag||6===e.tag)return e;for(e=e.child;null!==e;){var t=Ve(e);if(null!==t)return t;e=e.sibling}return null}var We=a.unstable_scheduleCallback,Ge=a.unstable_cancelCallback,Ye=a.unstable_shouldYield,Qe=a.unstable_requestPaint,Ke=a.unstable_now,Xe=a.unstable_getCurrentPriorityLevel,Je=a.unstable_ImmediatePriority,et=a.unstable_UserBlockingPriority,tt=a.unstable_NormalPriority,nt=a.unstable_LowPriority,rt=a.unstable_IdlePriority,at=null,it=null;var ot=Math.clz32?Math.clz32:function(e){return e>>>=0,0===e?32:31-(st(e)/lt|0)|0},st=Math.log,lt=Math.LN2;var ct=64,ut=4194304;function dt(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return 4194240&e;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return 130023424&e;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function pt(e,t){var n=e.pendingLanes;if(0===n)return 0;var r=0,a=e.suspendedLanes,i=e.pingedLanes,o=268435455&n;if(0!==o){var s=o&~a;0!==s?r=dt(s):0!==(i&=o)&&(r=dt(i))}else 0!==(o=n&~a)?r=dt(o):0!==i&&(r=dt(i));if(0===r)return 0;if(0!==t&&t!==r&&0==(t&a)&&((a=r&-r)>=(i=t&-t)||16===a&&0!=(4194240&i)))return t;if(0!=(4&r)&&(r|=16&n),0!==(t=e.entangledLanes))for(e=e.entanglements,t&=r;0<t;)a=1<<(n=31-ot(t)),r|=e[n],t&=~a;return r}function ft(e,t){switch(e){case 1:case 2:case 4:return t+250;case 8:case 16:case 32:case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;default:return-1}}function ht(e){return 0!==(e=-1073741825&e.pendingLanes)?e:1073741824&e?1073741824:0}function mt(){var e=ct;return 0==(4194240&(ct<<=1))&&(ct=64),e}function gt(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function vt(e,t,n){e.pendingLanes|=t,536870912!==t&&(e.suspendedLanes=0,e.pingedLanes=0),(e=e.eventTimes)[t=31-ot(t)]=n}function yt(e,t){var n=e.entangledLanes|=t;for(e=e.entanglements;n;){var r=31-ot(n),a=1<<r;a&t|e[r]&t&&(e[r]|=t),n&=~a}}var bt=0;function wt(e){return 1<(e&=-e)?4<e?0!=(268435455&e)?16:536870912:4:1}var kt,xt,St,_t,Et,Ct=!1,Tt=[],jt=null,Nt=null,Lt=null,At=new Map,Pt=new Map,Ot=[],Rt="mousedown mouseup touchcancel touchend touchstart auxclick dblclick pointercancel pointerdown pointerup dragend dragstart drop compositionend compositionstart keydown keypress keyup input textInput copy cut paste click change contextmenu reset submit".split(" ");function It(e,t){switch(e){case"focusin":case"focusout":jt=null;break;case"dragenter":case"dragleave":Nt=null;break;case"mouseover":case"mouseout":Lt=null;break;case"pointerover":case"pointerout":At.delete(t.pointerId);break;case"gotpointercapture":case"lostpointercapture":Pt.delete(t.pointerId)}}function Ft(e,t,n,r,a,i){return null===e||e.nativeEvent!==i?(e={blockedOn:t,domEventName:n,eventSystemFlags:r,nativeEvent:i,targetContainers:[a]},null!==t&&(null!==(t=ba(t))&&xt(t)),e):(e.eventSystemFlags|=r,t=e.targetContainers,null!==a&&-1===t.indexOf(a)&&t.push(a),e)}function Dt(e){var t=ya(e.target);if(null!==t){var n=Ue(t);if(null!==n)if(13===(t=n.tag)){if(null!==(t=Ze(n)))return e.blockedOn=t,void Et(e.priority,(function(){St(n)}))}else if(3===t&&n.stateNode.current.memoizedState.isDehydrated)return void(e.blockedOn=3===n.tag?n.stateNode.containerInfo:null)}e.blockedOn=null}function Mt(e){if(null!==e.blockedOn)return!1;for(var t=e.targetContainers;0<t.length;){var n=Yt(e.domEventName,e.eventSystemFlags,t[0],e.nativeEvent);if(null!==n)return null!==(t=ba(n))&&xt(t),e.blockedOn=n,!1;var r=new(n=e.nativeEvent).constructor(n.type,n);we=r,n.target.dispatchEvent(r),we=null,t.shift()}return!0}function zt(e,t,n){Mt(e)&&n.delete(t)}function Bt(){Ct=!1,null!==jt&&Mt(jt)&&(jt=null),null!==Nt&&Mt(Nt)&&(Nt=null),null!==Lt&&Mt(Lt)&&(Lt=null),At.forEach(zt),Pt.forEach(zt)}function $t(e,t){e.blockedOn===t&&(e.blockedOn=null,Ct||(Ct=!0,a.unstable_scheduleCallback(a.unstable_NormalPriority,Bt)))}function Ut(e){function t(t){return $t(t,e)}if(0<Tt.length){$t(Tt[0],e);for(var n=1;n<Tt.length;n++){var r=Tt[n];r.blockedOn===e&&(r.blockedOn=null)}}for(null!==jt&&$t(jt,e),null!==Nt&&$t(Nt,e),null!==Lt&&$t(Lt,e),At.forEach(t),Pt.forEach(t),n=0;n<Ot.length;n++)(r=Ot[n]).blockedOn===e&&(r.blockedOn=null);for(;0<Ot.length&&null===(n=Ot[0]).blockedOn;)Dt(n),null===n.blockedOn&&Ot.shift()}var Zt=w.ReactCurrentBatchConfig,Ht=!0;function qt(e,t,n,r){var a=bt,i=Zt.transition;Zt.transition=null;try{bt=1,Wt(e,t,n,r)}finally{bt=a,Zt.transition=i}}function Vt(e,t,n,r){var a=bt,i=Zt.transition;Zt.transition=null;try{bt=4,Wt(e,t,n,r)}finally{bt=a,Zt.transition=i}}function Wt(e,t,n,r){if(Ht){var a=Yt(e,t,n,r);if(null===a)Hr(e,t,r,Gt,n),It(e,r);else if(function(e,t,n,r,a){switch(t){case"focusin":return jt=Ft(jt,e,t,n,r,a),!0;case"dragenter":return Nt=Ft(Nt,e,t,n,r,a),!0;case"mouseover":return Lt=Ft(Lt,e,t,n,r,a),!0;case"pointerover":var i=a.pointerId;return At.set(i,Ft(At.get(i)||null,e,t,n,r,a)),!0;case"gotpointercapture":return i=a.pointerId,Pt.set(i,Ft(Pt.get(i)||null,e,t,n,r,a)),!0}return!1}(a,e,t,n,r))r.stopPropagation();else if(It(e,r),4&t&&-1<Rt.indexOf(e)){for(;null!==a;){var i=ba(a);if(null!==i&&kt(i),null===(i=Yt(e,t,n,r))&&Hr(e,t,r,Gt,n),i===a)break;a=i}null!==a&&r.stopPropagation()}else Hr(e,t,r,null,n)}}var Gt=null;function Yt(e,t,n,r){if(Gt=null,null!==(e=ya(e=ke(r))))if(null===(t=Ue(e)))e=null;else if(13===(n=t.tag)){if(null!==(e=Ze(t)))return e;e=null}else if(3===n){if(t.stateNode.current.memoizedState.isDehydrated)return 3===t.tag?t.stateNode.containerInfo:null;e=null}else t!==e&&(e=null);return Gt=e,null}function Qt(e){switch(e){case"cancel":case"click":case"close":case"contextmenu":case"copy":case"cut":case"auxclick":case"dblclick":case"dragend":case"dragstart":case"drop":case"focusin":case"focusout":case"input":case"invalid":case"keydown":case"keypress":case"keyup":case"mousedown":case"mouseup":case"paste":case"pause":case"play":case"pointercancel":case"pointerdown":case"pointerup":case"ratechange":case"reset":case"resize":case"seeked":case"submit":case"touchcancel":case"touchend":case"touchstart":case"volumechange":case"change":case"selectionchange":case"textInput":case"compositionstart":case"compositionend":case"compositionupdate":case"beforeblur":case"afterblur":case"beforeinput":case"blur":case"fullscreenchange":case"focus":case"hashchange":case"popstate":case"select":case"selectstart":return 1;case"drag":case"dragenter":case"dragexit":case"dragleave":case"dragover":case"mousemove":case"mouseout":case"mouseover":case"pointermove":case"pointerout":case"pointerover":case"scroll":case"toggle":case"touchmove":case"wheel":case"mouseenter":case"mouseleave":case"pointerenter":case"pointerleave":return 4;case"message":switch(Xe()){case Je:return 1;case et:return 4;case tt:case nt:return 16;case rt:return 536870912;default:return 16}default:return 16}}var Kt=null,Xt=null,Jt=null;function en(){if(Jt)return Jt;var e,t,n=Xt,r=n.length,a="value"in Kt?Kt.value:Kt.textContent,i=a.length;for(e=0;e<r&&n[e]===a[e];e++);var o=r-e;for(t=1;t<=o&&n[r-t]===a[i-t];t++);return Jt=a.slice(e,1<t?1-t:void 0)}function tn(e){var t=e.keyCode;return"charCode"in e?0===(e=e.charCode)&&13===t&&(e=13):e=t,10===e&&(e=13),32<=e||13===e?e:0}function nn(){return!0}function rn(){return!1}function an(e){function t(t,n,r,a,i){for(var o in this._reactName=t,this._targetInst=r,this.type=n,this.nativeEvent=a,this.target=i,this.currentTarget=null,e)e.hasOwnProperty(o)&&(t=e[o],this[o]=t?t(a):a[o]);return this.isDefaultPrevented=(null!=a.defaultPrevented?a.defaultPrevented:!1===a.returnValue)?nn:rn,this.isPropagationStopped=rn,this}return D(t.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=nn)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=nn)},persist:function(){},isPersistent:nn}),t}var on,sn,ln,cn={eventPhase:0,bubbles:0,cancelable:0,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:0,isTrusted:0},un=an(cn),dn=D({},cn,{view:0,detail:0}),pn=an(dn),fn=D({},dn,{screenX:0,screenY:0,clientX:0,clientY:0,pageX:0,pageY:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,getModifierState:En,button:0,buttons:0,relatedTarget:function(e){return void 0===e.relatedTarget?e.fromElement===e.srcElement?e.toElement:e.fromElement:e.relatedTarget},movementX:function(e){return"movementX"in e?e.movementX:(e!==ln&&(ln&&"mousemove"===e.type?(on=e.screenX-ln.screenX,sn=e.screenY-ln.screenY):sn=on=0,ln=e),on)},movementY:function(e){return"movementY"in e?e.movementY:sn}}),hn=an(fn),mn=an(D({},fn,{dataTransfer:0})),gn=an(D({},dn,{relatedTarget:0})),vn=an(D({},cn,{animationName:0,elapsedTime:0,pseudoElement:0})),yn=D({},cn,{clipboardData:function(e){return"clipboardData"in e?e.clipboardData:window.clipboardData}}),bn=an(yn),wn=an(D({},cn,{data:0})),kn={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},xn={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"},Sn={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"};function _n(e){var t=this.nativeEvent;return t.getModifierState?t.getModifierState(e):!!(e=Sn[e])&&!!t[e]}function En(){return _n}var Cn=D({},dn,{key:function(e){if(e.key){var t=kn[e.key]||e.key;if("Unidentified"!==t)return t}return"keypress"===e.type?13===(e=tn(e))?"Enter":String.fromCharCode(e):"keydown"===e.type||"keyup"===e.type?xn[e.keyCode]||"Unidentified":""},code:0,location:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,repeat:0,locale:0,getModifierState:En,charCode:function(e){return"keypress"===e.type?tn(e):0},keyCode:function(e){return"keydown"===e.type||"keyup"===e.type?e.keyCode:0},which:function(e){return"keypress"===e.type?tn(e):"keydown"===e.type||"keyup"===e.type?e.keyCode:0}}),Tn=an(Cn),jn=an(D({},fn,{pointerId:0,width:0,height:0,pressure:0,tangentialPressure:0,tiltX:0,tiltY:0,twist:0,pointerType:0,isPrimary:0})),Nn=an(D({},dn,{touches:0,targetTouches:0,changedTouches:0,altKey:0,metaKey:0,ctrlKey:0,shiftKey:0,getModifierState:En})),Ln=an(D({},cn,{propertyName:0,elapsedTime:0,pseudoElement:0})),An=D({},fn,{deltaX:function(e){return"deltaX"in e?e.deltaX:"wheelDeltaX"in e?-e.wheelDeltaX:0},deltaY:function(e){return"deltaY"in e?e.deltaY:"wheelDeltaY"in e?-e.wheelDeltaY:"wheelDelta"in e?-e.wheelDelta:0},deltaZ:0,deltaMode:0}),Pn=an(An),On=[9,13,27,32],Rn=u&&"CompositionEvent"in window,In=null;u&&"documentMode"in document&&(In=document.documentMode);var Fn=u&&"TextEvent"in window&&!In,Dn=u&&(!Rn||In&&8<In&&11>=In),Mn=String.fromCharCode(32),zn=!1;function Bn(e,t){switch(e){case"keyup":return-1!==On.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function $n(e){return"object"==typeof(e=e.detail)&&"data"in e?e.data:null}var Un=!1;var Zn={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};function Hn(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return"input"===t?!!Zn[e.type]:"textarea"===t}function qn(e,t,n,r){Ce(r),0<(t=Vr(t,"onChange")).length&&(n=new un("onChange","change",null,n,r),e.push({event:n,listeners:t}))}var Vn=null,Wn=null;function Gn(e){Mr(e,0)}function Yn(e){if(W(wa(e)))return e}function Qn(e,t){if("change"===e)return t}var Kn=!1;if(u){var Xn;if(u){var Jn="oninput"in document;if(!Jn){var er=document.createElement("div");er.setAttribute("oninput","return;"),Jn="function"==typeof er.oninput}Xn=Jn}else Xn=!1;Kn=Xn&&(!document.documentMode||9<document.documentMode)}function tr(){Vn&&(Vn.detachEvent("onpropertychange",nr),Wn=Vn=null)}function nr(e){if("value"===e.propertyName&&Yn(Wn)){var t=[];qn(t,Wn,e,ke(e)),Ae(Gn,t)}}function rr(e,t,n){"focusin"===e?(tr(),Wn=n,(Vn=t).attachEvent("onpropertychange",nr)):"focusout"===e&&tr()}function ar(e){if("selectionchange"===e||"keyup"===e||"keydown"===e)return Yn(Wn)}function ir(e,t){if("click"===e)return Yn(t)}function or(e,t){if("input"===e||"change"===e)return Yn(t)}var sr="function"==typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t};function lr(e,t){if(sr(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(r=0;r<n.length;r++){var a=n[r];if(!d.call(t,a)||!sr(e[a],t[a]))return!1}return!0}function cr(e){for(;e&&e.firstChild;)e=e.firstChild;return e}function ur(e,t){var n,r=cr(e);for(e=0;r;){if(3===r.nodeType){if(n=e+r.textContent.length,e<=t&&n>=t)return{node:r,offset:t-e};e=n}e:{for(;r;){if(r.nextSibling){r=r.nextSibling;break e}r=r.parentNode}r=void 0}r=cr(r)}}function dr(e,t){return!(!e||!t)&&(e===t||(!e||3!==e.nodeType)&&(t&&3===t.nodeType?dr(e,t.parentNode):"contains"in e?e.contains(t):!!e.compareDocumentPosition&&!!(16&e.compareDocumentPosition(t))))}function pr(){for(var e=window,t=G();t instanceof e.HTMLIFrameElement;){try{var n="string"==typeof t.contentWindow.location.href}catch(r){n=!1}if(!n)break;t=G((e=t.contentWindow).document)}return t}function fr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&("text"===e.type||"search"===e.type||"tel"===e.type||"url"===e.type||"password"===e.type)||"textarea"===t||"true"===e.contentEditable)}function hr(e){var t=pr(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&dr(n.ownerDocument.documentElement,n)){if(null!==r&&fr(n))if(t=r.start,void 0===(e=r.end)&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if((e=(t=n.ownerDocument||document)&&t.defaultView||window).getSelection){e=e.getSelection();var a=n.textContent.length,i=Math.min(r.start,a);r=void 0===r.end?i:Math.min(r.end,a),!e.extend&&i>r&&(a=r,r=i,i=a),a=ur(n,i);var o=ur(n,r);a&&o&&(1!==e.rangeCount||e.anchorNode!==a.node||e.anchorOffset!==a.offset||e.focusNode!==o.node||e.focusOffset!==o.offset)&&((t=t.createRange()).setStart(a.node,a.offset),e.removeAllRanges(),i>r?(e.addRange(t),e.extend(o.node,o.offset)):(t.setEnd(o.node,o.offset),e.addRange(t)))}for(t=[],e=n;e=e.parentNode;)1===e.nodeType&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for("function"==typeof n.focus&&n.focus(),n=0;n<t.length;n++)(e=t[n]).element.scrollLeft=e.left,e.element.scrollTop=e.top}}var mr=u&&"documentMode"in document&&11>=document.documentMode,gr=null,vr=null,yr=null,br=!1;function wr(e,t,n){var r=n.window===n?n.document:9===n.nodeType?n:n.ownerDocument;br||null==gr||gr!==G(r)||("selectionStart"in(r=gr)&&fr(r)?r={start:r.selectionStart,end:r.selectionEnd}:r={anchorNode:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection()).anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset},yr&&lr(yr,r)||(yr=r,0<(r=Vr(vr,"onSelect")).length&&(t=new un("onSelect","select",null,t,n),e.push({event:t,listeners:r}),t.target=gr)))}function kr(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit"+e]="webkit"+t,n["Moz"+e]="moz"+t,n}var xr={animationend:kr("Animation","AnimationEnd"),animationiteration:kr("Animation","AnimationIteration"),animationstart:kr("Animation","AnimationStart"),transitionend:kr("Transition","TransitionEnd")},Sr={},_r={};function Er(e){if(Sr[e])return Sr[e];if(!xr[e])return e;var t,n=xr[e];for(t in n)if(n.hasOwnProperty(t)&&t in _r)return Sr[e]=n[t];return e}u&&(_r=document.createElement("div").style,"AnimationEvent"in window||(delete xr.animationend.animation,delete xr.animationiteration.animation,delete xr.animationstart.animation),"TransitionEvent"in window||delete xr.transitionend.transition);var Cr=Er("animationend"),Tr=Er("animationiteration"),jr=Er("animationstart"),Nr=Er("transitionend"),Lr=new Map,Ar="abort auxClick cancel canPlay canPlayThrough click close contextMenu copy cut drag dragEnd dragEnter dragExit dragLeave dragOver dragStart drop durationChange emptied encrypted ended error gotPointerCapture input invalid keyDown keyPress keyUp load loadedData loadedMetadata loadStart lostPointerCapture mouseDown mouseMove mouseOut mouseOver mouseUp paste pause play playing pointerCancel pointerDown pointerMove pointerOut pointerOver pointerUp progress rateChange reset resize seeked seeking stalled submit suspend timeUpdate touchCancel touchEnd touchStart volumeChange scroll toggle touchMove waiting wheel".split(" ");function Pr(e,t){Lr.set(e,t),l(t,[e])}for(var Or=0;Or<Ar.length;Or++){var Rr=Ar[Or];Pr(Rr.toLowerCase(),"on"+(Rr[0].toUpperCase()+Rr.slice(1)))}Pr(Cr,"onAnimationEnd"),Pr(Tr,"onAnimationIteration"),Pr(jr,"onAnimationStart"),Pr("dblclick","onDoubleClick"),Pr("focusin","onFocus"),Pr("focusout","onBlur"),Pr(Nr,"onTransitionEnd"),c("onMouseEnter",["mouseout","mouseover"]),c("onMouseLeave",["mouseout","mouseover"]),c("onPointerEnter",["pointerout","pointerover"]),c("onPointerLeave",["pointerout","pointerover"]),l("onChange","change click focusin focusout input keydown keyup selectionchange".split(" ")),l("onSelect","focusout contextmenu dragend focusin keydown keyup mousedown mouseup selectionchange".split(" ")),l("onBeforeInput",["compositionend","keypress","textInput","paste"]),l("onCompositionEnd","compositionend focusout keydown keypress keyup mousedown".split(" ")),l("onCompositionStart","compositionstart focusout keydown keypress keyup mousedown".split(" ")),l("onCompositionUpdate","compositionupdate focusout keydown keypress keyup mousedown".split(" "));var Ir="abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange resize seeked seeking stalled suspend timeupdate volumechange waiting".split(" "),Fr=new Set("cancel close invalid load scroll toggle".split(" ").concat(Ir));function Dr(e,t,n){var r=e.type||"unknown-event";e.currentTarget=n,function(e,t,n,r,a,o,s,l,c){if($e.apply(this,arguments),Fe){if(!Fe)throw Error(i(198));var u=De;Fe=!1,De=null,Me||(Me=!0,ze=u)}}(r,t,void 0,e),e.currentTarget=null}function Mr(e,t){t=0!=(4&t);for(var n=0;n<e.length;n++){var r=e[n],a=r.event;r=r.listeners;e:{var i=void 0;if(t)for(var o=r.length-1;0<=o;o--){var s=r[o],l=s.instance,c=s.currentTarget;if(s=s.listener,l!==i&&a.isPropagationStopped())break e;Dr(a,s,c),i=l}else for(o=0;o<r.length;o++){if(l=(s=r[o]).instance,c=s.currentTarget,s=s.listener,l!==i&&a.isPropagationStopped())break e;Dr(a,s,c),i=l}}}if(Me)throw e=ze,Me=!1,ze=null,e}function zr(e,t){var n=t[ma];void 0===n&&(n=t[ma]=new Set);var r=e+"__bubble";n.has(r)||(Zr(t,e,2,!1),n.add(r))}function Br(e,t,n){var r=0;t&&(r|=4),Zr(n,e,r,t)}var $r="_reactListening"+Math.random().toString(36).slice(2);function Ur(e){if(!e[$r]){e[$r]=!0,o.forEach((function(t){"selectionchange"!==t&&(Fr.has(t)||Br(t,!1,e),Br(t,!0,e))}));var t=9===e.nodeType?e:e.ownerDocument;null===t||t[$r]||(t[$r]=!0,Br("selectionchange",!1,t))}}function Zr(e,t,n,r){switch(Qt(t)){case 1:var a=qt;break;case 4:a=Vt;break;default:a=Wt}n=a.bind(null,t,n,e),a=void 0,!Oe||"touchstart"!==t&&"touchmove"!==t&&"wheel"!==t||(a=!0),r?void 0!==a?e.addEventListener(t,n,{capture:!0,passive:a}):e.addEventListener(t,n,!0):void 0!==a?e.addEventListener(t,n,{passive:a}):e.addEventListener(t,n,!1)}function Hr(e,t,n,r,a){var i=r;if(0==(1&t)&&0==(2&t)&&null!==r)e:for(;;){if(null===r)return;var o=r.tag;if(3===o||4===o){var s=r.stateNode.containerInfo;if(s===a||8===s.nodeType&&s.parentNode===a)break;if(4===o)for(o=r.return;null!==o;){var l=o.tag;if((3===l||4===l)&&((l=o.stateNode.containerInfo)===a||8===l.nodeType&&l.parentNode===a))return;o=o.return}for(;null!==s;){if(null===(o=ya(s)))return;if(5===(l=o.tag)||6===l){r=i=o;continue e}s=s.parentNode}}r=r.return}Ae((function(){var r=i,a=ke(n),o=[];e:{var s=Lr.get(e);if(void 0!==s){var l=un,c=e;switch(e){case"keypress":if(0===tn(n))break e;case"keydown":case"keyup":l=Tn;break;case"focusin":c="focus",l=gn;break;case"focusout":c="blur",l=gn;break;case"beforeblur":case"afterblur":l=gn;break;case"click":if(2===n.button)break e;case"auxclick":case"dblclick":case"mousedown":case"mousemove":case"mouseup":case"mouseout":case"mouseover":case"contextmenu":l=hn;break;case"drag":case"dragend":case"dragenter":case"dragexit":case"dragleave":case"dragover":case"dragstart":case"drop":l=mn;break;case"touchcancel":case"touchend":case"touchmove":case"touchstart":l=Nn;break;case Cr:case Tr:case jr:l=vn;break;case Nr:l=Ln;break;case"scroll":l=pn;break;case"wheel":l=Pn;break;case"copy":case"cut":case"paste":l=bn;break;case"gotpointercapture":case"lostpointercapture":case"pointercancel":case"pointerdown":case"pointermove":case"pointerout":case"pointerover":case"pointerup":l=jn}var u=0!=(4&t),d=!u&&"scroll"===e,p=u?null!==s?s+"Capture":null:s;u=[];for(var f,h=r;null!==h;){var m=(f=h).stateNode;if(5===f.tag&&null!==m&&(f=m,null!==p&&(null!=(m=Pe(h,p))&&u.push(qr(h,m,f)))),d)break;h=h.return}0<u.length&&(s=new l(s,c,null,n,a),o.push({event:s,listeners:u}))}}if(0==(7&t)){if(l="mouseout"===e||"pointerout"===e,(!(s="mouseover"===e||"pointerover"===e)||n===we||!(c=n.relatedTarget||n.fromElement)||!ya(c)&&!c[ha])&&(l||s)&&(s=a.window===a?a:(s=a.ownerDocument)?s.defaultView||s.parentWindow:window,l?(l=r,null!==(c=(c=n.relatedTarget||n.toElement)?ya(c):null)&&(c!==(d=Ue(c))||5!==c.tag&&6!==c.tag)&&(c=null)):(l=null,c=r),l!==c)){if(u=hn,m="onMouseLeave",p="onMouseEnter",h="mouse","pointerout"!==e&&"pointerover"!==e||(u=jn,m="onPointerLeave",p="onPointerEnter",h="pointer"),d=null==l?s:wa(l),f=null==c?s:wa(c),(s=new u(m,h+"leave",l,n,a)).target=d,s.relatedTarget=f,m=null,ya(a)===r&&((u=new u(p,h+"enter",c,n,a)).target=f,u.relatedTarget=d,m=u),d=m,l&&c)e:{for(p=c,h=0,f=u=l;f;f=Wr(f))h++;for(f=0,m=p;m;m=Wr(m))f++;for(;0<h-f;)u=Wr(u),h--;for(;0<f-h;)p=Wr(p),f--;for(;h--;){if(u===p||null!==p&&u===p.alternate)break e;u=Wr(u),p=Wr(p)}u=null}else u=null;null!==l&&Gr(o,s,l,u,!1),null!==c&&null!==d&&Gr(o,d,c,u,!0)}if("select"===(l=(s=r?wa(r):window).nodeName&&s.nodeName.toLowerCase())||"input"===l&&"file"===s.type)var g=Qn;else if(Hn(s))if(Kn)g=or;else{g=ar;var v=rr}else(l=s.nodeName)&&"input"===l.toLowerCase()&&("checkbox"===s.type||"radio"===s.type)&&(g=ir);switch(g&&(g=g(e,r))?qn(o,g,n,a):(v&&v(e,s,r),"focusout"===e&&(v=s._wrapperState)&&v.controlled&&"number"===s.type&&ee(s,"number",s.value)),v=r?wa(r):window,e){case"focusin":(Hn(v)||"true"===v.contentEditable)&&(gr=v,vr=r,yr=null);break;case"focusout":yr=vr=gr=null;break;case"mousedown":br=!0;break;case"contextmenu":case"mouseup":case"dragend":br=!1,wr(o,n,a);break;case"selectionchange":if(mr)break;case"keydown":case"keyup":wr(o,n,a)}var y;if(Rn)e:{switch(e){case"compositionstart":var b="onCompositionStart";break e;case"compositionend":b="onCompositionEnd";break e;case"compositionupdate":b="onCompositionUpdate";break e}b=void 0}else Un?Bn(e,n)&&(b="onCompositionEnd"):"keydown"===e&&229===n.keyCode&&(b="onCompositionStart");b&&(Dn&&"ko"!==n.locale&&(Un||"onCompositionStart"!==b?"onCompositionEnd"===b&&Un&&(y=en()):(Xt="value"in(Kt=a)?Kt.value:Kt.textContent,Un=!0)),0<(v=Vr(r,b)).length&&(b=new wn(b,e,null,n,a),o.push({event:b,listeners:v}),y?b.data=y:null!==(y=$n(n))&&(b.data=y))),(y=Fn?function(e,t){switch(e){case"compositionend":return $n(t);case"keypress":return 32!==t.which?null:(zn=!0,Mn);case"textInput":return(e=t.data)===Mn&&zn?null:e;default:return null}}(e,n):function(e,t){if(Un)return"compositionend"===e||!Rn&&Bn(e,t)?(e=en(),Jt=Xt=Kt=null,Un=!1,e):null;switch(e){case"paste":default:return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1<t.char.length)return t.char;if(t.which)return String.fromCharCode(t.which)}return null;case"compositionend":return Dn&&"ko"!==t.locale?null:t.data}}(e,n))&&(0<(r=Vr(r,"onBeforeInput")).length&&(a=new wn("onBeforeInput","beforeinput",null,n,a),o.push({event:a,listeners:r}),a.data=y))}Mr(o,t)}))}function qr(e,t,n){return{instance:e,listener:t,currentTarget:n}}function Vr(e,t){for(var n=t+"Capture",r=[];null!==e;){var a=e,i=a.stateNode;5===a.tag&&null!==i&&(a=i,null!=(i=Pe(e,n))&&r.unshift(qr(e,i,a)),null!=(i=Pe(e,t))&&r.push(qr(e,i,a))),e=e.return}return r}function Wr(e){if(null===e)return null;do{e=e.return}while(e&&5!==e.tag);return e||null}function Gr(e,t,n,r,a){for(var i=t._reactName,o=[];null!==n&&n!==r;){var s=n,l=s.alternate,c=s.stateNode;if(null!==l&&l===r)break;5===s.tag&&null!==c&&(s=c,a?null!=(l=Pe(n,i))&&o.unshift(qr(n,l,s)):a||null!=(l=Pe(n,i))&&o.push(qr(n,l,s))),n=n.return}0!==o.length&&e.push({event:t,listeners:o})}var Yr=/\r\n?/g,Qr=/\u0000|\uFFFD/g;function Kr(e){return("string"==typeof e?e:""+e).replace(Yr,"\n").replace(Qr,"")}function Xr(e,t,n){if(t=Kr(t),Kr(e)!==t&&n)throw Error(i(425))}function Jr(){}var ea=null,ta=null;function na(e,t){return"textarea"===e||"noscript"===e||"string"==typeof t.children||"number"==typeof t.children||"object"==typeof t.dangerouslySetInnerHTML&&null!==t.dangerouslySetInnerHTML&&null!=t.dangerouslySetInnerHTML.__html}var ra="function"==typeof setTimeout?setTimeout:void 0,aa="function"==typeof clearTimeout?clearTimeout:void 0,ia="function"==typeof Promise?Promise:void 0,oa="function"==typeof queueMicrotask?queueMicrotask:void 0!==ia?function(e){return ia.resolve(null).then(e).catch(sa)}:ra;function sa(e){setTimeout((function(){throw e}))}function la(e,t){var n=t,r=0;do{var a=n.nextSibling;if(e.removeChild(n),a&&8===a.nodeType)if("/$"===(n=a.data)){if(0===r)return e.removeChild(a),void Ut(t);r--}else"$"!==n&&"$?"!==n&&"$!"!==n||r++;n=a}while(n);Ut(t)}function ca(e){for(;null!=e;e=e.nextSibling){var t=e.nodeType;if(1===t||3===t)break;if(8===t){if("$"===(t=e.data)||"$!"===t||"$?"===t)break;if("/$"===t)return null}}return e}function ua(e){e=e.previousSibling;for(var t=0;e;){if(8===e.nodeType){var n=e.data;if("$"===n||"$!"===n||"$?"===n){if(0===t)return e;t--}else"/$"===n&&t++}e=e.previousSibling}return null}var da=Math.random().toString(36).slice(2),pa="__reactFiber$"+da,fa="__reactProps$"+da,ha="__reactContainer$"+da,ma="__reactEvents$"+da,ga="__reactListeners$"+da,va="__reactHandles$"+da;function ya(e){var t=e[pa];if(t)return t;for(var n=e.parentNode;n;){if(t=n[ha]||n[pa]){if(n=t.alternate,null!==t.child||null!==n&&null!==n.child)for(e=ua(e);null!==e;){if(n=e[pa])return n;e=ua(e)}return t}n=(e=n).parentNode}return null}function ba(e){return!(e=e[pa]||e[ha])||5!==e.tag&&6!==e.tag&&13!==e.tag&&3!==e.tag?null:e}function wa(e){if(5===e.tag||6===e.tag)return e.stateNode;throw Error(i(33))}function ka(e){return e[fa]||null}var xa=[],Sa=-1;function _a(e){return{current:e}}function Ea(e){0>Sa||(e.current=xa[Sa],xa[Sa]=null,Sa--)}function Ca(e,t){Sa++,xa[Sa]=e.current,e.current=t}var Ta={},ja=_a(Ta),Na=_a(!1),La=Ta;function Aa(e,t){var n=e.type.contextTypes;if(!n)return Ta;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var a,i={};for(a in n)i[a]=t[a];return r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=i),i}function Pa(e){return null!=(e=e.childContextTypes)}function Oa(){Ea(Na),Ea(ja)}function Ra(e,t,n){if(ja.current!==Ta)throw Error(i(168));Ca(ja,t),Ca(Na,n)}function Ia(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,"function"!=typeof r.getChildContext)return n;for(var a in r=r.getChildContext())if(!(a in t))throw Error(i(108,Z(e)||"Unknown",a));return D({},n,r)}function Fa(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||Ta,La=ja.current,Ca(ja,e),Ca(Na,Na.current),!0}function Da(e,t,n){var r=e.stateNode;if(!r)throw Error(i(169));n?(e=Ia(e,t,La),r.__reactInternalMemoizedMergedChildContext=e,Ea(Na),Ea(ja),Ca(ja,e)):Ea(Na),Ca(Na,n)}var Ma=null,za=!1,Ba=!1;function $a(e){null===Ma?Ma=[e]:Ma.push(e)}function Ua(){if(!Ba&&null!==Ma){Ba=!0;var e=0,t=bt;try{var n=Ma;for(bt=1;e<n.length;e++){var r=n[e];do{r=r(!0)}while(null!==r)}Ma=null,za=!1}catch(a){throw null!==Ma&&(Ma=Ma.slice(e+1)),We(Je,Ua),a}finally{bt=t,Ba=!1}}return null}var Za=[],Ha=0,qa=null,Va=0,Wa=[],Ga=0,Ya=null,Qa=1,Ka="";function Xa(e,t){Za[Ha++]=Va,Za[Ha++]=qa,qa=e,Va=t}function Ja(e,t,n){Wa[Ga++]=Qa,Wa[Ga++]=Ka,Wa[Ga++]=Ya,Ya=e;var r=Qa;e=Ka;var a=32-ot(r)-1;r&=~(1<<a),n+=1;var i=32-ot(t)+a;if(30<i){var o=a-a%5;i=(r&(1<<o)-1).toString(32),r>>=o,a-=o,Qa=1<<32-ot(t)+a|n<<a|r,Ka=i+e}else Qa=1<<i|n<<a|r,Ka=e}function ei(e){null!==e.return&&(Xa(e,1),Ja(e,1,0))}function ti(e){for(;e===qa;)qa=Za[--Ha],Za[Ha]=null,Va=Za[--Ha],Za[Ha]=null;for(;e===Ya;)Ya=Wa[--Ga],Wa[Ga]=null,Ka=Wa[--Ga],Wa[Ga]=null,Qa=Wa[--Ga],Wa[Ga]=null}var ni=null,ri=null,ai=!1,ii=null;function oi(e,t){var n=Pc(5,null,null,0);n.elementType="DELETED",n.stateNode=t,n.return=e,null===(t=e.deletions)?(e.deletions=[n],e.flags|=16):t.push(n)}function si(e,t){switch(e.tag){case 5:var n=e.type;return null!==(t=1!==t.nodeType||n.toLowerCase()!==t.nodeName.toLowerCase()?null:t)&&(e.stateNode=t,ni=e,ri=ca(t.firstChild),!0);case 6:return null!==(t=""===e.pendingProps||3!==t.nodeType?null:t)&&(e.stateNode=t,ni=e,ri=null,!0);case 13:return null!==(t=8!==t.nodeType?null:t)&&(n=null!==Ya?{id:Qa,overflow:Ka}:null,e.memoizedState={dehydrated:t,treeContext:n,retryLane:1073741824},(n=Pc(18,null,null,0)).stateNode=t,n.return=e,e.child=n,ni=e,ri=null,!0);default:return!1}}function li(e){return 0!=(1&e.mode)&&0==(128&e.flags)}function ci(e){if(ai){var t=ri;if(t){var n=t;if(!si(e,t)){if(li(e))throw Error(i(418));t=ca(n.nextSibling);var r=ni;t&&si(e,t)?oi(r,n):(e.flags=-4097&e.flags|2,ai=!1,ni=e)}}else{if(li(e))throw Error(i(418));e.flags=-4097&e.flags|2,ai=!1,ni=e}}}function ui(e){for(e=e.return;null!==e&&5!==e.tag&&3!==e.tag&&13!==e.tag;)e=e.return;ni=e}function di(e){if(e!==ni)return!1;if(!ai)return ui(e),ai=!0,!1;var t;if((t=3!==e.tag)&&!(t=5!==e.tag)&&(t="head"!==(t=e.type)&&"body"!==t&&!na(e.type,e.memoizedProps)),t&&(t=ri)){if(li(e))throw pi(),Error(i(418));for(;t;)oi(e,t),t=ca(t.nextSibling)}if(ui(e),13===e.tag){if(!(e=null!==(e=e.memoizedState)?e.dehydrated:null))throw Error(i(317));e:{for(e=e.nextSibling,t=0;e;){if(8===e.nodeType){var n=e.data;if("/$"===n){if(0===t){ri=ca(e.nextSibling);break e}t--}else"$"!==n&&"$!"!==n&&"$?"!==n||t++}e=e.nextSibling}ri=null}}else ri=ni?ca(e.stateNode.nextSibling):null;return!0}function pi(){for(var e=ri;e;)e=ca(e.nextSibling)}function fi(){ri=ni=null,ai=!1}function hi(e){null===ii?ii=[e]:ii.push(e)}var mi=w.ReactCurrentBatchConfig;function gi(e,t){if(e&&e.defaultProps){for(var n in t=D({},t),e=e.defaultProps)void 0===t[n]&&(t[n]=e[n]);return t}return t}var vi=_a(null),yi=null,bi=null,wi=null;function ki(){wi=bi=yi=null}function xi(e){var t=vi.current;Ea(vi),e._currentValue=t}function Si(e,t,n){for(;null!==e;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,null!==r&&(r.childLanes|=t)):null!==r&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function _i(e,t){yi=e,wi=bi=null,null!==(e=e.dependencies)&&null!==e.firstContext&&(0!=(e.lanes&t)&&(ws=!0),e.firstContext=null)}function Ei(e){var t=e._currentValue;if(wi!==e)if(e={context:e,memoizedValue:t,next:null},null===bi){if(null===yi)throw Error(i(308));bi=e,yi.dependencies={lanes:0,firstContext:e}}else bi=bi.next=e;return t}var Ci=null;function Ti(e){null===Ci?Ci=[e]:Ci.push(e)}function ji(e,t,n,r){var a=t.interleaved;return null===a?(n.next=n,Ti(t)):(n.next=a.next,a.next=n),t.interleaved=n,Ni(e,r)}function Ni(e,t){e.lanes|=t;var n=e.alternate;for(null!==n&&(n.lanes|=t),n=e,e=e.return;null!==e;)e.childLanes|=t,null!==(n=e.alternate)&&(n.childLanes|=t),n=e,e=e.return;return 3===n.tag?n.stateNode:null}var Li=!1;function Ai(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function Pi(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Oi(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function Ri(e,t,n){var r=e.updateQueue;if(null===r)return null;if(r=r.shared,0!=(2&Nl)){var a=r.pending;return null===a?t.next=t:(t.next=a.next,a.next=t),r.pending=t,Ni(e,n)}return null===(a=r.interleaved)?(t.next=t,Ti(r)):(t.next=a.next,a.next=t),r.interleaved=t,Ni(e,n)}function Ii(e,t,n){if(null!==(t=t.updateQueue)&&(t=t.shared,0!=(4194240&n))){var r=t.lanes;n|=r&=e.pendingLanes,t.lanes=n,yt(e,n)}}function Fi(e,t){var n=e.updateQueue,r=e.alternate;if(null!==r&&n===(r=r.updateQueue)){var a=null,i=null;if(null!==(n=n.firstBaseUpdate)){do{var o={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};null===i?a=i=o:i=i.next=o,n=n.next}while(null!==n);null===i?a=i=t:i=i.next=t}else a=i=t;return n={baseState:r.baseState,firstBaseUpdate:a,lastBaseUpdate:i,shared:r.shared,effects:r.effects},void(e.updateQueue=n)}null===(e=n.lastBaseUpdate)?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function Di(e,t,n,r){var a=e.updateQueue;Li=!1;var i=a.firstBaseUpdate,o=a.lastBaseUpdate,s=a.shared.pending;if(null!==s){a.shared.pending=null;var l=s,c=l.next;l.next=null,null===o?i=c:o.next=c,o=l;var u=e.alternate;null!==u&&((s=(u=u.updateQueue).lastBaseUpdate)!==o&&(null===s?u.firstBaseUpdate=c:s.next=c,u.lastBaseUpdate=l))}if(null!==i){var d=a.baseState;for(o=0,u=c=l=null,s=i;;){var p=s.lane,f=s.eventTime;if((r&p)===p){null!==u&&(u=u.next={eventTime:f,lane:0,tag:s.tag,payload:s.payload,callback:s.callback,next:null});e:{var h=e,m=s;switch(p=t,f=n,m.tag){case 1:if("function"==typeof(h=m.payload)){d=h.call(f,d,p);break e}d=h;break e;case 3:h.flags=-65537&h.flags|128;case 0:if(null==(p="function"==typeof(h=m.payload)?h.call(f,d,p):h))break e;d=D({},d,p);break e;case 2:Li=!0}}null!==s.callback&&0!==s.lane&&(e.flags|=64,null===(p=a.effects)?a.effects=[s]:p.push(s))}else f={eventTime:f,lane:p,tag:s.tag,payload:s.payload,callback:s.callback,next:null},null===u?(c=u=f,l=d):u=u.next=f,o|=p;if(null===(s=s.next)){if(null===(s=a.shared.pending))break;s=(p=s).next,p.next=null,a.lastBaseUpdate=p,a.shared.pending=null}}if(null===u&&(l=d),a.baseState=l,a.firstBaseUpdate=c,a.lastBaseUpdate=u,null!==(t=a.shared.interleaved)){a=t;do{o|=a.lane,a=a.next}while(a!==t)}else null===i&&(a.shared.lanes=0);Dl|=o,e.lanes=o,e.memoizedState=d}}function Mi(e,t,n){if(e=t.effects,t.effects=null,null!==e)for(t=0;t<e.length;t++){var r=e[t],a=r.callback;if(null!==a){if(r.callback=null,r=n,"function"!=typeof a)throw Error(i(191,a));a.call(r)}}}var zi=(new r.Component).refs;function Bi(e,t,n,r){n=null==(n=n(r,t=e.memoizedState))?t:D({},t,n),e.memoizedState=n,0===e.lanes&&(e.updateQueue.baseState=n)}var $i={isMounted:function(e){return!!(e=e._reactInternals)&&Ue(e)===e},enqueueSetState:function(e,t,n){e=e._reactInternals;var r=tc(),a=nc(e),i=Oi(r,a);i.payload=t,null!=n&&(i.callback=n),null!==(t=Ri(e,i,a))&&(rc(t,e,a,r),Ii(t,e,a))},enqueueReplaceState:function(e,t,n){e=e._reactInternals;var r=tc(),a=nc(e),i=Oi(r,a);i.tag=1,i.payload=t,null!=n&&(i.callback=n),null!==(t=Ri(e,i,a))&&(rc(t,e,a,r),Ii(t,e,a))},enqueueForceUpdate:function(e,t){e=e._reactInternals;var n=tc(),r=nc(e),a=Oi(n,r);a.tag=2,null!=t&&(a.callback=t),null!==(t=Ri(e,a,r))&&(rc(t,e,r,n),Ii(t,e,r))}};function Ui(e,t,n,r,a,i,o){return"function"==typeof(e=e.stateNode).shouldComponentUpdate?e.shouldComponentUpdate(r,i,o):!t.prototype||!t.prototype.isPureReactComponent||(!lr(n,r)||!lr(a,i))}function Zi(e,t,n){var r=!1,a=Ta,i=t.contextType;return"object"==typeof i&&null!==i?i=Ei(i):(a=Pa(t)?La:ja.current,i=(r=null!=(r=t.contextTypes))?Aa(e,a):Ta),t=new t(n,i),e.memoizedState=null!==t.state&&void 0!==t.state?t.state:null,t.updater=$i,e.stateNode=t,t._reactInternals=e,r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=a,e.__reactInternalMemoizedMaskedChildContext=i),t}function Hi(e,t,n,r){e=t.state,"function"==typeof t.componentWillReceiveProps&&t.componentWillReceiveProps(n,r),"function"==typeof t.UNSAFE_componentWillReceiveProps&&t.UNSAFE_componentWillReceiveProps(n,r),t.state!==e&&$i.enqueueReplaceState(t,t.state,null)}function qi(e,t,n,r){var a=e.stateNode;a.props=n,a.state=e.memoizedState,a.refs=zi,Ai(e);var i=t.contextType;"object"==typeof i&&null!==i?a.context=Ei(i):(i=Pa(t)?La:ja.current,a.context=Aa(e,i)),a.state=e.memoizedState,"function"==typeof(i=t.getDerivedStateFromProps)&&(Bi(e,t,i,n),a.state=e.memoizedState),"function"==typeof t.getDerivedStateFromProps||"function"==typeof a.getSnapshotBeforeUpdate||"function"!=typeof a.UNSAFE_componentWillMount&&"function"!=typeof a.componentWillMount||(t=a.state,"function"==typeof a.componentWillMount&&a.componentWillMount(),"function"==typeof a.UNSAFE_componentWillMount&&a.UNSAFE_componentWillMount(),t!==a.state&&$i.enqueueReplaceState(a,a.state,null),Di(e,n,a,r),a.state=e.memoizedState),"function"==typeof a.componentDidMount&&(e.flags|=4194308)}function Vi(e,t,n){if(null!==(e=n.ref)&&"function"!=typeof e&&"object"!=typeof e){if(n._owner){if(n=n._owner){if(1!==n.tag)throw Error(i(309));var r=n.stateNode}if(!r)throw Error(i(147,e));var a=r,o=""+e;return null!==t&&null!==t.ref&&"function"==typeof t.ref&&t.ref._stringRef===o?t.ref:(t=function(e){var t=a.refs;t===zi&&(t=a.refs={}),null===e?delete t[o]:t[o]=e},t._stringRef=o,t)}if("string"!=typeof e)throw Error(i(284));if(!n._owner)throw Error(i(290,e))}return e}function Wi(e,t){throw e=Object.prototype.toString.call(t),Error(i(31,"[object Object]"===e?"object with keys {"+Object.keys(t).join(", ")+"}":e))}function Gi(e){return(0,e._init)(e._payload)}function Yi(e){function t(t,n){if(e){var r=t.deletions;null===r?(t.deletions=[n],t.flags|=16):r.push(n)}}function n(n,r){if(!e)return null;for(;null!==r;)t(n,r),r=r.sibling;return null}function r(e,t){for(e=new Map;null!==t;)null!==t.key?e.set(t.key,t):e.set(t.index,t),t=t.sibling;return e}function a(e,t){return(e=Rc(e,t)).index=0,e.sibling=null,e}function o(t,n,r){return t.index=r,e?null!==(r=t.alternate)?(r=r.index)<n?(t.flags|=2,n):r:(t.flags|=2,n):(t.flags|=1048576,n)}function s(t){return e&&null===t.alternate&&(t.flags|=2),t}function l(e,t,n,r){return null===t||6!==t.tag?((t=Mc(n,e.mode,r)).return=e,t):((t=a(t,n)).return=e,t)}function c(e,t,n,r){var i=n.type;return i===S?d(e,t,n.props.children,r,n.key):null!==t&&(t.elementType===i||"object"==typeof i&&null!==i&&i.$$typeof===P&&Gi(i)===t.type)?((r=a(t,n.props)).ref=Vi(e,t,n),r.return=e,r):((r=Ic(n.type,n.key,n.props,null,e.mode,r)).ref=Vi(e,t,n),r.return=e,r)}function u(e,t,n,r){return null===t||4!==t.tag||t.stateNode.containerInfo!==n.containerInfo||t.stateNode.implementation!==n.implementation?((t=zc(n,e.mode,r)).return=e,t):((t=a(t,n.children||[])).return=e,t)}function d(e,t,n,r,i){return null===t||7!==t.tag?((t=Fc(n,e.mode,r,i)).return=e,t):((t=a(t,n)).return=e,t)}function p(e,t,n){if("string"==typeof t&&""!==t||"number"==typeof t)return(t=Mc(""+t,e.mode,n)).return=e,t;if("object"==typeof t&&null!==t){switch(t.$$typeof){case k:return(n=Ic(t.type,t.key,t.props,null,e.mode,n)).ref=Vi(e,null,t),n.return=e,n;case x:return(t=zc(t,e.mode,n)).return=e,t;case P:return p(e,(0,t._init)(t._payload),n)}if(te(t)||I(t))return(t=Fc(t,e.mode,n,null)).return=e,t;Wi(e,t)}return null}function f(e,t,n,r){var a=null!==t?t.key:null;if("string"==typeof n&&""!==n||"number"==typeof n)return null!==a?null:l(e,t,""+n,r);if("object"==typeof n&&null!==n){switch(n.$$typeof){case k:return n.key===a?c(e,t,n,r):null;case x:return n.key===a?u(e,t,n,r):null;case P:return f(e,t,(a=n._init)(n._payload),r)}if(te(n)||I(n))return null!==a?null:d(e,t,n,r,null);Wi(e,n)}return null}function h(e,t,n,r,a){if("string"==typeof r&&""!==r||"number"==typeof r)return l(t,e=e.get(n)||null,""+r,a);if("object"==typeof r&&null!==r){switch(r.$$typeof){case k:return c(t,e=e.get(null===r.key?n:r.key)||null,r,a);case x:return u(t,e=e.get(null===r.key?n:r.key)||null,r,a);case P:return h(e,t,n,(0,r._init)(r._payload),a)}if(te(r)||I(r))return d(t,e=e.get(n)||null,r,a,null);Wi(t,r)}return null}function m(a,i,s,l){for(var c=null,u=null,d=i,m=i=0,g=null;null!==d&&m<s.length;m++){d.index>m?(g=d,d=null):g=d.sibling;var v=f(a,d,s[m],l);if(null===v){null===d&&(d=g);break}e&&d&&null===v.alternate&&t(a,d),i=o(v,i,m),null===u?c=v:u.sibling=v,u=v,d=g}if(m===s.length)return n(a,d),ai&&Xa(a,m),c;if(null===d){for(;m<s.length;m++)null!==(d=p(a,s[m],l))&&(i=o(d,i,m),null===u?c=d:u.sibling=d,u=d);return ai&&Xa(a,m),c}for(d=r(a,d);m<s.length;m++)null!==(g=h(d,a,m,s[m],l))&&(e&&null!==g.alternate&&d.delete(null===g.key?m:g.key),i=o(g,i,m),null===u?c=g:u.sibling=g,u=g);return e&&d.forEach((function(e){return t(a,e)})),ai&&Xa(a,m),c}function g(a,s,l,c){var u=I(l);if("function"!=typeof u)throw Error(i(150));if(null==(l=u.call(l)))throw Error(i(151));for(var d=u=null,m=s,g=s=0,v=null,y=l.next();null!==m&&!y.done;g++,y=l.next()){m.index>g?(v=m,m=null):v=m.sibling;var b=f(a,m,y.value,c);if(null===b){null===m&&(m=v);break}e&&m&&null===b.alternate&&t(a,m),s=o(b,s,g),null===d?u=b:d.sibling=b,d=b,m=v}if(y.done)return n(a,m),ai&&Xa(a,g),u;if(null===m){for(;!y.done;g++,y=l.next())null!==(y=p(a,y.value,c))&&(s=o(y,s,g),null===d?u=y:d.sibling=y,d=y);return ai&&Xa(a,g),u}for(m=r(a,m);!y.done;g++,y=l.next())null!==(y=h(m,a,g,y.value,c))&&(e&&null!==y.alternate&&m.delete(null===y.key?g:y.key),s=o(y,s,g),null===d?u=y:d.sibling=y,d=y);return e&&m.forEach((function(e){return t(a,e)})),ai&&Xa(a,g),u}return function e(r,i,o,l){if("object"==typeof o&&null!==o&&o.type===S&&null===o.key&&(o=o.props.children),"object"==typeof o&&null!==o){switch(o.$$typeof){case k:e:{for(var c=o.key,u=i;null!==u;){if(u.key===c){if((c=o.type)===S){if(7===u.tag){n(r,u.sibling),(i=a(u,o.props.children)).return=r,r=i;break e}}else if(u.elementType===c||"object"==typeof c&&null!==c&&c.$$typeof===P&&Gi(c)===u.type){n(r,u.sibling),(i=a(u,o.props)).ref=Vi(r,u,o),i.return=r,r=i;break e}n(r,u);break}t(r,u),u=u.sibling}o.type===S?((i=Fc(o.props.children,r.mode,l,o.key)).return=r,r=i):((l=Ic(o.type,o.key,o.props,null,r.mode,l)).ref=Vi(r,i,o),l.return=r,r=l)}return s(r);case x:e:{for(u=o.key;null!==i;){if(i.key===u){if(4===i.tag&&i.stateNode.containerInfo===o.containerInfo&&i.stateNode.implementation===o.implementation){n(r,i.sibling),(i=a(i,o.children||[])).return=r,r=i;break e}n(r,i);break}t(r,i),i=i.sibling}(i=zc(o,r.mode,l)).return=r,r=i}return s(r);case P:return e(r,i,(u=o._init)(o._payload),l)}if(te(o))return m(r,i,o,l);if(I(o))return g(r,i,o,l);Wi(r,o)}return"string"==typeof o&&""!==o||"number"==typeof o?(o=""+o,null!==i&&6===i.tag?(n(r,i.sibling),(i=a(i,o)).return=r,r=i):(n(r,i),(i=Mc(o,r.mode,l)).return=r,r=i),s(r)):n(r,i)}}var Qi=Yi(!0),Ki=Yi(!1),Xi={},Ji=_a(Xi),eo=_a(Xi),to=_a(Xi);function no(e){if(e===Xi)throw Error(i(174));return e}function ro(e,t){switch(Ca(to,t),Ca(eo,e),Ca(Ji,Xi),e=t.nodeType){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:le(null,"");break;default:t=le(t=(e=8===e?t.parentNode:t).namespaceURI||null,e=e.tagName)}Ea(Ji),Ca(Ji,t)}function ao(){Ea(Ji),Ea(eo),Ea(to)}function io(e){no(to.current);var t=no(Ji.current),n=le(t,e.type);t!==n&&(Ca(eo,e),Ca(Ji,n))}function oo(e){eo.current===e&&(Ea(Ji),Ea(eo))}var so=_a(0);function lo(e){for(var t=e;null!==t;){if(13===t.tag){var n=t.memoizedState;if(null!==n&&(null===(n=n.dehydrated)||"$?"===n.data||"$!"===n.data))return t}else if(19===t.tag&&void 0!==t.memoizedProps.revealOrder){if(0!=(128&t.flags))return t}else if(null!==t.child){t.child.return=t,t=t.child;continue}if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}var co=[];function uo(){for(var e=0;e<co.length;e++)co[e]._workInProgressVersionPrimary=null;co.length=0}var po=w.ReactCurrentDispatcher,fo=w.ReactCurrentBatchConfig,ho=0,mo=null,go=null,vo=null,yo=!1,bo=!1,wo=0,ko=0;function xo(){throw Error(i(321))}function So(e,t){if(null===t)return!1;for(var n=0;n<t.length&&n<e.length;n++)if(!sr(e[n],t[n]))return!1;return!0}function _o(e,t,n,r,a,o){if(ho=o,mo=t,t.memoizedState=null,t.updateQueue=null,t.lanes=0,po.current=null===e||null===e.memoizedState?ss:ls,e=n(r,a),bo){o=0;do{if(bo=!1,wo=0,25<=o)throw Error(i(301));o+=1,vo=go=null,t.updateQueue=null,po.current=cs,e=n(r,a)}while(bo)}if(po.current=os,t=null!==go&&null!==go.next,ho=0,vo=go=mo=null,yo=!1,t)throw Error(i(300));return e}function Eo(){var e=0!==wo;return wo=0,e}function Co(){var e={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return null===vo?mo.memoizedState=vo=e:vo=vo.next=e,vo}function To(){if(null===go){var e=mo.alternate;e=null!==e?e.memoizedState:null}else e=go.next;var t=null===vo?mo.memoizedState:vo.next;if(null!==t)vo=t,go=e;else{if(null===e)throw Error(i(310));e={memoizedState:(go=e).memoizedState,baseState:go.baseState,baseQueue:go.baseQueue,queue:go.queue,next:null},null===vo?mo.memoizedState=vo=e:vo=vo.next=e}return vo}function jo(e,t){return"function"==typeof t?t(e):t}function No(e){var t=To(),n=t.queue;if(null===n)throw Error(i(311));n.lastRenderedReducer=e;var r=go,a=r.baseQueue,o=n.pending;if(null!==o){if(null!==a){var s=a.next;a.next=o.next,o.next=s}r.baseQueue=a=o,n.pending=null}if(null!==a){o=a.next,r=r.baseState;var l=s=null,c=null,u=o;do{var d=u.lane;if((ho&d)===d)null!==c&&(c=c.next={lane:0,action:u.action,hasEagerState:u.hasEagerState,eagerState:u.eagerState,next:null}),r=u.hasEagerState?u.eagerState:e(r,u.action);else{var p={lane:d,action:u.action,hasEagerState:u.hasEagerState,eagerState:u.eagerState,next:null};null===c?(l=c=p,s=r):c=c.next=p,mo.lanes|=d,Dl|=d}u=u.next}while(null!==u&&u!==o);null===c?s=r:c.next=l,sr(r,t.memoizedState)||(ws=!0),t.memoizedState=r,t.baseState=s,t.baseQueue=c,n.lastRenderedState=r}if(null!==(e=n.interleaved)){a=e;do{o=a.lane,mo.lanes|=o,Dl|=o,a=a.next}while(a!==e)}else null===a&&(n.lanes=0);return[t.memoizedState,n.dispatch]}function Lo(e){var t=To(),n=t.queue;if(null===n)throw Error(i(311));n.lastRenderedReducer=e;var r=n.dispatch,a=n.pending,o=t.memoizedState;if(null!==a){n.pending=null;var s=a=a.next;do{o=e(o,s.action),s=s.next}while(s!==a);sr(o,t.memoizedState)||(ws=!0),t.memoizedState=o,null===t.baseQueue&&(t.baseState=o),n.lastRenderedState=o}return[o,r]}function Ao(){}function Po(e,t){var n=mo,r=To(),a=t(),o=!sr(r.memoizedState,a);if(o&&(r.memoizedState=a,ws=!0),r=r.queue,Ho(Io.bind(null,n,r,e),[e]),r.getSnapshot!==t||o||null!==vo&&1&vo.memoizedState.tag){if(n.flags|=2048,zo(9,Ro.bind(null,n,r,a,t),void 0,null),null===Ll)throw Error(i(349));0!=(30&ho)||Oo(n,t,a)}return a}function Oo(e,t,n){e.flags|=16384,e={getSnapshot:t,value:n},null===(t=mo.updateQueue)?(t={lastEffect:null,stores:null},mo.updateQueue=t,t.stores=[e]):null===(n=t.stores)?t.stores=[e]:n.push(e)}function Ro(e,t,n,r){t.value=n,t.getSnapshot=r,Fo(t)&&Do(e)}function Io(e,t,n){return n((function(){Fo(t)&&Do(e)}))}function Fo(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!sr(e,n)}catch(r){return!0}}function Do(e){var t=Ni(e,1);null!==t&&rc(t,e,1,-1)}function Mo(e){var t=Co();return"function"==typeof e&&(e=e()),t.memoizedState=t.baseState=e,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:jo,lastRenderedState:e},t.queue=e,e=e.dispatch=ns.bind(null,mo,e),[t.memoizedState,e]}function zo(e,t,n,r){return e={tag:e,create:t,destroy:n,deps:r,next:null},null===(t=mo.updateQueue)?(t={lastEffect:null,stores:null},mo.updateQueue=t,t.lastEffect=e.next=e):null===(n=t.lastEffect)?t.lastEffect=e.next=e:(r=n.next,n.next=e,e.next=r,t.lastEffect=e),e}function Bo(){return To().memoizedState}function $o(e,t,n,r){var a=Co();mo.flags|=e,a.memoizedState=zo(1|t,n,void 0,void 0===r?null:r)}function Uo(e,t,n,r){var a=To();r=void 0===r?null:r;var i=void 0;if(null!==go){var o=go.memoizedState;if(i=o.destroy,null!==r&&So(r,o.deps))return void(a.memoizedState=zo(t,n,i,r))}mo.flags|=e,a.memoizedState=zo(1|t,n,i,r)}function Zo(e,t){return $o(8390656,8,e,t)}function Ho(e,t){return Uo(2048,8,e,t)}function qo(e,t){return Uo(4,2,e,t)}function Vo(e,t){return Uo(4,4,e,t)}function Wo(e,t){return"function"==typeof t?(e=e(),t(e),function(){t(null)}):null!=t?(e=e(),t.current=e,function(){t.current=null}):void 0}function Go(e,t,n){return n=null!=n?n.concat([e]):null,Uo(4,4,Wo.bind(null,t,e),n)}function Yo(){}function Qo(e,t){var n=To();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&So(t,r[1])?r[0]:(n.memoizedState=[e,t],e)}function Ko(e,t){var n=To();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&So(t,r[1])?r[0]:(e=e(),n.memoizedState=[e,t],e)}function Xo(e,t,n){return 0==(21&ho)?(e.baseState&&(e.baseState=!1,ws=!0),e.memoizedState=n):(sr(n,t)||(n=mt(),mo.lanes|=n,Dl|=n,e.baseState=!0),t)}function Jo(e,t){var n=bt;bt=0!==n&&4>n?n:4,e(!0);var r=fo.transition;fo.transition={};try{e(!1),t()}finally{bt=n,fo.transition=r}}function es(){return To().memoizedState}function ts(e,t,n){var r=nc(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},rs(e))as(t,n);else if(null!==(n=ji(e,t,n,r))){rc(n,e,r,tc()),is(n,t,r)}}function ns(e,t,n){var r=nc(e),a={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(rs(e))as(t,a);else{var i=e.alternate;if(0===e.lanes&&(null===i||0===i.lanes)&&null!==(i=t.lastRenderedReducer))try{var o=t.lastRenderedState,s=i(o,n);if(a.hasEagerState=!0,a.eagerState=s,sr(s,o)){var l=t.interleaved;return null===l?(a.next=a,Ti(t)):(a.next=l.next,l.next=a),void(t.interleaved=a)}}catch(c){}null!==(n=ji(e,t,a,r))&&(rc(n,e,r,a=tc()),is(n,t,r))}}function rs(e){var t=e.alternate;return e===mo||null!==t&&t===mo}function as(e,t){bo=yo=!0;var n=e.pending;null===n?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function is(e,t,n){if(0!=(4194240&n)){var r=t.lanes;n|=r&=e.pendingLanes,t.lanes=n,yt(e,n)}}var os={readContext:Ei,useCallback:xo,useContext:xo,useEffect:xo,useImperativeHandle:xo,useInsertionEffect:xo,useLayoutEffect:xo,useMemo:xo,useReducer:xo,useRef:xo,useState:xo,useDebugValue:xo,useDeferredValue:xo,useTransition:xo,useMutableSource:xo,useSyncExternalStore:xo,useId:xo,unstable_isNewReconciler:!1},ss={readContext:Ei,useCallback:function(e,t){return Co().memoizedState=[e,void 0===t?null:t],e},useContext:Ei,useEffect:Zo,useImperativeHandle:function(e,t,n){return n=null!=n?n.concat([e]):null,$o(4194308,4,Wo.bind(null,t,e),n)},useLayoutEffect:function(e,t){return $o(4194308,4,e,t)},useInsertionEffect:function(e,t){return $o(4,2,e,t)},useMemo:function(e,t){var n=Co();return t=void 0===t?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=Co();return t=void 0!==n?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=ts.bind(null,mo,e),[r.memoizedState,e]},useRef:function(e){return e={current:e},Co().memoizedState=e},useState:Mo,useDebugValue:Yo,useDeferredValue:function(e){return Co().memoizedState=e},useTransition:function(){var e=Mo(!1),t=e[0];return e=Jo.bind(null,e[1]),Co().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=mo,a=Co();if(ai){if(void 0===n)throw Error(i(407));n=n()}else{if(n=t(),null===Ll)throw Error(i(349));0!=(30&ho)||Oo(r,t,n)}a.memoizedState=n;var o={value:n,getSnapshot:t};return a.queue=o,Zo(Io.bind(null,r,o,e),[e]),r.flags|=2048,zo(9,Ro.bind(null,r,o,n,t),void 0,null),n},useId:function(){var e=Co(),t=Ll.identifierPrefix;if(ai){var n=Ka;t=":"+t+"R"+(n=(Qa&~(1<<32-ot(Qa)-1)).toString(32)+n),0<(n=wo++)&&(t+="H"+n.toString(32)),t+=":"}else t=":"+t+"r"+(n=ko++).toString(32)+":";return e.memoizedState=t},unstable_isNewReconciler:!1},ls={readContext:Ei,useCallback:Qo,useContext:Ei,useEffect:Ho,useImperativeHandle:Go,useInsertionEffect:qo,useLayoutEffect:Vo,useMemo:Ko,useReducer:No,useRef:Bo,useState:function(){return No(jo)},useDebugValue:Yo,useDeferredValue:function(e){return Xo(To(),go.memoizedState,e)},useTransition:function(){return[No(jo)[0],To().memoizedState]},useMutableSource:Ao,useSyncExternalStore:Po,useId:es,unstable_isNewReconciler:!1},cs={readContext:Ei,useCallback:Qo,useContext:Ei,useEffect:Ho,useImperativeHandle:Go,useInsertionEffect:qo,useLayoutEffect:Vo,useMemo:Ko,useReducer:Lo,useRef:Bo,useState:function(){return Lo(jo)},useDebugValue:Yo,useDeferredValue:function(e){var t=To();return null===go?t.memoizedState=e:Xo(t,go.memoizedState,e)},useTransition:function(){return[Lo(jo)[0],To().memoizedState]},useMutableSource:Ao,useSyncExternalStore:Po,useId:es,unstable_isNewReconciler:!1};function us(e,t){try{var n="",r=t;do{n+=$(r),r=r.return}while(r);var a=n}catch(i){a="\nError generating stack: "+i.message+"\n"+i.stack}return{value:e,source:t,stack:a,digest:null}}function ds(e,t,n){return{value:e,source:null,stack:null!=n?n:null,digest:null!=t?t:null}}function ps(e,t){try{console.error(t.value)}catch(n){setTimeout((function(){throw n}))}}var fs="function"==typeof WeakMap?WeakMap:Map;function hs(e,t,n){(n=Oi(-1,n)).tag=3,n.payload={element:null};var r=t.value;return n.callback=function(){ql||(ql=!0,Vl=r),ps(0,t)},n}function ms(e,t,n){(n=Oi(-1,n)).tag=3;var r=e.type.getDerivedStateFromError;if("function"==typeof r){var a=t.value;n.payload=function(){return r(a)},n.callback=function(){ps(0,t)}}var i=e.stateNode;return null!==i&&"function"==typeof i.componentDidCatch&&(n.callback=function(){ps(0,t),"function"!=typeof r&&(null===Wl?Wl=new Set([this]):Wl.add(this));var e=t.stack;this.componentDidCatch(t.value,{componentStack:null!==e?e:""})}),n}function gs(e,t,n){var r=e.pingCache;if(null===r){r=e.pingCache=new fs;var a=new Set;r.set(t,a)}else void 0===(a=r.get(t))&&(a=new Set,r.set(t,a));a.has(n)||(a.add(n),e=Cc.bind(null,e,t,n),t.then(e,e))}function vs(e){do{var t;if((t=13===e.tag)&&(t=null===(t=e.memoizedState)||null!==t.dehydrated),t)return e;e=e.return}while(null!==e);return null}function ys(e,t,n,r,a){return 0==(1&e.mode)?(e===t?e.flags|=65536:(e.flags|=128,n.flags|=131072,n.flags&=-52805,1===n.tag&&(null===n.alternate?n.tag=17:((t=Oi(-1,1)).tag=2,Ri(n,t,1))),n.lanes|=1),e):(e.flags|=65536,e.lanes=a,e)}var bs=w.ReactCurrentOwner,ws=!1;function ks(e,t,n,r){t.child=null===e?Ki(t,null,n,r):Qi(t,e.child,n,r)}function xs(e,t,n,r,a){n=n.render;var i=t.ref;return _i(t,a),r=_o(e,t,n,r,i,a),n=Eo(),null===e||ws?(ai&&n&&ei(t),t.flags|=1,ks(e,t,r,a),t.child):(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~a,qs(e,t,a))}function Ss(e,t,n,r,a){if(null===e){var i=n.type;return"function"!=typeof i||Oc(i)||void 0!==i.defaultProps||null!==n.compare||void 0!==n.defaultProps?((e=Ic(n.type,null,r,t,t.mode,a)).ref=t.ref,e.return=t,t.child=e):(t.tag=15,t.type=i,_s(e,t,i,r,a))}if(i=e.child,0==(e.lanes&a)){var o=i.memoizedProps;if((n=null!==(n=n.compare)?n:lr)(o,r)&&e.ref===t.ref)return qs(e,t,a)}return t.flags|=1,(e=Rc(i,r)).ref=t.ref,e.return=t,t.child=e}function _s(e,t,n,r,a){if(null!==e){var i=e.memoizedProps;if(lr(i,r)&&e.ref===t.ref){if(ws=!1,t.pendingProps=r=i,0==(e.lanes&a))return t.lanes=e.lanes,qs(e,t,a);0!=(131072&e.flags)&&(ws=!0)}}return Ts(e,t,n,r,a)}function Es(e,t,n){var r=t.pendingProps,a=r.children,i=null!==e?e.memoizedState:null;if("hidden"===r.mode)if(0==(1&t.mode))t.memoizedState={baseLanes:0,cachePool:null,transitions:null},Ca(Rl,Ol),Ol|=n;else{if(0==(1073741824&n))return e=null!==i?i.baseLanes|n:n,t.lanes=t.childLanes=1073741824,t.memoizedState={baseLanes:e,cachePool:null,transitions:null},t.updateQueue=null,Ca(Rl,Ol),Ol|=e,null;t.memoizedState={baseLanes:0,cachePool:null,transitions:null},r=null!==i?i.baseLanes:n,Ca(Rl,Ol),Ol|=r}else null!==i?(r=i.baseLanes|n,t.memoizedState=null):r=n,Ca(Rl,Ol),Ol|=r;return ks(e,t,a,n),t.child}function Cs(e,t){var n=t.ref;(null===e&&null!==n||null!==e&&e.ref!==n)&&(t.flags|=512,t.flags|=2097152)}function Ts(e,t,n,r,a){var i=Pa(n)?La:ja.current;return i=Aa(t,i),_i(t,a),n=_o(e,t,n,r,i,a),r=Eo(),null===e||ws?(ai&&r&&ei(t),t.flags|=1,ks(e,t,n,a),t.child):(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~a,qs(e,t,a))}function js(e,t,n,r,a){if(Pa(n)){var i=!0;Fa(t)}else i=!1;if(_i(t,a),null===t.stateNode)Hs(e,t),Zi(t,n,r),qi(t,n,r,a),r=!0;else if(null===e){var o=t.stateNode,s=t.memoizedProps;o.props=s;var l=o.context,c=n.contextType;"object"==typeof c&&null!==c?c=Ei(c):c=Aa(t,c=Pa(n)?La:ja.current);var u=n.getDerivedStateFromProps,d="function"==typeof u||"function"==typeof o.getSnapshotBeforeUpdate;d||"function"!=typeof o.UNSAFE_componentWillReceiveProps&&"function"!=typeof o.componentWillReceiveProps||(s!==r||l!==c)&&Hi(t,o,r,c),Li=!1;var p=t.memoizedState;o.state=p,Di(t,r,o,a),l=t.memoizedState,s!==r||p!==l||Na.current||Li?("function"==typeof u&&(Bi(t,n,u,r),l=t.memoizedState),(s=Li||Ui(t,n,s,r,p,l,c))?(d||"function"!=typeof o.UNSAFE_componentWillMount&&"function"!=typeof o.componentWillMount||("function"==typeof o.componentWillMount&&o.componentWillMount(),"function"==typeof o.UNSAFE_componentWillMount&&o.UNSAFE_componentWillMount()),"function"==typeof o.componentDidMount&&(t.flags|=4194308)):("function"==typeof o.componentDidMount&&(t.flags|=4194308),t.memoizedProps=r,t.memoizedState=l),o.props=r,o.state=l,o.context=c,r=s):("function"==typeof o.componentDidMount&&(t.flags|=4194308),r=!1)}else{o=t.stateNode,Pi(e,t),s=t.memoizedProps,c=t.type===t.elementType?s:gi(t.type,s),o.props=c,d=t.pendingProps,p=o.context,"object"==typeof(l=n.contextType)&&null!==l?l=Ei(l):l=Aa(t,l=Pa(n)?La:ja.current);var f=n.getDerivedStateFromProps;(u="function"==typeof f||"function"==typeof o.getSnapshotBeforeUpdate)||"function"!=typeof o.UNSAFE_componentWillReceiveProps&&"function"!=typeof o.componentWillReceiveProps||(s!==d||p!==l)&&Hi(t,o,r,l),Li=!1,p=t.memoizedState,o.state=p,Di(t,r,o,a);var h=t.memoizedState;s!==d||p!==h||Na.current||Li?("function"==typeof f&&(Bi(t,n,f,r),h=t.memoizedState),(c=Li||Ui(t,n,c,r,p,h,l)||!1)?(u||"function"!=typeof o.UNSAFE_componentWillUpdate&&"function"!=typeof o.componentWillUpdate||("function"==typeof o.componentWillUpdate&&o.componentWillUpdate(r,h,l),"function"==typeof o.UNSAFE_componentWillUpdate&&o.UNSAFE_componentWillUpdate(r,h,l)),"function"==typeof o.componentDidUpdate&&(t.flags|=4),"function"==typeof o.getSnapshotBeforeUpdate&&(t.flags|=1024)):("function"!=typeof o.componentDidUpdate||s===e.memoizedProps&&p===e.memoizedState||(t.flags|=4),"function"!=typeof o.getSnapshotBeforeUpdate||s===e.memoizedProps&&p===e.memoizedState||(t.flags|=1024),t.memoizedProps=r,t.memoizedState=h),o.props=r,o.state=h,o.context=l,r=c):("function"!=typeof o.componentDidUpdate||s===e.memoizedProps&&p===e.memoizedState||(t.flags|=4),"function"!=typeof o.getSnapshotBeforeUpdate||s===e.memoizedProps&&p===e.memoizedState||(t.flags|=1024),r=!1)}return Ns(e,t,n,r,i,a)}function Ns(e,t,n,r,a,i){Cs(e,t);var o=0!=(128&t.flags);if(!r&&!o)return a&&Da(t,n,!1),qs(e,t,i);r=t.stateNode,bs.current=t;var s=o&&"function"!=typeof n.getDerivedStateFromError?null:r.render();return t.flags|=1,null!==e&&o?(t.child=Qi(t,e.child,null,i),t.child=Qi(t,null,s,i)):ks(e,t,s,i),t.memoizedState=r.state,a&&Da(t,n,!0),t.child}function Ls(e){var t=e.stateNode;t.pendingContext?Ra(0,t.pendingContext,t.pendingContext!==t.context):t.context&&Ra(0,t.context,!1),ro(e,t.containerInfo)}function As(e,t,n,r,a){return fi(),hi(a),t.flags|=256,ks(e,t,n,r),t.child}var Ps,Os,Rs,Is,Fs={dehydrated:null,treeContext:null,retryLane:0};function Ds(e){return{baseLanes:e,cachePool:null,transitions:null}}function Ms(e,t,n){var r,a=t.pendingProps,o=so.current,s=!1,l=0!=(128&t.flags);if((r=l)||(r=(null===e||null!==e.memoizedState)&&0!=(2&o)),r?(s=!0,t.flags&=-129):null!==e&&null===e.memoizedState||(o|=1),Ca(so,1&o),null===e)return ci(t),null!==(e=t.memoizedState)&&null!==(e=e.dehydrated)?(0==(1&t.mode)?t.lanes=1:"$!"===e.data?t.lanes=8:t.lanes=1073741824,null):(l=a.children,e=a.fallback,s?(a=t.mode,s=t.child,l={mode:"hidden",children:l},0==(1&a)&&null!==s?(s.childLanes=0,s.pendingProps=l):s=Dc(l,a,0,null),e=Fc(e,a,n,null),s.return=t,e.return=t,s.sibling=e,t.child=s,t.child.memoizedState=Ds(n),t.memoizedState=Fs,e):zs(t,l));if(null!==(o=e.memoizedState)&&null!==(r=o.dehydrated))return function(e,t,n,r,a,o,s){if(n)return 256&t.flags?(t.flags&=-257,Bs(e,t,s,r=ds(Error(i(422))))):null!==t.memoizedState?(t.child=e.child,t.flags|=128,null):(o=r.fallback,a=t.mode,r=Dc({mode:"visible",children:r.children},a,0,null),(o=Fc(o,a,s,null)).flags|=2,r.return=t,o.return=t,r.sibling=o,t.child=r,0!=(1&t.mode)&&Qi(t,e.child,null,s),t.child.memoizedState=Ds(s),t.memoizedState=Fs,o);if(0==(1&t.mode))return Bs(e,t,s,null);if("$!"===a.data){if(r=a.nextSibling&&a.nextSibling.dataset)var l=r.dgst;return r=l,Bs(e,t,s,r=ds(o=Error(i(419)),r,void 0))}if(l=0!=(s&e.childLanes),ws||l){if(null!==(r=Ll)){switch(s&-s){case 4:a=2;break;case 16:a=8;break;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:a=32;break;case 536870912:a=268435456;break;default:a=0}0!==(a=0!=(a&(r.suspendedLanes|s))?0:a)&&a!==o.retryLane&&(o.retryLane=a,Ni(e,a),rc(r,e,a,-1))}return gc(),Bs(e,t,s,r=ds(Error(i(421))))}return"$?"===a.data?(t.flags|=128,t.child=e.child,t=jc.bind(null,e),a._reactRetry=t,null):(e=o.treeContext,ri=ca(a.nextSibling),ni=t,ai=!0,ii=null,null!==e&&(Wa[Ga++]=Qa,Wa[Ga++]=Ka,Wa[Ga++]=Ya,Qa=e.id,Ka=e.overflow,Ya=t),t=zs(t,r.children),t.flags|=4096,t)}(e,t,l,a,r,o,n);if(s){s=a.fallback,l=t.mode,r=(o=e.child).sibling;var c={mode:"hidden",children:a.children};return 0==(1&l)&&t.child!==o?((a=t.child).childLanes=0,a.pendingProps=c,t.deletions=null):(a=Rc(o,c)).subtreeFlags=14680064&o.subtreeFlags,null!==r?s=Rc(r,s):(s=Fc(s,l,n,null)).flags|=2,s.return=t,a.return=t,a.sibling=s,t.child=a,a=s,s=t.child,l=null===(l=e.child.memoizedState)?Ds(n):{baseLanes:l.baseLanes|n,cachePool:null,transitions:l.transitions},s.memoizedState=l,s.childLanes=e.childLanes&~n,t.memoizedState=Fs,a}return e=(s=e.child).sibling,a=Rc(s,{mode:"visible",children:a.children}),0==(1&t.mode)&&(a.lanes=n),a.return=t,a.sibling=null,null!==e&&(null===(n=t.deletions)?(t.deletions=[e],t.flags|=16):n.push(e)),t.child=a,t.memoizedState=null,a}function zs(e,t){return(t=Dc({mode:"visible",children:t},e.mode,0,null)).return=e,e.child=t}function Bs(e,t,n,r){return null!==r&&hi(r),Qi(t,e.child,null,n),(e=zs(t,t.pendingProps.children)).flags|=2,t.memoizedState=null,e}function $s(e,t,n){e.lanes|=t;var r=e.alternate;null!==r&&(r.lanes|=t),Si(e.return,t,n)}function Us(e,t,n,r,a){var i=e.memoizedState;null===i?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:r,tail:n,tailMode:a}:(i.isBackwards=t,i.rendering=null,i.renderingStartTime=0,i.last=r,i.tail=n,i.tailMode=a)}function Zs(e,t,n){var r=t.pendingProps,a=r.revealOrder,i=r.tail;if(ks(e,t,r.children,n),0!=(2&(r=so.current)))r=1&r|2,t.flags|=128;else{if(null!==e&&0!=(128&e.flags))e:for(e=t.child;null!==e;){if(13===e.tag)null!==e.memoizedState&&$s(e,n,t);else if(19===e.tag)$s(e,n,t);else if(null!==e.child){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;null===e.sibling;){if(null===e.return||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}if(Ca(so,r),0==(1&t.mode))t.memoizedState=null;else switch(a){case"forwards":for(n=t.child,a=null;null!==n;)null!==(e=n.alternate)&&null===lo(e)&&(a=n),n=n.sibling;null===(n=a)?(a=t.child,t.child=null):(a=n.sibling,n.sibling=null),Us(t,!1,a,n,i);break;case"backwards":for(n=null,a=t.child,t.child=null;null!==a;){if(null!==(e=a.alternate)&&null===lo(e)){t.child=a;break}e=a.sibling,a.sibling=n,n=a,a=e}Us(t,!0,n,null,i);break;case"together":Us(t,!1,null,null,void 0);break;default:t.memoizedState=null}return t.child}function Hs(e,t){0==(1&t.mode)&&null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2)}function qs(e,t,n){if(null!==e&&(t.dependencies=e.dependencies),Dl|=t.lanes,0==(n&t.childLanes))return null;if(null!==e&&t.child!==e.child)throw Error(i(153));if(null!==t.child){for(n=Rc(e=t.child,e.pendingProps),t.child=n,n.return=t;null!==e.sibling;)e=e.sibling,(n=n.sibling=Rc(e,e.pendingProps)).return=t;n.sibling=null}return t.child}function Vs(e,t){if(!ai)switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;null!==t;)null!==t.alternate&&(n=t),t=t.sibling;null===n?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var r=null;null!==n;)null!==n.alternate&&(r=n),n=n.sibling;null===r?t||null===e.tail?e.tail=null:e.tail.sibling=null:r.sibling=null}}function Ws(e){var t=null!==e.alternate&&e.alternate.child===e.child,n=0,r=0;if(t)for(var a=e.child;null!==a;)n|=a.lanes|a.childLanes,r|=14680064&a.subtreeFlags,r|=14680064&a.flags,a.return=e,a=a.sibling;else for(a=e.child;null!==a;)n|=a.lanes|a.childLanes,r|=a.subtreeFlags,r|=a.flags,a.return=e,a=a.sibling;return e.subtreeFlags|=r,e.childLanes=n,t}function Gs(e,t,n){var r=t.pendingProps;switch(ti(t),t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return Ws(t),null;case 1:case 17:return Pa(t.type)&&Oa(),Ws(t),null;case 3:return r=t.stateNode,ao(),Ea(Na),Ea(ja),uo(),r.pendingContext&&(r.context=r.pendingContext,r.pendingContext=null),null!==e&&null!==e.child||(di(t)?t.flags|=4:null===e||e.memoizedState.isDehydrated&&0==(256&t.flags)||(t.flags|=1024,null!==ii&&(sc(ii),ii=null))),Os(e,t),Ws(t),null;case 5:oo(t);var a=no(to.current);if(n=t.type,null!==e&&null!=t.stateNode)Rs(e,t,n,r,a),e.ref!==t.ref&&(t.flags|=512,t.flags|=2097152);else{if(!r){if(null===t.stateNode)throw Error(i(166));return Ws(t),null}if(e=no(Ji.current),di(t)){r=t.stateNode,n=t.type;var o=t.memoizedProps;switch(r[pa]=t,r[fa]=o,e=0!=(1&t.mode),n){case"dialog":zr("cancel",r),zr("close",r);break;case"iframe":case"object":case"embed":zr("load",r);break;case"video":case"audio":for(a=0;a<Ir.length;a++)zr(Ir[a],r);break;case"source":zr("error",r);break;case"img":case"image":case"link":zr("error",r),zr("load",r);break;case"details":zr("toggle",r);break;case"input":Q(r,o),zr("invalid",r);break;case"select":r._wrapperState={wasMultiple:!!o.multiple},zr("invalid",r);break;case"textarea":ae(r,o),zr("invalid",r)}for(var l in ye(n,o),a=null,o)if(o.hasOwnProperty(l)){var c=o[l];"children"===l?"string"==typeof c?r.textContent!==c&&(!0!==o.suppressHydrationWarning&&Xr(r.textContent,c,e),a=["children",c]):"number"==typeof c&&r.textContent!==""+c&&(!0!==o.suppressHydrationWarning&&Xr(r.textContent,c,e),a=["children",""+c]):s.hasOwnProperty(l)&&null!=c&&"onScroll"===l&&zr("scroll",r)}switch(n){case"input":V(r),J(r,o,!0);break;case"textarea":V(r),oe(r);break;case"select":case"option":break;default:"function"==typeof o.onClick&&(r.onclick=Jr)}r=a,t.updateQueue=r,null!==r&&(t.flags|=4)}else{l=9===a.nodeType?a:a.ownerDocument,"http://www.w3.org/1999/xhtml"===e&&(e=se(n)),"http://www.w3.org/1999/xhtml"===e?"script"===n?((e=l.createElement("div")).innerHTML="<script><\/script>",e=e.removeChild(e.firstChild)):"string"==typeof r.is?e=l.createElement(n,{is:r.is}):(e=l.createElement(n),"select"===n&&(l=e,r.multiple?l.multiple=!0:r.size&&(l.size=r.size))):e=l.createElementNS(e,n),e[pa]=t,e[fa]=r,Ps(e,t,!1,!1),t.stateNode=e;e:{switch(l=be(n,r),n){case"dialog":zr("cancel",e),zr("close",e),a=r;break;case"iframe":case"object":case"embed":zr("load",e),a=r;break;case"video":case"audio":for(a=0;a<Ir.length;a++)zr(Ir[a],e);a=r;break;case"source":zr("error",e),a=r;break;case"img":case"image":case"link":zr("error",e),zr("load",e),a=r;break;case"details":zr("toggle",e),a=r;break;case"input":Q(e,r),a=Y(e,r),zr("invalid",e);break;case"option":default:a=r;break;case"select":e._wrapperState={wasMultiple:!!r.multiple},a=D({},r,{value:void 0}),zr("invalid",e);break;case"textarea":ae(e,r),a=re(e,r),zr("invalid",e)}for(o in ye(n,a),c=a)if(c.hasOwnProperty(o)){var u=c[o];"style"===o?ge(e,u):"dangerouslySetInnerHTML"===o?null!=(u=u?u.__html:void 0)&&de(e,u):"children"===o?"string"==typeof u?("textarea"!==n||""!==u)&&pe(e,u):"number"==typeof u&&pe(e,""+u):"suppressContentEditableWarning"!==o&&"suppressHydrationWarning"!==o&&"autoFocus"!==o&&(s.hasOwnProperty(o)?null!=u&&"onScroll"===o&&zr("scroll",e):null!=u&&b(e,o,u,l))}switch(n){case"input":V(e),J(e,r,!1);break;case"textarea":V(e),oe(e);break;case"option":null!=r.value&&e.setAttribute("value",""+H(r.value));break;case"select":e.multiple=!!r.multiple,null!=(o=r.value)?ne(e,!!r.multiple,o,!1):null!=r.defaultValue&&ne(e,!!r.multiple,r.defaultValue,!0);break;default:"function"==typeof a.onClick&&(e.onclick=Jr)}switch(n){case"button":case"input":case"select":case"textarea":r=!!r.autoFocus;break e;case"img":r=!0;break e;default:r=!1}}r&&(t.flags|=4)}null!==t.ref&&(t.flags|=512,t.flags|=2097152)}return Ws(t),null;case 6:if(e&&null!=t.stateNode)Is(e,t,e.memoizedProps,r);else{if("string"!=typeof r&&null===t.stateNode)throw Error(i(166));if(n=no(to.current),no(Ji.current),di(t)){if(r=t.stateNode,n=t.memoizedProps,r[pa]=t,(o=r.nodeValue!==n)&&null!==(e=ni))switch(e.tag){case 3:Xr(r.nodeValue,n,0!=(1&e.mode));break;case 5:!0!==e.memoizedProps.suppressHydrationWarning&&Xr(r.nodeValue,n,0!=(1&e.mode))}o&&(t.flags|=4)}else(r=(9===n.nodeType?n:n.ownerDocument).createTextNode(r))[pa]=t,t.stateNode=r}return Ws(t),null;case 13:if(Ea(so),r=t.memoizedState,null===e||null!==e.memoizedState&&null!==e.memoizedState.dehydrated){if(ai&&null!==ri&&0!=(1&t.mode)&&0==(128&t.flags))pi(),fi(),t.flags|=98560,o=!1;else if(o=di(t),null!==r&&null!==r.dehydrated){if(null===e){if(!o)throw Error(i(318));if(!(o=null!==(o=t.memoizedState)?o.dehydrated:null))throw Error(i(317));o[pa]=t}else fi(),0==(128&t.flags)&&(t.memoizedState=null),t.flags|=4;Ws(t),o=!1}else null!==ii&&(sc(ii),ii=null),o=!0;if(!o)return 65536&t.flags?t:null}return 0!=(128&t.flags)?(t.lanes=n,t):((r=null!==r)!==(null!==e&&null!==e.memoizedState)&&r&&(t.child.flags|=8192,0!=(1&t.mode)&&(null===e||0!=(1&so.current)?0===Il&&(Il=3):gc())),null!==t.updateQueue&&(t.flags|=4),Ws(t),null);case 4:return ao(),Os(e,t),null===e&&Ur(t.stateNode.containerInfo),Ws(t),null;case 10:return xi(t.type._context),Ws(t),null;case 19:if(Ea(so),null===(o=t.memoizedState))return Ws(t),null;if(r=0!=(128&t.flags),null===(l=o.rendering))if(r)Vs(o,!1);else{if(0!==Il||null!==e&&0!=(128&e.flags))for(e=t.child;null!==e;){if(null!==(l=lo(e))){for(t.flags|=128,Vs(o,!1),null!==(r=l.updateQueue)&&(t.updateQueue=r,t.flags|=4),t.subtreeFlags=0,r=n,n=t.child;null!==n;)e=r,(o=n).flags&=14680066,null===(l=o.alternate)?(o.childLanes=0,o.lanes=e,o.child=null,o.subtreeFlags=0,o.memoizedProps=null,o.memoizedState=null,o.updateQueue=null,o.dependencies=null,o.stateNode=null):(o.childLanes=l.childLanes,o.lanes=l.lanes,o.child=l.child,o.subtreeFlags=0,o.deletions=null,o.memoizedProps=l.memoizedProps,o.memoizedState=l.memoizedState,o.updateQueue=l.updateQueue,o.type=l.type,e=l.dependencies,o.dependencies=null===e?null:{lanes:e.lanes,firstContext:e.firstContext}),n=n.sibling;return Ca(so,1&so.current|2),t.child}e=e.sibling}null!==o.tail&&Ke()>Zl&&(t.flags|=128,r=!0,Vs(o,!1),t.lanes=4194304)}else{if(!r)if(null!==(e=lo(l))){if(t.flags|=128,r=!0,null!==(n=e.updateQueue)&&(t.updateQueue=n,t.flags|=4),Vs(o,!0),null===o.tail&&"hidden"===o.tailMode&&!l.alternate&&!ai)return Ws(t),null}else 2*Ke()-o.renderingStartTime>Zl&&1073741824!==n&&(t.flags|=128,r=!0,Vs(o,!1),t.lanes=4194304);o.isBackwards?(l.sibling=t.child,t.child=l):(null!==(n=o.last)?n.sibling=l:t.child=l,o.last=l)}return null!==o.tail?(t=o.tail,o.rendering=t,o.tail=t.sibling,o.renderingStartTime=Ke(),t.sibling=null,n=so.current,Ca(so,r?1&n|2:1&n),t):(Ws(t),null);case 22:case 23:return pc(),r=null!==t.memoizedState,null!==e&&null!==e.memoizedState!==r&&(t.flags|=8192),r&&0!=(1&t.mode)?0!=(1073741824&Ol)&&(Ws(t),6&t.subtreeFlags&&(t.flags|=8192)):Ws(t),null;case 24:case 25:return null}throw Error(i(156,t.tag))}function Ys(e,t){switch(ti(t),t.tag){case 1:return Pa(t.type)&&Oa(),65536&(e=t.flags)?(t.flags=-65537&e|128,t):null;case 3:return ao(),Ea(Na),Ea(ja),uo(),0!=(65536&(e=t.flags))&&0==(128&e)?(t.flags=-65537&e|128,t):null;case 5:return oo(t),null;case 13:if(Ea(so),null!==(e=t.memoizedState)&&null!==e.dehydrated){if(null===t.alternate)throw Error(i(340));fi()}return 65536&(e=t.flags)?(t.flags=-65537&e|128,t):null;case 19:return Ea(so),null;case 4:return ao(),null;case 10:return xi(t.type._context),null;case 22:case 23:return pc(),null;default:return null}}Ps=function(e,t){for(var n=t.child;null!==n;){if(5===n.tag||6===n.tag)e.appendChild(n.stateNode);else if(4!==n.tag&&null!==n.child){n.child.return=n,n=n.child;continue}if(n===t)break;for(;null===n.sibling;){if(null===n.return||n.return===t)return;n=n.return}n.sibling.return=n.return,n=n.sibling}},Os=function(){},Rs=function(e,t,n,r){var a=e.memoizedProps;if(a!==r){e=t.stateNode,no(Ji.current);var i,o=null;switch(n){case"input":a=Y(e,a),r=Y(e,r),o=[];break;case"select":a=D({},a,{value:void 0}),r=D({},r,{value:void 0}),o=[];break;case"textarea":a=re(e,a),r=re(e,r),o=[];break;default:"function"!=typeof a.onClick&&"function"==typeof r.onClick&&(e.onclick=Jr)}for(u in ye(n,r),n=null,a)if(!r.hasOwnProperty(u)&&a.hasOwnProperty(u)&&null!=a[u])if("style"===u){var l=a[u];for(i in l)l.hasOwnProperty(i)&&(n||(n={}),n[i]="")}else"dangerouslySetInnerHTML"!==u&&"children"!==u&&"suppressContentEditableWarning"!==u&&"suppressHydrationWarning"!==u&&"autoFocus"!==u&&(s.hasOwnProperty(u)?o||(o=[]):(o=o||[]).push(u,null));for(u in r){var c=r[u];if(l=null!=a?a[u]:void 0,r.hasOwnProperty(u)&&c!==l&&(null!=c||null!=l))if("style"===u)if(l){for(i in l)!l.hasOwnProperty(i)||c&&c.hasOwnProperty(i)||(n||(n={}),n[i]="");for(i in c)c.hasOwnProperty(i)&&l[i]!==c[i]&&(n||(n={}),n[i]=c[i])}else n||(o||(o=[]),o.push(u,n)),n=c;else"dangerouslySetInnerHTML"===u?(c=c?c.__html:void 0,l=l?l.__html:void 0,null!=c&&l!==c&&(o=o||[]).push(u,c)):"children"===u?"string"!=typeof c&&"number"!=typeof c||(o=o||[]).push(u,""+c):"suppressContentEditableWarning"!==u&&"suppressHydrationWarning"!==u&&(s.hasOwnProperty(u)?(null!=c&&"onScroll"===u&&zr("scroll",e),o||l===c||(o=[])):(o=o||[]).push(u,c))}n&&(o=o||[]).push("style",n);var u=o;(t.updateQueue=u)&&(t.flags|=4)}},Is=function(e,t,n,r){n!==r&&(t.flags|=4)};var Qs=!1,Ks=!1,Xs="function"==typeof WeakSet?WeakSet:Set,Js=null;function el(e,t){var n=e.ref;if(null!==n)if("function"==typeof n)try{n(null)}catch(r){Ec(e,t,r)}else n.current=null}function tl(e,t,n){try{n()}catch(r){Ec(e,t,r)}}var nl=!1;function rl(e,t,n){var r=t.updateQueue;if(null!==(r=null!==r?r.lastEffect:null)){var a=r=r.next;do{if((a.tag&e)===e){var i=a.destroy;a.destroy=void 0,void 0!==i&&tl(t,n,i)}a=a.next}while(a!==r)}}function al(e,t){if(null!==(t=null!==(t=t.updateQueue)?t.lastEffect:null)){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function il(e){var t=e.ref;if(null!==t){var n=e.stateNode;e.tag,e=n,"function"==typeof t?t(e):t.current=e}}function ol(e){var t=e.alternate;null!==t&&(e.alternate=null,ol(t)),e.child=null,e.deletions=null,e.sibling=null,5===e.tag&&(null!==(t=e.stateNode)&&(delete t[pa],delete t[fa],delete t[ma],delete t[ga],delete t[va])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function sl(e){return 5===e.tag||3===e.tag||4===e.tag}function ll(e){e:for(;;){for(;null===e.sibling;){if(null===e.return||sl(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;5!==e.tag&&6!==e.tag&&18!==e.tag;){if(2&e.flags)continue e;if(null===e.child||4===e.tag)continue e;e.child.return=e,e=e.child}if(!(2&e.flags))return e.stateNode}}function cl(e,t,n){var r=e.tag;if(5===r||6===r)e=e.stateNode,t?8===n.nodeType?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(8===n.nodeType?(t=n.parentNode).insertBefore(e,n):(t=n).appendChild(e),null!=(n=n._reactRootContainer)||null!==t.onclick||(t.onclick=Jr));else if(4!==r&&null!==(e=e.child))for(cl(e,t,n),e=e.sibling;null!==e;)cl(e,t,n),e=e.sibling}function ul(e,t,n){var r=e.tag;if(5===r||6===r)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(4!==r&&null!==(e=e.child))for(ul(e,t,n),e=e.sibling;null!==e;)ul(e,t,n),e=e.sibling}var dl=null,pl=!1;function fl(e,t,n){for(n=n.child;null!==n;)hl(e,t,n),n=n.sibling}function hl(e,t,n){if(it&&"function"==typeof it.onCommitFiberUnmount)try{it.onCommitFiberUnmount(at,n)}catch(s){}switch(n.tag){case 5:Ks||el(n,t);case 6:var r=dl,a=pl;dl=null,fl(e,t,n),pl=a,null!==(dl=r)&&(pl?(e=dl,n=n.stateNode,8===e.nodeType?e.parentNode.removeChild(n):e.removeChild(n)):dl.removeChild(n.stateNode));break;case 18:null!==dl&&(pl?(e=dl,n=n.stateNode,8===e.nodeType?la(e.parentNode,n):1===e.nodeType&&la(e,n),Ut(e)):la(dl,n.stateNode));break;case 4:r=dl,a=pl,dl=n.stateNode.containerInfo,pl=!0,fl(e,t,n),dl=r,pl=a;break;case 0:case 11:case 14:case 15:if(!Ks&&(null!==(r=n.updateQueue)&&null!==(r=r.lastEffect))){a=r=r.next;do{var i=a,o=i.destroy;i=i.tag,void 0!==o&&(0!=(2&i)||0!=(4&i))&&tl(n,t,o),a=a.next}while(a!==r)}fl(e,t,n);break;case 1:if(!Ks&&(el(n,t),"function"==typeof(r=n.stateNode).componentWillUnmount))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(s){Ec(n,t,s)}fl(e,t,n);break;case 21:fl(e,t,n);break;case 22:1&n.mode?(Ks=(r=Ks)||null!==n.memoizedState,fl(e,t,n),Ks=r):fl(e,t,n);break;default:fl(e,t,n)}}function ml(e){var t=e.updateQueue;if(null!==t){e.updateQueue=null;var n=e.stateNode;null===n&&(n=e.stateNode=new Xs),t.forEach((function(t){var r=Nc.bind(null,e,t);n.has(t)||(n.add(t),t.then(r,r))}))}}function gl(e,t){var n=t.deletions;if(null!==n)for(var r=0;r<n.length;r++){var a=n[r];try{var o=e,s=t,l=s;e:for(;null!==l;){switch(l.tag){case 5:dl=l.stateNode,pl=!1;break e;case 3:case 4:dl=l.stateNode.containerInfo,pl=!0;break e}l=l.return}if(null===dl)throw Error(i(160));hl(o,s,a),dl=null,pl=!1;var c=a.alternate;null!==c&&(c.return=null),a.return=null}catch(u){Ec(a,t,u)}}if(12854&t.subtreeFlags)for(t=t.child;null!==t;)vl(t,e),t=t.sibling}function vl(e,t){var n=e.alternate,r=e.flags;switch(e.tag){case 0:case 11:case 14:case 15:if(gl(t,e),yl(e),4&r){try{rl(3,e,e.return),al(3,e)}catch(g){Ec(e,e.return,g)}try{rl(5,e,e.return)}catch(g){Ec(e,e.return,g)}}break;case 1:gl(t,e),yl(e),512&r&&null!==n&&el(n,n.return);break;case 5:if(gl(t,e),yl(e),512&r&&null!==n&&el(n,n.return),32&e.flags){var a=e.stateNode;try{pe(a,"")}catch(g){Ec(e,e.return,g)}}if(4&r&&null!=(a=e.stateNode)){var o=e.memoizedProps,s=null!==n?n.memoizedProps:o,l=e.type,c=e.updateQueue;if(e.updateQueue=null,null!==c)try{"input"===l&&"radio"===o.type&&null!=o.name&&K(a,o),be(l,s);var u=be(l,o);for(s=0;s<c.length;s+=2){var d=c[s],p=c[s+1];"style"===d?ge(a,p):"dangerouslySetInnerHTML"===d?de(a,p):"children"===d?pe(a,p):b(a,d,p,u)}switch(l){case"input":X(a,o);break;case"textarea":ie(a,o);break;case"select":var f=a._wrapperState.wasMultiple;a._wrapperState.wasMultiple=!!o.multiple;var h=o.value;null!=h?ne(a,!!o.multiple,h,!1):f!==!!o.multiple&&(null!=o.defaultValue?ne(a,!!o.multiple,o.defaultValue,!0):ne(a,!!o.multiple,o.multiple?[]:"",!1))}a[fa]=o}catch(g){Ec(e,e.return,g)}}break;case 6:if(gl(t,e),yl(e),4&r){if(null===e.stateNode)throw Error(i(162));a=e.stateNode,o=e.memoizedProps;try{a.nodeValue=o}catch(g){Ec(e,e.return,g)}}break;case 3:if(gl(t,e),yl(e),4&r&&null!==n&&n.memoizedState.isDehydrated)try{Ut(t.containerInfo)}catch(g){Ec(e,e.return,g)}break;case 4:default:gl(t,e),yl(e);break;case 13:gl(t,e),yl(e),8192&(a=e.child).flags&&(o=null!==a.memoizedState,a.stateNode.isHidden=o,!o||null!==a.alternate&&null!==a.alternate.memoizedState||(Ul=Ke())),4&r&&ml(e);break;case 22:if(d=null!==n&&null!==n.memoizedState,1&e.mode?(Ks=(u=Ks)||d,gl(t,e),Ks=u):gl(t,e),yl(e),8192&r){if(u=null!==e.memoizedState,(e.stateNode.isHidden=u)&&!d&&0!=(1&e.mode))for(Js=e,d=e.child;null!==d;){for(p=Js=d;null!==Js;){switch(h=(f=Js).child,f.tag){case 0:case 11:case 14:case 15:rl(4,f,f.return);break;case 1:el(f,f.return);var m=f.stateNode;if("function"==typeof m.componentWillUnmount){r=f,n=f.return;try{t=r,m.props=t.memoizedProps,m.state=t.memoizedState,m.componentWillUnmount()}catch(g){Ec(r,n,g)}}break;case 5:el(f,f.return);break;case 22:if(null!==f.memoizedState){xl(p);continue}}null!==h?(h.return=f,Js=h):xl(p)}d=d.sibling}e:for(d=null,p=e;;){if(5===p.tag){if(null===d){d=p;try{a=p.stateNode,u?"function"==typeof(o=a.style).setProperty?o.setProperty("display","none","important"):o.display="none":(l=p.stateNode,s=null!=(c=p.memoizedProps.style)&&c.hasOwnProperty("display")?c.display:null,l.style.display=me("display",s))}catch(g){Ec(e,e.return,g)}}}else if(6===p.tag){if(null===d)try{p.stateNode.nodeValue=u?"":p.memoizedProps}catch(g){Ec(e,e.return,g)}}else if((22!==p.tag&&23!==p.tag||null===p.memoizedState||p===e)&&null!==p.child){p.child.return=p,p=p.child;continue}if(p===e)break e;for(;null===p.sibling;){if(null===p.return||p.return===e)break e;d===p&&(d=null),p=p.return}d===p&&(d=null),p.sibling.return=p.return,p=p.sibling}}break;case 19:gl(t,e),yl(e),4&r&&ml(e);case 21:}}function yl(e){var t=e.flags;if(2&t){try{e:{for(var n=e.return;null!==n;){if(sl(n)){var r=n;break e}n=n.return}throw Error(i(160))}switch(r.tag){case 5:var a=r.stateNode;32&r.flags&&(pe(a,""),r.flags&=-33),ul(e,ll(e),a);break;case 3:case 4:var o=r.stateNode.containerInfo;cl(e,ll(e),o);break;default:throw Error(i(161))}}catch(s){Ec(e,e.return,s)}e.flags&=-3}4096&t&&(e.flags&=-4097)}function bl(e,t,n){Js=e,wl(e,t,n)}function wl(e,t,n){for(var r=0!=(1&e.mode);null!==Js;){var a=Js,i=a.child;if(22===a.tag&&r){var o=null!==a.memoizedState||Qs;if(!o){var s=a.alternate,l=null!==s&&null!==s.memoizedState||Ks;s=Qs;var c=Ks;if(Qs=o,(Ks=l)&&!c)for(Js=a;null!==Js;)l=(o=Js).child,22===o.tag&&null!==o.memoizedState?Sl(a):null!==l?(l.return=o,Js=l):Sl(a);for(;null!==i;)Js=i,wl(i,t,n),i=i.sibling;Js=a,Qs=s,Ks=c}kl(e)}else 0!=(8772&a.subtreeFlags)&&null!==i?(i.return=a,Js=i):kl(e)}}function kl(e){for(;null!==Js;){var t=Js;if(0!=(8772&t.flags)){var n=t.alternate;try{if(0!=(8772&t.flags))switch(t.tag){case 0:case 11:case 15:Ks||al(5,t);break;case 1:var r=t.stateNode;if(4&t.flags&&!Ks)if(null===n)r.componentDidMount();else{var a=t.elementType===t.type?n.memoizedProps:gi(t.type,n.memoizedProps);r.componentDidUpdate(a,n.memoizedState,r.__reactInternalSnapshotBeforeUpdate)}var o=t.updateQueue;null!==o&&Mi(t,o,r);break;case 3:var s=t.updateQueue;if(null!==s){if(n=null,null!==t.child)switch(t.child.tag){case 5:case 1:n=t.child.stateNode}Mi(t,s,n)}break;case 5:var l=t.stateNode;if(null===n&&4&t.flags){n=l;var c=t.memoizedProps;switch(t.type){case"button":case"input":case"select":case"textarea":c.autoFocus&&n.focus();break;case"img":c.src&&(n.src=c.src)}}break;case 6:case 4:case 12:case 19:case 17:case 21:case 22:case 23:case 25:break;case 13:if(null===t.memoizedState){var u=t.alternate;if(null!==u){var d=u.memoizedState;if(null!==d){var p=d.dehydrated;null!==p&&Ut(p)}}}break;default:throw Error(i(163))}Ks||512&t.flags&&il(t)}catch(f){Ec(t,t.return,f)}}if(t===e){Js=null;break}if(null!==(n=t.sibling)){n.return=t.return,Js=n;break}Js=t.return}}function xl(e){for(;null!==Js;){var t=Js;if(t===e){Js=null;break}var n=t.sibling;if(null!==n){n.return=t.return,Js=n;break}Js=t.return}}function Sl(e){for(;null!==Js;){var t=Js;try{switch(t.tag){case 0:case 11:case 15:var n=t.return;try{al(4,t)}catch(l){Ec(t,n,l)}break;case 1:var r=t.stateNode;if("function"==typeof r.componentDidMount){var a=t.return;try{r.componentDidMount()}catch(l){Ec(t,a,l)}}var i=t.return;try{il(t)}catch(l){Ec(t,i,l)}break;case 5:var o=t.return;try{il(t)}catch(l){Ec(t,o,l)}}}catch(l){Ec(t,t.return,l)}if(t===e){Js=null;break}var s=t.sibling;if(null!==s){s.return=t.return,Js=s;break}Js=t.return}}var _l,El=Math.ceil,Cl=w.ReactCurrentDispatcher,Tl=w.ReactCurrentOwner,jl=w.ReactCurrentBatchConfig,Nl=0,Ll=null,Al=null,Pl=0,Ol=0,Rl=_a(0),Il=0,Fl=null,Dl=0,Ml=0,zl=0,Bl=null,$l=null,Ul=0,Zl=1/0,Hl=null,ql=!1,Vl=null,Wl=null,Gl=!1,Yl=null,Ql=0,Kl=0,Xl=null,Jl=-1,ec=0;function tc(){return 0!=(6&Nl)?Ke():-1!==Jl?Jl:Jl=Ke()}function nc(e){return 0==(1&e.mode)?1:0!=(2&Nl)&&0!==Pl?Pl&-Pl:null!==mi.transition?(0===ec&&(ec=mt()),ec):0!==(e=bt)?e:e=void 0===(e=window.event)?16:Qt(e.type)}function rc(e,t,n,r){if(50<Kl)throw Kl=0,Xl=null,Error(i(185));vt(e,n,r),0!=(2&Nl)&&e===Ll||(e===Ll&&(0==(2&Nl)&&(Ml|=n),4===Il&&lc(e,Pl)),ac(e,r),1===n&&0===Nl&&0==(1&t.mode)&&(Zl=Ke()+500,za&&Ua()))}function ac(e,t){var n=e.callbackNode;!function(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,a=e.expirationTimes,i=e.pendingLanes;0<i;){var o=31-ot(i),s=1<<o,l=a[o];-1===l?0!=(s&n)&&0==(s&r)||(a[o]=ft(s,t)):l<=t&&(e.expiredLanes|=s),i&=~s}}(e,t);var r=pt(e,e===Ll?Pl:0);if(0===r)null!==n&&Ge(n),e.callbackNode=null,e.callbackPriority=0;else if(t=r&-r,e.callbackPriority!==t){if(null!=n&&Ge(n),1===t)0===e.tag?function(e){za=!0,$a(e)}(cc.bind(null,e)):$a(cc.bind(null,e)),oa((function(){0==(6&Nl)&&Ua()})),n=null;else{switch(wt(r)){case 1:n=Je;break;case 4:n=et;break;case 16:default:n=tt;break;case 536870912:n=rt}n=Lc(n,ic.bind(null,e))}e.callbackPriority=t,e.callbackNode=n}}function ic(e,t){if(Jl=-1,ec=0,0!=(6&Nl))throw Error(i(327));var n=e.callbackNode;if(Sc()&&e.callbackNode!==n)return null;var r=pt(e,e===Ll?Pl:0);if(0===r)return null;if(0!=(30&r)||0!=(r&e.expiredLanes)||t)t=vc(e,r);else{t=r;var a=Nl;Nl|=2;var o=mc();for(Ll===e&&Pl===t||(Hl=null,Zl=Ke()+500,fc(e,t));;)try{bc();break}catch(l){hc(e,l)}ki(),Cl.current=o,Nl=a,null!==Al?t=0:(Ll=null,Pl=0,t=Il)}if(0!==t){if(2===t&&(0!==(a=ht(e))&&(r=a,t=oc(e,a))),1===t)throw n=Fl,fc(e,0),lc(e,r),ac(e,Ke()),n;if(6===t)lc(e,r);else{if(a=e.current.alternate,0==(30&r)&&!function(e){for(var t=e;;){if(16384&t.flags){var n=t.updateQueue;if(null!==n&&null!==(n=n.stores))for(var r=0;r<n.length;r++){var a=n[r],i=a.getSnapshot;a=a.value;try{if(!sr(i(),a))return!1}catch(s){return!1}}}if(n=t.child,16384&t.subtreeFlags&&null!==n)n.return=t,t=n;else{if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return!0;t=t.return}t.sibling.return=t.return,t=t.sibling}}return!0}(a)&&(2===(t=vc(e,r))&&(0!==(o=ht(e))&&(r=o,t=oc(e,o))),1===t))throw n=Fl,fc(e,0),lc(e,r),ac(e,Ke()),n;switch(e.finishedWork=a,e.finishedLanes=r,t){case 0:case 1:throw Error(i(345));case 2:case 5:xc(e,$l,Hl);break;case 3:if(lc(e,r),(130023424&r)===r&&10<(t=Ul+500-Ke())){if(0!==pt(e,0))break;if(((a=e.suspendedLanes)&r)!==r){tc(),e.pingedLanes|=e.suspendedLanes&a;break}e.timeoutHandle=ra(xc.bind(null,e,$l,Hl),t);break}xc(e,$l,Hl);break;case 4:if(lc(e,r),(4194240&r)===r)break;for(t=e.eventTimes,a=-1;0<r;){var s=31-ot(r);o=1<<s,(s=t[s])>a&&(a=s),r&=~o}if(r=a,10<(r=(120>(r=Ke()-r)?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*El(r/1960))-r)){e.timeoutHandle=ra(xc.bind(null,e,$l,Hl),r);break}xc(e,$l,Hl);break;default:throw Error(i(329))}}}return ac(e,Ke()),e.callbackNode===n?ic.bind(null,e):null}function oc(e,t){var n=Bl;return e.current.memoizedState.isDehydrated&&(fc(e,t).flags|=256),2!==(e=vc(e,t))&&(t=$l,$l=n,null!==t&&sc(t)),e}function sc(e){null===$l?$l=e:$l.push.apply($l,e)}function lc(e,t){for(t&=~zl,t&=~Ml,e.suspendedLanes|=t,e.pingedLanes&=~t,e=e.expirationTimes;0<t;){var n=31-ot(t),r=1<<n;e[n]=-1,t&=~r}}function cc(e){if(0!=(6&Nl))throw Error(i(327));Sc();var t=pt(e,0);if(0==(1&t))return ac(e,Ke()),null;var n=vc(e,t);if(0!==e.tag&&2===n){var r=ht(e);0!==r&&(t=r,n=oc(e,r))}if(1===n)throw n=Fl,fc(e,0),lc(e,t),ac(e,Ke()),n;if(6===n)throw Error(i(345));return e.finishedWork=e.current.alternate,e.finishedLanes=t,xc(e,$l,Hl),ac(e,Ke()),null}function uc(e,t){var n=Nl;Nl|=1;try{return e(t)}finally{0===(Nl=n)&&(Zl=Ke()+500,za&&Ua())}}function dc(e){null!==Yl&&0===Yl.tag&&0==(6&Nl)&&Sc();var t=Nl;Nl|=1;var n=jl.transition,r=bt;try{if(jl.transition=null,bt=1,e)return e()}finally{bt=r,jl.transition=n,0==(6&(Nl=t))&&Ua()}}function pc(){Ol=Rl.current,Ea(Rl)}function fc(e,t){e.finishedWork=null,e.finishedLanes=0;var n=e.timeoutHandle;if(-1!==n&&(e.timeoutHandle=-1,aa(n)),null!==Al)for(n=Al.return;null!==n;){var r=n;switch(ti(r),r.tag){case 1:null!=(r=r.type.childContextTypes)&&Oa();break;case 3:ao(),Ea(Na),Ea(ja),uo();break;case 5:oo(r);break;case 4:ao();break;case 13:case 19:Ea(so);break;case 10:xi(r.type._context);break;case 22:case 23:pc()}n=n.return}if(Ll=e,Al=e=Rc(e.current,null),Pl=Ol=t,Il=0,Fl=null,zl=Ml=Dl=0,$l=Bl=null,null!==Ci){for(t=0;t<Ci.length;t++)if(null!==(r=(n=Ci[t]).interleaved)){n.interleaved=null;var a=r.next,i=n.pending;if(null!==i){var o=i.next;i.next=a,r.next=o}n.pending=r}Ci=null}return e}function hc(e,t){for(;;){var n=Al;try{if(ki(),po.current=os,yo){for(var r=mo.memoizedState;null!==r;){var a=r.queue;null!==a&&(a.pending=null),r=r.next}yo=!1}if(ho=0,vo=go=mo=null,bo=!1,wo=0,Tl.current=null,null===n||null===n.return){Il=1,Fl=t,Al=null;break}e:{var o=e,s=n.return,l=n,c=t;if(t=Pl,l.flags|=32768,null!==c&&"object"==typeof c&&"function"==typeof c.then){var u=c,d=l,p=d.tag;if(0==(1&d.mode)&&(0===p||11===p||15===p)){var f=d.alternate;f?(d.updateQueue=f.updateQueue,d.memoizedState=f.memoizedState,d.lanes=f.lanes):(d.updateQueue=null,d.memoizedState=null)}var h=vs(s);if(null!==h){h.flags&=-257,ys(h,s,l,0,t),1&h.mode&&gs(o,u,t),c=u;var m=(t=h).updateQueue;if(null===m){var g=new Set;g.add(c),t.updateQueue=g}else m.add(c);break e}if(0==(1&t)){gs(o,u,t),gc();break e}c=Error(i(426))}else if(ai&&1&l.mode){var v=vs(s);if(null!==v){0==(65536&v.flags)&&(v.flags|=256),ys(v,s,l,0,t),hi(us(c,l));break e}}o=c=us(c,l),4!==Il&&(Il=2),null===Bl?Bl=[o]:Bl.push(o),o=s;do{switch(o.tag){case 3:o.flags|=65536,t&=-t,o.lanes|=t,Fi(o,hs(0,c,t));break e;case 1:l=c;var y=o.type,b=o.stateNode;if(0==(128&o.flags)&&("function"==typeof y.getDerivedStateFromError||null!==b&&"function"==typeof b.componentDidCatch&&(null===Wl||!Wl.has(b)))){o.flags|=65536,t&=-t,o.lanes|=t,Fi(o,ms(o,l,t));break e}}o=o.return}while(null!==o)}kc(n)}catch(w){t=w,Al===n&&null!==n&&(Al=n=n.return);continue}break}}function mc(){var e=Cl.current;return Cl.current=os,null===e?os:e}function gc(){0!==Il&&3!==Il&&2!==Il||(Il=4),null===Ll||0==(268435455&Dl)&&0==(268435455&Ml)||lc(Ll,Pl)}function vc(e,t){var n=Nl;Nl|=2;var r=mc();for(Ll===e&&Pl===t||(Hl=null,fc(e,t));;)try{yc();break}catch(a){hc(e,a)}if(ki(),Nl=n,Cl.current=r,null!==Al)throw Error(i(261));return Ll=null,Pl=0,Il}function yc(){for(;null!==Al;)wc(Al)}function bc(){for(;null!==Al&&!Ye();)wc(Al)}function wc(e){var t=_l(e.alternate,e,Ol);e.memoizedProps=e.pendingProps,null===t?kc(e):Al=t,Tl.current=null}function kc(e){var t=e;do{var n=t.alternate;if(e=t.return,0==(32768&t.flags)){if(null!==(n=Gs(n,t,Ol)))return void(Al=n)}else{if(null!==(n=Ys(n,t)))return n.flags&=32767,void(Al=n);if(null===e)return Il=6,void(Al=null);e.flags|=32768,e.subtreeFlags=0,e.deletions=null}if(null!==(t=t.sibling))return void(Al=t);Al=t=e}while(null!==t);0===Il&&(Il=5)}function xc(e,t,n){var r=bt,a=jl.transition;try{jl.transition=null,bt=1,function(e,t,n,r){do{Sc()}while(null!==Yl);if(0!=(6&Nl))throw Error(i(327));n=e.finishedWork;var a=e.finishedLanes;if(null===n)return null;if(e.finishedWork=null,e.finishedLanes=0,n===e.current)throw Error(i(177));e.callbackNode=null,e.callbackPriority=0;var o=n.lanes|n.childLanes;if(function(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0<n;){var a=31-ot(n),i=1<<a;t[a]=0,r[a]=-1,e[a]=-1,n&=~i}}(e,o),e===Ll&&(Al=Ll=null,Pl=0),0==(2064&n.subtreeFlags)&&0==(2064&n.flags)||Gl||(Gl=!0,Lc(tt,(function(){return Sc(),null}))),o=0!=(15990&n.flags),0!=(15990&n.subtreeFlags)||o){o=jl.transition,jl.transition=null;var s=bt;bt=1;var l=Nl;Nl|=4,Tl.current=null,function(e,t){if(ea=Ht,fr(e=pr())){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{var r=(n=(n=e.ownerDocument)&&n.defaultView||window).getSelection&&n.getSelection();if(r&&0!==r.rangeCount){n=r.anchorNode;var a=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch(k){n=null;break e}var s=0,l=-1,c=-1,u=0,d=0,p=e,f=null;t:for(;;){for(var h;p!==n||0!==a&&3!==p.nodeType||(l=s+a),p!==o||0!==r&&3!==p.nodeType||(c=s+r),3===p.nodeType&&(s+=p.nodeValue.length),null!==(h=p.firstChild);)f=p,p=h;for(;;){if(p===e)break t;if(f===n&&++u===a&&(l=s),f===o&&++d===r&&(c=s),null!==(h=p.nextSibling))break;f=(p=f).parentNode}p=h}n=-1===l||-1===c?null:{start:l,end:c}}else n=null}n=n||{start:0,end:0}}else n=null;for(ta={focusedElem:e,selectionRange:n},Ht=!1,Js=t;null!==Js;)if(e=(t=Js).child,0!=(1028&t.subtreeFlags)&&null!==e)e.return=t,Js=e;else for(;null!==Js;){t=Js;try{var m=t.alternate;if(0!=(1024&t.flags))switch(t.tag){case 0:case 11:case 15:case 5:case 6:case 4:case 17:break;case 1:if(null!==m){var g=m.memoizedProps,v=m.memoizedState,y=t.stateNode,b=y.getSnapshotBeforeUpdate(t.elementType===t.type?g:gi(t.type,g),v);y.__reactInternalSnapshotBeforeUpdate=b}break;case 3:var w=t.stateNode.containerInfo;1===w.nodeType?w.textContent="":9===w.nodeType&&w.documentElement&&w.removeChild(w.documentElement);break;default:throw Error(i(163))}}catch(k){Ec(t,t.return,k)}if(null!==(e=t.sibling)){e.return=t.return,Js=e;break}Js=t.return}m=nl,nl=!1}(e,n),vl(n,e),hr(ta),Ht=!!ea,ta=ea=null,e.current=n,bl(n,e,a),Qe(),Nl=l,bt=s,jl.transition=o}else e.current=n;if(Gl&&(Gl=!1,Yl=e,Ql=a),o=e.pendingLanes,0===o&&(Wl=null),function(e){if(it&&"function"==typeof it.onCommitFiberRoot)try{it.onCommitFiberRoot(at,e,void 0,128==(128&e.current.flags))}catch(t){}}(n.stateNode),ac(e,Ke()),null!==t)for(r=e.onRecoverableError,n=0;n<t.length;n++)a=t[n],r(a.value,{componentStack:a.stack,digest:a.digest});if(ql)throw ql=!1,e=Vl,Vl=null,e;0!=(1&Ql)&&0!==e.tag&&Sc(),o=e.pendingLanes,0!=(1&o)?e===Xl?Kl++:(Kl=0,Xl=e):Kl=0,Ua()}(e,t,n,r)}finally{jl.transition=a,bt=r}return null}function Sc(){if(null!==Yl){var e=wt(Ql),t=jl.transition,n=bt;try{if(jl.transition=null,bt=16>e?16:e,null===Yl)var r=!1;else{if(e=Yl,Yl=null,Ql=0,0!=(6&Nl))throw Error(i(331));var a=Nl;for(Nl|=4,Js=e.current;null!==Js;){var o=Js,s=o.child;if(0!=(16&Js.flags)){var l=o.deletions;if(null!==l){for(var c=0;c<l.length;c++){var u=l[c];for(Js=u;null!==Js;){var d=Js;switch(d.tag){case 0:case 11:case 15:rl(8,d,o)}var p=d.child;if(null!==p)p.return=d,Js=p;else for(;null!==Js;){var f=(d=Js).sibling,h=d.return;if(ol(d),d===u){Js=null;break}if(null!==f){f.return=h,Js=f;break}Js=h}}}var m=o.alternate;if(null!==m){var g=m.child;if(null!==g){m.child=null;do{var v=g.sibling;g.sibling=null,g=v}while(null!==g)}}Js=o}}if(0!=(2064&o.subtreeFlags)&&null!==s)s.return=o,Js=s;else e:for(;null!==Js;){if(0!=(2048&(o=Js).flags))switch(o.tag){case 0:case 11:case 15:rl(9,o,o.return)}var y=o.sibling;if(null!==y){y.return=o.return,Js=y;break e}Js=o.return}}var b=e.current;for(Js=b;null!==Js;){var w=(s=Js).child;if(0!=(2064&s.subtreeFlags)&&null!==w)w.return=s,Js=w;else e:for(s=b;null!==Js;){if(0!=(2048&(l=Js).flags))try{switch(l.tag){case 0:case 11:case 15:al(9,l)}}catch(x){Ec(l,l.return,x)}if(l===s){Js=null;break e}var k=l.sibling;if(null!==k){k.return=l.return,Js=k;break e}Js=l.return}}if(Nl=a,Ua(),it&&"function"==typeof it.onPostCommitFiberRoot)try{it.onPostCommitFiberRoot(at,e)}catch(x){}r=!0}return r}finally{bt=n,jl.transition=t}}return!1}function _c(e,t,n){e=Ri(e,t=hs(0,t=us(n,t),1),1),t=tc(),null!==e&&(vt(e,1,t),ac(e,t))}function Ec(e,t,n){if(3===e.tag)_c(e,e,n);else for(;null!==t;){if(3===t.tag){_c(t,e,n);break}if(1===t.tag){var r=t.stateNode;if("function"==typeof t.type.getDerivedStateFromError||"function"==typeof r.componentDidCatch&&(null===Wl||!Wl.has(r))){t=Ri(t,e=ms(t,e=us(n,e),1),1),e=tc(),null!==t&&(vt(t,1,e),ac(t,e));break}}t=t.return}}function Cc(e,t,n){var r=e.pingCache;null!==r&&r.delete(t),t=tc(),e.pingedLanes|=e.suspendedLanes&n,Ll===e&&(Pl&n)===n&&(4===Il||3===Il&&(130023424&Pl)===Pl&&500>Ke()-Ul?fc(e,0):zl|=n),ac(e,t)}function Tc(e,t){0===t&&(0==(1&e.mode)?t=1:(t=ut,0==(130023424&(ut<<=1))&&(ut=4194304)));var n=tc();null!==(e=Ni(e,t))&&(vt(e,t,n),ac(e,n))}function jc(e){var t=e.memoizedState,n=0;null!==t&&(n=t.retryLane),Tc(e,n)}function Nc(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,a=e.memoizedState;null!==a&&(n=a.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(i(314))}null!==r&&r.delete(t),Tc(e,n)}function Lc(e,t){return We(e,t)}function Ac(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Pc(e,t,n,r){return new Ac(e,t,n,r)}function Oc(e){return!(!(e=e.prototype)||!e.isReactComponent)}function Rc(e,t){var n=e.alternate;return null===n?((n=Pc(e.tag,t,e.key,e.mode)).elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=14680064&e.flags,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=null===t?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Ic(e,t,n,r,a,o){var s=2;if(r=e,"function"==typeof e)Oc(e)&&(s=1);else if("string"==typeof e)s=5;else e:switch(e){case S:return Fc(n.children,a,o,t);case _:s=8,a|=8;break;case E:return(e=Pc(12,n,t,2|a)).elementType=E,e.lanes=o,e;case N:return(e=Pc(13,n,t,a)).elementType=N,e.lanes=o,e;case L:return(e=Pc(19,n,t,a)).elementType=L,e.lanes=o,e;case O:return Dc(n,a,o,t);default:if("object"==typeof e&&null!==e)switch(e.$$typeof){case C:s=10;break e;case T:s=9;break e;case j:s=11;break e;case A:s=14;break e;case P:s=16,r=null;break e}throw Error(i(130,null==e?e:typeof e,""))}return(t=Pc(s,n,t,a)).elementType=e,t.type=r,t.lanes=o,t}function Fc(e,t,n,r){return(e=Pc(7,e,r,t)).lanes=n,e}function Dc(e,t,n,r){return(e=Pc(22,e,r,t)).elementType=O,e.lanes=n,e.stateNode={isHidden:!1},e}function Mc(e,t,n){return(e=Pc(6,e,null,t)).lanes=n,e}function zc(e,t,n){return(t=Pc(4,null!==e.children?e.children:[],e.key,t)).lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Bc(e,t,n,r,a){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=gt(0),this.expirationTimes=gt(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=gt(0),this.identifierPrefix=r,this.onRecoverableError=a,this.mutableSourceEagerHydrationData=null}function $c(e,t,n,r,a,i,o,s,l){return e=new Bc(e,t,n,s,l),1===t?(t=1,!0===i&&(t|=8)):t=0,i=Pc(3,null,null,t),e.current=i,i.stateNode=e,i.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},Ai(i),e}function Uc(e){if(!e)return Ta;e:{if(Ue(e=e._reactInternals)!==e||1!==e.tag)throw Error(i(170));var t=e;do{switch(t.tag){case 3:t=t.stateNode.context;break e;case 1:if(Pa(t.type)){t=t.stateNode.__reactInternalMemoizedMergedChildContext;break e}}t=t.return}while(null!==t);throw Error(i(171))}if(1===e.tag){var n=e.type;if(Pa(n))return Ia(e,n,t)}return t}function Zc(e,t,n,r,a,i,o,s,l){return(e=$c(n,r,!0,e,0,i,0,s,l)).context=Uc(null),n=e.current,(i=Oi(r=tc(),a=nc(n))).callback=null!=t?t:null,Ri(n,i,a),e.current.lanes=a,vt(e,a,r),ac(e,r),e}function Hc(e,t,n,r){var a=t.current,i=tc(),o=nc(a);return n=Uc(n),null===t.context?t.context=n:t.pendingContext=n,(t=Oi(i,o)).payload={element:e},null!==(r=void 0===r?null:r)&&(t.callback=r),null!==(e=Ri(a,t,o))&&(rc(e,a,o,i),Ii(e,a,o)),o}function qc(e){return(e=e.current).child?(e.child.tag,e.child.stateNode):null}function Vc(e,t){if(null!==(e=e.memoizedState)&&null!==e.dehydrated){var n=e.retryLane;e.retryLane=0!==n&&n<t?n:t}}function Wc(e,t){Vc(e,t),(e=e.alternate)&&Vc(e,t)}_l=function(e,t,n){if(null!==e)if(e.memoizedProps!==t.pendingProps||Na.current)ws=!0;else{if(0==(e.lanes&n)&&0==(128&t.flags))return ws=!1,function(e,t,n){switch(t.tag){case 3:Ls(t),fi();break;case 5:io(t);break;case 1:Pa(t.type)&&Fa(t);break;case 4:ro(t,t.stateNode.containerInfo);break;case 10:var r=t.type._context,a=t.memoizedProps.value;Ca(vi,r._currentValue),r._currentValue=a;break;case 13:if(null!==(r=t.memoizedState))return null!==r.dehydrated?(Ca(so,1&so.current),t.flags|=128,null):0!=(n&t.child.childLanes)?Ms(e,t,n):(Ca(so,1&so.current),null!==(e=qs(e,t,n))?e.sibling:null);Ca(so,1&so.current);break;case 19:if(r=0!=(n&t.childLanes),0!=(128&e.flags)){if(r)return Zs(e,t,n);t.flags|=128}if(null!==(a=t.memoizedState)&&(a.rendering=null,a.tail=null,a.lastEffect=null),Ca(so,so.current),r)break;return null;case 22:case 23:return t.lanes=0,Es(e,t,n)}return qs(e,t,n)}(e,t,n);ws=0!=(131072&e.flags)}else ws=!1,ai&&0!=(1048576&t.flags)&&Ja(t,Va,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;Hs(e,t),e=t.pendingProps;var a=Aa(t,ja.current);_i(t,n),a=_o(null,t,r,e,a,n);var o=Eo();return t.flags|=1,"object"==typeof a&&null!==a&&"function"==typeof a.render&&void 0===a.$$typeof?(t.tag=1,t.memoizedState=null,t.updateQueue=null,Pa(r)?(o=!0,Fa(t)):o=!1,t.memoizedState=null!==a.state&&void 0!==a.state?a.state:null,Ai(t),a.updater=$i,t.stateNode=a,a._reactInternals=t,qi(t,r,e,n),t=Ns(null,t,r,!0,o,n)):(t.tag=0,ai&&o&&ei(t),ks(null,t,a,n),t=t.child),t;case 16:r=t.elementType;e:{switch(Hs(e,t),e=t.pendingProps,r=(a=r._init)(r._payload),t.type=r,a=t.tag=function(e){if("function"==typeof e)return Oc(e)?1:0;if(null!=e){if((e=e.$$typeof)===j)return 11;if(e===A)return 14}return 2}(r),e=gi(r,e),a){case 0:t=Ts(null,t,r,e,n);break e;case 1:t=js(null,t,r,e,n);break e;case 11:t=xs(null,t,r,e,n);break e;case 14:t=Ss(null,t,r,gi(r.type,e),n);break e}throw Error(i(306,r,""))}return t;case 0:return r=t.type,a=t.pendingProps,Ts(e,t,r,a=t.elementType===r?a:gi(r,a),n);case 1:return r=t.type,a=t.pendingProps,js(e,t,r,a=t.elementType===r?a:gi(r,a),n);case 3:e:{if(Ls(t),null===e)throw Error(i(387));r=t.pendingProps,a=(o=t.memoizedState).element,Pi(e,t),Di(t,r,null,n);var s=t.memoizedState;if(r=s.element,o.isDehydrated){if(o={element:r,isDehydrated:!1,cache:s.cache,pendingSuspenseBoundaries:s.pendingSuspenseBoundaries,transitions:s.transitions},t.updateQueue.baseState=o,t.memoizedState=o,256&t.flags){t=As(e,t,r,n,a=us(Error(i(423)),t));break e}if(r!==a){t=As(e,t,r,n,a=us(Error(i(424)),t));break e}for(ri=ca(t.stateNode.containerInfo.firstChild),ni=t,ai=!0,ii=null,n=Ki(t,null,r,n),t.child=n;n;)n.flags=-3&n.flags|4096,n=n.sibling}else{if(fi(),r===a){t=qs(e,t,n);break e}ks(e,t,r,n)}t=t.child}return t;case 5:return io(t),null===e&&ci(t),r=t.type,a=t.pendingProps,o=null!==e?e.memoizedProps:null,s=a.children,na(r,a)?s=null:null!==o&&na(r,o)&&(t.flags|=32),Cs(e,t),ks(e,t,s,n),t.child;case 6:return null===e&&ci(t),null;case 13:return Ms(e,t,n);case 4:return ro(t,t.stateNode.containerInfo),r=t.pendingProps,null===e?t.child=Qi(t,null,r,n):ks(e,t,r,n),t.child;case 11:return r=t.type,a=t.pendingProps,xs(e,t,r,a=t.elementType===r?a:gi(r,a),n);case 7:return ks(e,t,t.pendingProps,n),t.child;case 8:case 12:return ks(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,a=t.pendingProps,o=t.memoizedProps,s=a.value,Ca(vi,r._currentValue),r._currentValue=s,null!==o)if(sr(o.value,s)){if(o.children===a.children&&!Na.current){t=qs(e,t,n);break e}}else for(null!==(o=t.child)&&(o.return=t);null!==o;){var l=o.dependencies;if(null!==l){s=o.child;for(var c=l.firstContext;null!==c;){if(c.context===r){if(1===o.tag){(c=Oi(-1,n&-n)).tag=2;var u=o.updateQueue;if(null!==u){var d=(u=u.shared).pending;null===d?c.next=c:(c.next=d.next,d.next=c),u.pending=c}}o.lanes|=n,null!==(c=o.alternate)&&(c.lanes|=n),Si(o.return,n,t),l.lanes|=n;break}c=c.next}}else if(10===o.tag)s=o.type===t.type?null:o.child;else if(18===o.tag){if(null===(s=o.return))throw Error(i(341));s.lanes|=n,null!==(l=s.alternate)&&(l.lanes|=n),Si(s,n,t),s=o.sibling}else s=o.child;if(null!==s)s.return=o;else for(s=o;null!==s;){if(s===t){s=null;break}if(null!==(o=s.sibling)){o.return=s.return,s=o;break}s=s.return}o=s}ks(e,t,a.children,n),t=t.child}return t;case 9:return a=t.type,r=t.pendingProps.children,_i(t,n),r=r(a=Ei(a)),t.flags|=1,ks(e,t,r,n),t.child;case 14:return a=gi(r=t.type,t.pendingProps),Ss(e,t,r,a=gi(r.type,a),n);case 15:return _s(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,a=t.pendingProps,a=t.elementType===r?a:gi(r,a),Hs(e,t),t.tag=1,Pa(r)?(e=!0,Fa(t)):e=!1,_i(t,n),Zi(t,r,a),qi(t,r,a,n),Ns(null,t,r,!0,e,n);case 19:return Zs(e,t,n);case 22:return Es(e,t,n)}throw Error(i(156,t.tag))};var Gc="function"==typeof reportError?reportError:function(e){console.error(e)};function Yc(e){this._internalRoot=e}function Qc(e){this._internalRoot=e}function Kc(e){return!(!e||1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType)}function Xc(e){return!(!e||1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType&&(8!==e.nodeType||" react-mount-point-unstable "!==e.nodeValue))}function Jc(){}function eu(e,t,n,r,a){var i=n._reactRootContainer;if(i){var o=i;if("function"==typeof a){var s=a;a=function(){var e=qc(o);s.call(e)}}Hc(t,o,e,a)}else o=function(e,t,n,r,a){if(a){if("function"==typeof r){var i=r;r=function(){var e=qc(o);i.call(e)}}var o=Zc(t,r,e,0,null,!1,0,"",Jc);return e._reactRootContainer=o,e[ha]=o.current,Ur(8===e.nodeType?e.parentNode:e),dc(),o}for(;a=e.lastChild;)e.removeChild(a);if("function"==typeof r){var s=r;r=function(){var e=qc(l);s.call(e)}}var l=$c(e,0,!1,null,0,!1,0,"",Jc);return e._reactRootContainer=l,e[ha]=l.current,Ur(8===e.nodeType?e.parentNode:e),dc((function(){Hc(t,l,n,r)})),l}(n,t,e,a,r);return qc(o)}Qc.prototype.render=Yc.prototype.render=function(e){var t=this._internalRoot;if(null===t)throw Error(i(409));Hc(e,t,null,null)},Qc.prototype.unmount=Yc.prototype.unmount=function(){var e=this._internalRoot;if(null!==e){this._internalRoot=null;var t=e.containerInfo;dc((function(){Hc(null,e,null,null)})),t[ha]=null}},Qc.prototype.unstable_scheduleHydration=function(e){if(e){var t=_t();e={blockedOn:null,target:e,priority:t};for(var n=0;n<Ot.length&&0!==t&&t<Ot[n].priority;n++);Ot.splice(n,0,e),0===n&&Dt(e)}},kt=function(e){switch(e.tag){case 3:var t=e.stateNode;if(t.current.memoizedState.isDehydrated){var n=dt(t.pendingLanes);0!==n&&(yt(t,1|n),ac(t,Ke()),0==(6&Nl)&&(Zl=Ke()+500,Ua()))}break;case 13:dc((function(){var t=Ni(e,1);if(null!==t){var n=tc();rc(t,e,1,n)}})),Wc(e,1)}},xt=function(e){if(13===e.tag){var t=Ni(e,134217728);if(null!==t)rc(t,e,134217728,tc());Wc(e,134217728)}},St=function(e){if(13===e.tag){var t=nc(e),n=Ni(e,t);if(null!==n)rc(n,e,t,tc());Wc(e,t)}},_t=function(){return bt},Et=function(e,t){var n=bt;try{return bt=e,t()}finally{bt=n}},xe=function(e,t,n){switch(t){case"input":if(X(e,n),t=n.name,"radio"===n.type&&null!=t){for(n=e;n.parentNode;)n=n.parentNode;for(n=n.querySelectorAll("input[name="+JSON.stringify(""+t)+'][type="radio"]'),t=0;t<n.length;t++){var r=n[t];if(r!==e&&r.form===e.form){var a=ka(r);if(!a)throw Error(i(90));W(r),X(r,a)}}}break;case"textarea":ie(e,n);break;case"select":null!=(t=n.value)&&ne(e,!!n.multiple,t,!1)}},je=uc,Ne=dc;var tu={usingClientEntryPoint:!1,Events:[ba,wa,ka,Ce,Te,uc]},nu={findFiberByHostInstance:ya,bundleType:0,version:"18.2.0",rendererPackageName:"react-dom"},ru={bundleType:nu.bundleType,version:nu.version,rendererPackageName:nu.rendererPackageName,rendererConfig:nu.rendererConfig,overrideHookState:null,overrideHookStateDeletePath:null,overrideHookStateRenamePath:null,overrideProps:null,overridePropsDeletePath:null,overridePropsRenamePath:null,setErrorHandler:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:w.ReactCurrentDispatcher,findHostInstanceByFiber:function(e){return null===(e=qe(e))?null:e.stateNode},findFiberByHostInstance:nu.findFiberByHostInstance||function(){return null},findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null,reconcilerVersion:"18.2.0-next-9e3b772b8-20220608"};if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__){var au=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(!au.isDisabled&&au.supportsFiber)try{at=au.inject(ru),it=au}catch(ue){}}t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=tu,t.createPortal=function(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null;if(!Kc(t))throw Error(i(200));return function(e,t,n){var r=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null;return{$$typeof:x,key:null==r?null:""+r,children:e,containerInfo:t,implementation:n}}(e,t,null,n)},t.createRoot=function(e,t){if(!Kc(e))throw Error(i(299));var n=!1,r="",a=Gc;return null!=t&&(!0===t.unstable_strictMode&&(n=!0),void 0!==t.identifierPrefix&&(r=t.identifierPrefix),void 0!==t.onRecoverableError&&(a=t.onRecoverableError)),t=$c(e,1,!1,null,0,n,0,r,a),e[ha]=t.current,Ur(8===e.nodeType?e.parentNode:e),new Yc(t)},t.findDOMNode=function(e){if(null==e)return null;if(1===e.nodeType)return e;var t=e._reactInternals;if(void 0===t){if("function"==typeof e.render)throw Error(i(188));throw e=Object.keys(e).join(","),Error(i(268,e))}return e=null===(e=qe(t))?null:e.stateNode},t.flushSync=function(e){return dc(e)},t.hydrate=function(e,t,n){if(!Xc(t))throw Error(i(200));return eu(null,e,t,!0,n)},t.hydrateRoot=function(e,t,n){if(!Kc(e))throw Error(i(405));var r=null!=n&&n.hydratedSources||null,a=!1,o="",s=Gc;if(null!=n&&(!0===n.unstable_strictMode&&(a=!0),void 0!==n.identifierPrefix&&(o=n.identifierPrefix),void 0!==n.onRecoverableError&&(s=n.onRecoverableError)),t=Zc(t,null,e,1,null!=n?n:null,a,0,o,s),e[ha]=t.current,Ur(e),r)for(e=0;e<r.length;e++)a=(a=(n=r[e])._getVersion)(n._source),null==t.mutableSourceEagerHydrationData?t.mutableSourceEagerHydrationData=[n,a]:t.mutableSourceEagerHydrationData.push(n,a);return new Qc(t)},t.render=function(e,t,n){if(!Xc(t))throw Error(i(200));return eu(null,e,t,!1,n)},t.unmountComponentAtNode=function(e){if(!Xc(e))throw Error(i(40));return!!e._reactRootContainer&&(dc((function(){eu(null,null,e,!1,(function(){e._reactRootContainer=null,e[ha]=null}))})),!0)},t.unstable_batchedUpdates=uc,t.unstable_renderSubtreeIntoContainer=function(e,t,n,r){if(!Xc(n))throw Error(i(200));if(null==e||void 0===e._reactInternals)throw Error(i(38));return eu(e,t,n,!1,r)},t.version="18.2.0-next-9e3b772b8-20220608"},745:(e,t,n)=>{"use strict";var r=n(3935);t.createRoot=r.createRoot,t.hydrateRoot=r.hydrateRoot},3935:(e,t,n)=>{"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}(),e.exports=n(4448)},9590:e=>{var t="undefined"!=typeof Element,n="function"==typeof Map,r="function"==typeof Set,a="function"==typeof ArrayBuffer&&!!ArrayBuffer.isView;function i(e,o){if(e===o)return!0;if(e&&o&&"object"==typeof e&&"object"==typeof o){if(e.constructor!==o.constructor)return!1;var s,l,c,u;if(Array.isArray(e)){if((s=e.length)!=o.length)return!1;for(l=s;0!=l--;)if(!i(e[l],o[l]))return!1;return!0}if(n&&e instanceof Map&&o instanceof Map){if(e.size!==o.size)return!1;for(u=e.entries();!(l=u.next()).done;)if(!o.has(l.value[0]))return!1;for(u=e.entries();!(l=u.next()).done;)if(!i(l.value[1],o.get(l.value[0])))return!1;return!0}if(r&&e instanceof Set&&o instanceof Set){if(e.size!==o.size)return!1;for(u=e.entries();!(l=u.next()).done;)if(!o.has(l.value[0]))return!1;return!0}if(a&&ArrayBuffer.isView(e)&&ArrayBuffer.isView(o)){if((s=e.length)!=o.length)return!1;for(l=s;0!=l--;)if(e[l]!==o[l])return!1;return!0}if(e.constructor===RegExp)return e.source===o.source&&e.flags===o.flags;if(e.valueOf!==Object.prototype.valueOf&&"function"==typeof e.valueOf&&"function"==typeof o.valueOf)return e.valueOf()===o.valueOf();if(e.toString!==Object.prototype.toString&&"function"==typeof e.toString&&"function"==typeof o.toString)return e.toString()===o.toString();if((s=(c=Object.keys(e)).length)!==Object.keys(o).length)return!1;for(l=s;0!=l--;)if(!Object.prototype.hasOwnProperty.call(o,c[l]))return!1;if(t&&e instanceof Element)return!1;for(l=s;0!=l--;)if(("_owner"!==c[l]&&"__v"!==c[l]&&"__o"!==c[l]||!e.$$typeof)&&!i(e[c[l]],o[c[l]]))return!1;return!0}return e!=e&&o!=o}e.exports=function(e,t){try{return i(e,t)}catch(n){if((n.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw n}}},405:(e,t,n)=>{"use strict";n.d(t,{B6:()=>q,ql:()=>J});var r=n(7294),a=n(5697),i=n.n(a),o=n(9590),s=n.n(o),l=n(1143),c=n.n(l),u=n(6774),d=n.n(u);function p(){return p=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},p.apply(this,arguments)}function f(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,h(e,t)}function h(e,t){return h=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},h(e,t)}function m(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)t.indexOf(n=i[r])>=0||(a[n]=e[n]);return a}var g={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title",FRAGMENT:"Symbol(react.fragment)"},v={rel:["amphtml","canonical","alternate"]},y={type:["application/ld+json"]},b={charset:"",name:["robots","description"],property:["og:type","og:title","og:url","og:image","og:image:alt","og:description","twitter:url","twitter:title","twitter:description","twitter:image","twitter:image:alt","twitter:card","twitter:site"]},w=Object.keys(g).map((function(e){return g[e]})),k={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"},x=Object.keys(k).reduce((function(e,t){return e[k[t]]=t,e}),{}),S=function(e,t){for(var n=e.length-1;n>=0;n-=1){var r=e[n];if(Object.prototype.hasOwnProperty.call(r,t))return r[t]}return null},_=function(e){var t=S(e,g.TITLE),n=S(e,"titleTemplate");if(Array.isArray(t)&&(t=t.join("")),n&&t)return n.replace(/%s/g,(function(){return t}));var r=S(e,"defaultTitle");return t||r||void 0},E=function(e){return S(e,"onChangeClientState")||function(){}},C=function(e,t){return t.filter((function(t){return void 0!==t[e]})).map((function(t){return t[e]})).reduce((function(e,t){return p({},e,t)}),{})},T=function(e,t){return t.filter((function(e){return void 0!==e[g.BASE]})).map((function(e){return e[g.BASE]})).reverse().reduce((function(t,n){if(!t.length)for(var r=Object.keys(n),a=0;a<r.length;a+=1){var i=r[a].toLowerCase();if(-1!==e.indexOf(i)&&n[i])return t.concat(n)}return t}),[])},j=function(e,t,n){var r={};return n.filter((function(t){return!!Array.isArray(t[e])||(void 0!==t[e]&&console&&"function"==typeof console.warn&&console.warn("Helmet: "+e+' should be of type "Array". Instead found type "'+typeof t[e]+'"'),!1)})).map((function(t){return t[e]})).reverse().reduce((function(e,n){var a={};n.filter((function(e){for(var n,i=Object.keys(e),o=0;o<i.length;o+=1){var s=i[o],l=s.toLowerCase();-1===t.indexOf(l)||"rel"===n&&"canonical"===e[n].toLowerCase()||"rel"===l&&"stylesheet"===e[l].toLowerCase()||(n=l),-1===t.indexOf(s)||"innerHTML"!==s&&"cssText"!==s&&"itemprop"!==s||(n=s)}if(!n||!e[n])return!1;var c=e[n].toLowerCase();return r[n]||(r[n]={}),a[n]||(a[n]={}),!r[n][c]&&(a[n][c]=!0,!0)})).reverse().forEach((function(t){return e.push(t)}));for(var i=Object.keys(a),o=0;o<i.length;o+=1){var s=i[o],l=p({},r[s],a[s]);r[s]=l}return e}),[]).reverse()},N=function(e,t){if(Array.isArray(e)&&e.length)for(var n=0;n<e.length;n+=1)if(e[n][t])return!0;return!1},L=function(e){return Array.isArray(e)?e.join(""):e},A=function(e,t){return Array.isArray(e)?e.reduce((function(e,n){return function(e,t){for(var n=Object.keys(e),r=0;r<n.length;r+=1)if(t[n[r]]&&t[n[r]].includes(e[n[r]]))return!0;return!1}(n,t)?e.priority.push(n):e.default.push(n),e}),{priority:[],default:[]}):{default:e}},P=function(e,t){var n;return p({},e,((n={})[t]=void 0,n))},O=[g.NOSCRIPT,g.SCRIPT,g.STYLE],R=function(e,t){return void 0===t&&(t=!0),!1===t?String(e):String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")},I=function(e){return Object.keys(e).reduce((function(t,n){var r=void 0!==e[n]?n+'="'+e[n]+'"':""+n;return t?t+" "+r:r}),"")},F=function(e,t){return void 0===t&&(t={}),Object.keys(e).reduce((function(t,n){return t[k[n]||n]=e[n],t}),t)},D=function(e,t){return t.map((function(t,n){var a,i=((a={key:n})["data-rh"]=!0,a);return Object.keys(t).forEach((function(e){var n=k[e]||e;"innerHTML"===n||"cssText"===n?i.dangerouslySetInnerHTML={__html:t.innerHTML||t.cssText}:i[n]=t[e]})),r.createElement(e,i)}))},M=function(e,t,n){switch(e){case g.TITLE:return{toComponent:function(){return n=t.titleAttributes,(a={key:e=t.title})["data-rh"]=!0,i=F(n,a),[r.createElement(g.TITLE,i,e)];var e,n,a,i},toString:function(){return function(e,t,n,r){var a=I(n),i=L(t);return a?"<"+e+' data-rh="true" '+a+">"+R(i,r)+"</"+e+">":"<"+e+' data-rh="true">'+R(i,r)+"</"+e+">"}(e,t.title,t.titleAttributes,n)}};case"bodyAttributes":case"htmlAttributes":return{toComponent:function(){return F(t)},toString:function(){return I(t)}};default:return{toComponent:function(){return D(e,t)},toString:function(){return function(e,t,n){return t.reduce((function(t,r){var a=Object.keys(r).filter((function(e){return!("innerHTML"===e||"cssText"===e)})).reduce((function(e,t){var a=void 0===r[t]?t:t+'="'+R(r[t],n)+'"';return e?e+" "+a:a}),""),i=r.innerHTML||r.cssText||"",o=-1===O.indexOf(e);return t+"<"+e+' data-rh="true" '+a+(o?"/>":">"+i+"</"+e+">")}),"")}(e,t,n)}}}},z=function(e){var t=e.baseTag,n=e.bodyAttributes,r=e.encode,a=e.htmlAttributes,i=e.noscriptTags,o=e.styleTags,s=e.title,l=void 0===s?"":s,c=e.titleAttributes,u=e.linkTags,d=e.metaTags,p=e.scriptTags,f={toComponent:function(){},toString:function(){return""}};if(e.prioritizeSeoTags){var h=function(e){var t=e.linkTags,n=e.scriptTags,r=e.encode,a=A(e.metaTags,b),i=A(t,v),o=A(n,y);return{priorityMethods:{toComponent:function(){return[].concat(D(g.META,a.priority),D(g.LINK,i.priority),D(g.SCRIPT,o.priority))},toString:function(){return M(g.META,a.priority,r)+" "+M(g.LINK,i.priority,r)+" "+M(g.SCRIPT,o.priority,r)}},metaTags:a.default,linkTags:i.default,scriptTags:o.default}}(e);f=h.priorityMethods,u=h.linkTags,d=h.metaTags,p=h.scriptTags}return{priority:f,base:M(g.BASE,t,r),bodyAttributes:M("bodyAttributes",n,r),htmlAttributes:M("htmlAttributes",a,r),link:M(g.LINK,u,r),meta:M(g.META,d,r),noscript:M(g.NOSCRIPT,i,r),script:M(g.SCRIPT,p,r),style:M(g.STYLE,o,r),title:M(g.TITLE,{title:l,titleAttributes:c},r)}},B=[],$=function(e,t){var n=this;void 0===t&&(t="undefined"!=typeof document),this.instances=[],this.value={setHelmet:function(e){n.context.helmet=e},helmetInstances:{get:function(){return n.canUseDOM?B:n.instances},add:function(e){(n.canUseDOM?B:n.instances).push(e)},remove:function(e){var t=(n.canUseDOM?B:n.instances).indexOf(e);(n.canUseDOM?B:n.instances).splice(t,1)}}},this.context=e,this.canUseDOM=t,t||(e.helmet=z({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}}))},U=r.createContext({}),Z=i().shape({setHelmet:i().func,helmetInstances:i().shape({get:i().func,add:i().func,remove:i().func})}),H="undefined"!=typeof document,q=function(e){function t(n){var r;return(r=e.call(this,n)||this).helmetData=new $(r.props.context,t.canUseDOM),r}return f(t,e),t.prototype.render=function(){return r.createElement(U.Provider,{value:this.helmetData.value},this.props.children)},t}(r.Component);q.canUseDOM=H,q.propTypes={context:i().shape({helmet:i().shape()}),children:i().node.isRequired},q.defaultProps={context:{}},q.displayName="HelmetProvider";var V=function(e,t){var n,r=document.head||document.querySelector(g.HEAD),a=r.querySelectorAll(e+"[data-rh]"),i=[].slice.call(a),o=[];return t&&t.length&&t.forEach((function(t){var r=document.createElement(e);for(var a in t)Object.prototype.hasOwnProperty.call(t,a)&&("innerHTML"===a?r.innerHTML=t.innerHTML:"cssText"===a?r.styleSheet?r.styleSheet.cssText=t.cssText:r.appendChild(document.createTextNode(t.cssText)):r.setAttribute(a,void 0===t[a]?"":t[a]));r.setAttribute("data-rh","true"),i.some((function(e,t){return n=t,r.isEqualNode(e)}))?i.splice(n,1):o.push(r)})),i.forEach((function(e){return e.parentNode.removeChild(e)})),o.forEach((function(e){return r.appendChild(e)})),{oldTags:i,newTags:o}},W=function(e,t){var n=document.getElementsByTagName(e)[0];if(n){for(var r=n.getAttribute("data-rh"),a=r?r.split(","):[],i=[].concat(a),o=Object.keys(t),s=0;s<o.length;s+=1){var l=o[s],c=t[l]||"";n.getAttribute(l)!==c&&n.setAttribute(l,c),-1===a.indexOf(l)&&a.push(l);var u=i.indexOf(l);-1!==u&&i.splice(u,1)}for(var d=i.length-1;d>=0;d-=1)n.removeAttribute(i[d]);a.length===i.length?n.removeAttribute("data-rh"):n.getAttribute("data-rh")!==o.join(",")&&n.setAttribute("data-rh",o.join(","))}},G=function(e,t){var n=e.baseTag,r=e.htmlAttributes,a=e.linkTags,i=e.metaTags,o=e.noscriptTags,s=e.onChangeClientState,l=e.scriptTags,c=e.styleTags,u=e.title,d=e.titleAttributes;W(g.BODY,e.bodyAttributes),W(g.HTML,r),function(e,t){void 0!==e&&document.title!==e&&(document.title=L(e)),W(g.TITLE,t)}(u,d);var p={baseTag:V(g.BASE,n),linkTags:V(g.LINK,a),metaTags:V(g.META,i),noscriptTags:V(g.NOSCRIPT,o),scriptTags:V(g.SCRIPT,l),styleTags:V(g.STYLE,c)},f={},h={};Object.keys(p).forEach((function(e){var t=p[e],n=t.newTags,r=t.oldTags;n.length&&(f[e]=n),r.length&&(h[e]=p[e].oldTags)})),t&&t(),s(e,f,h)},Y=null,Q=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(t=e.call.apply(e,[this].concat(r))||this).rendered=!1,t}f(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!d()(e,this.props)},n.componentDidUpdate=function(){this.emitChange()},n.componentWillUnmount=function(){this.props.context.helmetInstances.remove(this),this.emitChange()},n.emitChange=function(){var e,t,n=this.props.context,r=n.setHelmet,a=null,i=(e=n.helmetInstances.get().map((function(e){var t=p({},e.props);return delete t.context,t})),{baseTag:T(["href"],e),bodyAttributes:C("bodyAttributes",e),defer:S(e,"defer"),encode:S(e,"encodeSpecialCharacters"),htmlAttributes:C("htmlAttributes",e),linkTags:j(g.LINK,["rel","href"],e),metaTags:j(g.META,["name","charset","http-equiv","property","itemprop"],e),noscriptTags:j(g.NOSCRIPT,["innerHTML"],e),onChangeClientState:E(e),scriptTags:j(g.SCRIPT,["src","innerHTML"],e),styleTags:j(g.STYLE,["cssText"],e),title:_(e),titleAttributes:C("titleAttributes",e),prioritizeSeoTags:N(e,"prioritizeSeoTags")});q.canUseDOM?(t=i,Y&&cancelAnimationFrame(Y),t.defer?Y=requestAnimationFrame((function(){G(t,(function(){Y=null}))})):(G(t),Y=null)):z&&(a=z(i)),r(a)},n.init=function(){this.rendered||(this.rendered=!0,this.props.context.helmetInstances.add(this),this.emitChange())},n.render=function(){return this.init(),null},t}(r.Component);Q.propTypes={context:Z.isRequired},Q.displayName="HelmetDispatcher";var K=["children"],X=["children"],J=function(e){function t(){return e.apply(this,arguments)||this}f(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!s()(P(this.props,"helmetData"),P(e,"helmetData"))},n.mapNestedChildrenToProps=function(e,t){if(!t)return null;switch(e.type){case g.SCRIPT:case g.NOSCRIPT:return{innerHTML:t};case g.STYLE:return{cssText:t};default:throw new Error("<"+e.type+" /> elements are self-closing and can not contain children. Refer to our API for more information.")}},n.flattenArrayTypeChildren=function(e){var t,n=e.child,r=e.arrayTypeChildren;return p({},r,((t={})[n.type]=[].concat(r[n.type]||[],[p({},e.newChildProps,this.mapNestedChildrenToProps(n,e.nestedChildren))]),t))},n.mapObjectTypeChildren=function(e){var t,n,r=e.child,a=e.newProps,i=e.newChildProps,o=e.nestedChildren;switch(r.type){case g.TITLE:return p({},a,((t={})[r.type]=o,t.titleAttributes=p({},i),t));case g.BODY:return p({},a,{bodyAttributes:p({},i)});case g.HTML:return p({},a,{htmlAttributes:p({},i)});default:return p({},a,((n={})[r.type]=p({},i),n))}},n.mapArrayTypeChildrenToProps=function(e,t){var n=p({},t);return Object.keys(e).forEach((function(t){var r;n=p({},n,((r={})[t]=e[t],r))})),n},n.warnOnInvalidChildren=function(e,t){return c()(w.some((function(t){return e.type===t})),"function"==typeof e.type?"You may be attempting to nest <Helmet> components within each other, which is not allowed. Refer to our API for more information.":"Only elements types "+w.join(", ")+" are allowed. Helmet does not support rendering <"+e.type+"> elements. Refer to our API for more information."),c()(!t||"string"==typeof t||Array.isArray(t)&&!t.some((function(e){return"string"!=typeof e})),"Helmet expects a string as a child of <"+e.type+">. Did you forget to wrap your children in braces? ( <"+e.type+">{``}</"+e.type+"> ) Refer to our API for more information."),!0},n.mapChildrenToProps=function(e,t){var n=this,a={};return r.Children.forEach(e,(function(e){if(e&&e.props){var r=e.props,i=r.children,o=m(r,K),s=Object.keys(o).reduce((function(e,t){return e[x[t]||t]=o[t],e}),{}),l=e.type;switch("symbol"==typeof l?l=l.toString():n.warnOnInvalidChildren(e,i),l){case g.FRAGMENT:t=n.mapChildrenToProps(i,t);break;case g.LINK:case g.META:case g.NOSCRIPT:case g.SCRIPT:case g.STYLE:a=n.flattenArrayTypeChildren({child:e,arrayTypeChildren:a,newChildProps:s,nestedChildren:i});break;default:t=n.mapObjectTypeChildren({child:e,newProps:t,newChildProps:s,nestedChildren:i})}}})),this.mapArrayTypeChildrenToProps(a,t)},n.render=function(){var e=this.props,t=e.children,n=m(e,X),a=p({},n),i=n.helmetData;return t&&(a=this.mapChildrenToProps(t,a)),!i||i instanceof $||(i=new $(i.context,i.instances)),i?r.createElement(Q,p({},a,{context:i.value,helmetData:void 0})):r.createElement(U.Consumer,null,(function(e){return r.createElement(Q,p({},a,{context:e}))}))},t}(r.Component);J.propTypes={base:i().object,bodyAttributes:i().object,children:i().oneOfType([i().arrayOf(i().node),i().node]),defaultTitle:i().string,defer:i().bool,encodeSpecialCharacters:i().bool,htmlAttributes:i().object,link:i().arrayOf(i().object),meta:i().arrayOf(i().object),noscript:i().arrayOf(i().object),onChangeClientState:i().func,script:i().arrayOf(i().object),style:i().arrayOf(i().object),title:i().string,titleAttributes:i().object,titleTemplate:i().string,prioritizeSeoTags:i().bool,helmetData:i().object},J.defaultProps={defer:!0,encodeSpecialCharacters:!0,prioritizeSeoTags:!1},J.displayName="Helmet"},9921:(e,t)=>{"use strict";var n="function"==typeof Symbol&&Symbol.for,r=n?Symbol.for("react.element"):60103,a=n?Symbol.for("react.portal"):60106,i=n?Symbol.for("react.fragment"):60107,o=n?Symbol.for("react.strict_mode"):60108,s=n?Symbol.for("react.profiler"):60114,l=n?Symbol.for("react.provider"):60109,c=n?Symbol.for("react.context"):60110,u=n?Symbol.for("react.async_mode"):60111,d=n?Symbol.for("react.concurrent_mode"):60111,p=n?Symbol.for("react.forward_ref"):60112,f=n?Symbol.for("react.suspense"):60113,h=n?Symbol.for("react.suspense_list"):60120,m=n?Symbol.for("react.memo"):60115,g=n?Symbol.for("react.lazy"):60116,v=n?Symbol.for("react.block"):60121,y=n?Symbol.for("react.fundamental"):60117,b=n?Symbol.for("react.responder"):60118,w=n?Symbol.for("react.scope"):60119;function k(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case r:switch(e=e.type){case u:case d:case i:case s:case o:case f:return e;default:switch(e=e&&e.$$typeof){case c:case p:case g:case m:case l:return e;default:return t}}case a:return t}}}function x(e){return k(e)===d}t.AsyncMode=u,t.ConcurrentMode=d,t.ContextConsumer=c,t.ContextProvider=l,t.Element=r,t.ForwardRef=p,t.Fragment=i,t.Lazy=g,t.Memo=m,t.Portal=a,t.Profiler=s,t.StrictMode=o,t.Suspense=f,t.isAsyncMode=function(e){return x(e)||k(e)===u},t.isConcurrentMode=x,t.isContextConsumer=function(e){return k(e)===c},t.isContextProvider=function(e){return k(e)===l},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===r},t.isForwardRef=function(e){return k(e)===p},t.isFragment=function(e){return k(e)===i},t.isLazy=function(e){return k(e)===g},t.isMemo=function(e){return k(e)===m},t.isPortal=function(e){return k(e)===a},t.isProfiler=function(e){return k(e)===s},t.isStrictMode=function(e){return k(e)===o},t.isSuspense=function(e){return k(e)===f},t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===i||e===d||e===s||e===o||e===f||e===h||"object"==typeof e&&null!==e&&(e.$$typeof===g||e.$$typeof===m||e.$$typeof===l||e.$$typeof===c||e.$$typeof===p||e.$$typeof===y||e.$$typeof===b||e.$$typeof===w||e.$$typeof===v)},t.typeOf=k},9864:(e,t,n)=>{"use strict";e.exports=n(9921)},8356:(e,t,n)=>{"use strict";function r(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}function a(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(){return o=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},o.apply(this,arguments)}var s=n(7294),l=n(5697),c=[],u=[];function d(e){var t=e(),n={loading:!0,loaded:null,error:null};return n.promise=t.then((function(e){return n.loading=!1,n.loaded=e,e})).catch((function(e){throw n.loading=!1,n.error=e,e})),n}function p(e){var t={loading:!1,loaded:{},error:null},n=[];try{Object.keys(e).forEach((function(r){var a=d(e[r]);a.loading?t.loading=!0:(t.loaded[r]=a.loaded,t.error=a.error),n.push(a.promise),a.promise.then((function(e){t.loaded[r]=e})).catch((function(e){t.error=e}))}))}catch(r){t.error=r}return t.promise=Promise.all(n).then((function(e){return t.loading=!1,e})).catch((function(e){throw t.loading=!1,e})),t}function f(e,t){return s.createElement((n=e)&&n.__esModule?n.default:n,t);var n}function h(e,t){var d,p;if(!t.loading)throw new Error("react-loadable requires a `loading` component");var h=o({loader:null,loading:null,delay:200,timeout:null,render:f,webpack:null,modules:null},t),m=null;function g(){return m||(m=e(h.loader)),m.promise}return c.push(g),"function"==typeof h.webpack&&u.push((function(){if((0,h.webpack)().every((function(e){return void 0!==e&&void 0!==n.m[e]})))return g()})),p=d=function(t){function n(n){var r;return i(a(a(r=t.call(this,n)||this)),"retry",(function(){r.setState({error:null,loading:!0,timedOut:!1}),m=e(h.loader),r._loadModule()})),g(),r.state={error:m.error,pastDelay:!1,timedOut:!1,loading:m.loading,loaded:m.loaded},r}r(n,t),n.preload=function(){return g()};var o=n.prototype;return o.UNSAFE_componentWillMount=function(){this._loadModule()},o.componentDidMount=function(){this._mounted=!0},o._loadModule=function(){var e=this;if(this.context.loadable&&Array.isArray(h.modules)&&h.modules.forEach((function(t){e.context.loadable.report(t)})),m.loading){var t=function(t){e._mounted&&e.setState(t)};"number"==typeof h.delay&&(0===h.delay?this.setState({pastDelay:!0}):this._delay=setTimeout((function(){t({pastDelay:!0})}),h.delay)),"number"==typeof h.timeout&&(this._timeout=setTimeout((function(){t({timedOut:!0})}),h.timeout));var n=function(){t({error:m.error,loaded:m.loaded,loading:m.loading}),e._clearTimeouts()};m.promise.then((function(){return n(),null})).catch((function(e){return n(),null}))}},o.componentWillUnmount=function(){this._mounted=!1,this._clearTimeouts()},o._clearTimeouts=function(){clearTimeout(this._delay),clearTimeout(this._timeout)},o.render=function(){return this.state.loading||this.state.error?s.createElement(h.loading,{isLoading:this.state.loading,pastDelay:this.state.pastDelay,timedOut:this.state.timedOut,error:this.state.error,retry:this.retry}):this.state.loaded?h.render(this.state.loaded,this.props):null},n}(s.Component),i(d,"contextTypes",{loadable:l.shape({report:l.func.isRequired})}),p}function m(e){return h(d,e)}m.Map=function(e){if("function"!=typeof e.render)throw new Error("LoadableMap requires a `render(loaded, props)` function");return h(p,e)};var g=function(e){function t(){return e.apply(this,arguments)||this}r(t,e);var n=t.prototype;return n.getChildContext=function(){return{loadable:{report:this.props.report}}},n.render=function(){return s.Children.only(this.props.children)},t}(s.Component);function v(e){for(var t=[];e.length;){var n=e.pop();t.push(n())}return Promise.all(t).then((function(){if(e.length)return v(e)}))}i(g,"propTypes",{report:l.func.isRequired}),i(g,"childContextTypes",{loadable:l.shape({report:l.func.isRequired}).isRequired}),m.Capture=g,m.preloadAll=function(){return new Promise((function(e,t){v(c).then(e,t)}))},m.preloadReady=function(){return new Promise((function(e,t){v(u).then(e,e)}))},e.exports=m},8790:(e,t,n)=>{"use strict";n.d(t,{H:()=>s,f:()=>o});var r=n(6550),a=n(7462),i=n(7294);function o(e,t,n){return void 0===n&&(n=[]),e.some((function(e){var a=e.path?(0,r.LX)(t,e):n.length?n[n.length-1].match:r.F0.computeRootMatch(t);return a&&(n.push({route:e,match:a}),e.routes&&o(e.routes,t,n)),a})),n}function s(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),e?i.createElement(r.rs,n,e.map((function(e,n){return i.createElement(r.AW,{key:e.key||n,path:e.path,exact:e.exact,strict:e.strict,render:function(n){return e.render?e.render((0,a.Z)({},n,{},t,{route:e})):i.createElement(e.component,(0,a.Z)({},n,t,{route:e}))}})}))):null}},3727:(e,t,n)=>{"use strict";n.d(t,{OL:()=>b,VK:()=>u,rU:()=>g});var r=n(6550),a=n(5068),i=n(7294),o=n(9318),s=n(7462),l=n(3366),c=n(8776),u=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(t=e.call.apply(e,[this].concat(r))||this).history=(0,o.lX)(t.props),t}return(0,a.Z)(t,e),t.prototype.render=function(){return i.createElement(r.F0,{history:this.history,children:this.props.children})},t}(i.Component);i.Component;var d=function(e,t){return"function"==typeof e?e(t):e},p=function(e,t){return"string"==typeof e?(0,o.ob)(e,null,null,t):e},f=function(e){return e},h=i.forwardRef;void 0===h&&(h=f);var m=h((function(e,t){var n=e.innerRef,r=e.navigate,a=e.onClick,o=(0,l.Z)(e,["innerRef","navigate","onClick"]),c=o.target,u=(0,s.Z)({},o,{onClick:function(e){try{a&&a(e)}catch(t){throw e.preventDefault(),t}e.defaultPrevented||0!==e.button||c&&"_self"!==c||function(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}(e)||(e.preventDefault(),r())}});return u.ref=f!==h&&t||n,i.createElement("a",u)}));var g=h((function(e,t){var n=e.component,a=void 0===n?m:n,u=e.replace,g=e.to,v=e.innerRef,y=(0,l.Z)(e,["component","replace","to","innerRef"]);return i.createElement(r.s6.Consumer,null,(function(e){e||(0,c.Z)(!1);var n=e.history,r=p(d(g,e.location),e.location),l=r?n.createHref(r):"",m=(0,s.Z)({},y,{href:l,navigate:function(){var t=d(g,e.location),r=(0,o.Ep)(e.location)===(0,o.Ep)(p(t));(u||r?n.replace:n.push)(t)}});return f!==h?m.ref=t||v:m.innerRef=v,i.createElement(a,m)}))})),v=function(e){return e},y=i.forwardRef;void 0===y&&(y=v);var b=y((function(e,t){var n=e["aria-current"],a=void 0===n?"page":n,o=e.activeClassName,u=void 0===o?"active":o,f=e.activeStyle,h=e.className,m=e.exact,b=e.isActive,w=e.location,k=e.sensitive,x=e.strict,S=e.style,_=e.to,E=e.innerRef,C=(0,l.Z)(e,["aria-current","activeClassName","activeStyle","className","exact","isActive","location","sensitive","strict","style","to","innerRef"]);return i.createElement(r.s6.Consumer,null,(function(e){e||(0,c.Z)(!1);var n=w||e.location,o=p(d(_,n),n),l=o.pathname,T=l&&l.replace(/([.+*?=^!:${}()[\]|/\\])/g,"\\$1"),j=T?(0,r.LX)(n.pathname,{path:T,exact:m,sensitive:k,strict:x}):null,N=!!(b?b(j,n):j),L="function"==typeof h?h(N):h,A="function"==typeof S?S(N):S;N&&(L=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.filter((function(e){return e})).join(" ")}(L,u),A=(0,s.Z)({},A,f));var P=(0,s.Z)({"aria-current":N&&a||null,className:L,style:A,to:o},C);return v!==y?P.ref=t||E:P.innerRef=E,i.createElement(g,P)}))}))},6550:(e,t,n)=>{"use strict";n.d(t,{AW:()=>_,F0:()=>b,LX:()=>S,TH:()=>O,k6:()=>P,rs:()=>L,s6:()=>y});var r=n(5068),a=n(7294),i=n(5697),o=n.n(i),s=n(9318),l=n(8776),c=n(7462),u=n(4779),d=n.n(u),p=(n(9864),n(3366)),f=(n(8679),1073741823),h="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==n.g?n.g:{};var m=a.createContext||function(e,t){var n,i,s="__create-react-context-"+function(){var e="__global_unique_id__";return h[e]=(h[e]||0)+1}()+"__",l=function(e){function n(){for(var t,n,r,a=arguments.length,i=new Array(a),o=0;o<a;o++)i[o]=arguments[o];return(t=e.call.apply(e,[this].concat(i))||this).emitter=(n=t.props.value,r=[],{on:function(e){r.push(e)},off:function(e){r=r.filter((function(t){return t!==e}))},get:function(){return n},set:function(e,t){n=e,r.forEach((function(e){return e(n,t)}))}}),t}(0,r.Z)(n,e);var a=n.prototype;return a.getChildContext=function(){var e;return(e={})[s]=this.emitter,e},a.componentWillReceiveProps=function(e){if(this.props.value!==e.value){var n,r=this.props.value,a=e.value;((i=r)===(o=a)?0!==i||1/i==1/o:i!=i&&o!=o)?n=0:(n="function"==typeof t?t(r,a):f,0!==(n|=0)&&this.emitter.set(e.value,n))}var i,o},a.render=function(){return this.props.children},n}(a.Component);l.childContextTypes=((n={})[s]=o().object.isRequired,n);var c=function(t){function n(){for(var e,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(e=t.call.apply(t,[this].concat(r))||this).observedBits=void 0,e.state={value:e.getValue()},e.onUpdate=function(t,n){0!=((0|e.observedBits)&n)&&e.setState({value:e.getValue()})},e}(0,r.Z)(n,t);var a=n.prototype;return a.componentWillReceiveProps=function(e){var t=e.observedBits;this.observedBits=null==t?f:t},a.componentDidMount=function(){this.context[s]&&this.context[s].on(this.onUpdate);var e=this.props.observedBits;this.observedBits=null==e?f:e},a.componentWillUnmount=function(){this.context[s]&&this.context[s].off(this.onUpdate)},a.getValue=function(){return this.context[s]?this.context[s].get():e},a.render=function(){return(e=this.props.children,Array.isArray(e)?e[0]:e)(this.state.value);var e},n}(a.Component);return c.contextTypes=((i={})[s]=o().object,i),{Provider:l,Consumer:c}},g=function(e){var t=m();return t.displayName=e,t},v=g("Router-History"),y=g("Router"),b=function(e){function t(t){var n;return(n=e.call(this,t)||this).state={location:t.history.location},n._isMounted=!1,n._pendingLocation=null,t.staticContext||(n.unlisten=t.history.listen((function(e){n._pendingLocation=e}))),n}(0,r.Z)(t,e),t.computeRootMatch=function(e){return{path:"/",url:"/",params:{},isExact:"/"===e}};var n=t.prototype;return n.componentDidMount=function(){var e=this;this._isMounted=!0,this.unlisten&&this.unlisten(),this.props.staticContext||(this.unlisten=this.props.history.listen((function(t){e._isMounted&&e.setState({location:t})}))),this._pendingLocation&&this.setState({location:this._pendingLocation})},n.componentWillUnmount=function(){this.unlisten&&(this.unlisten(),this._isMounted=!1,this._pendingLocation=null)},n.render=function(){return a.createElement(y.Provider,{value:{history:this.props.history,location:this.state.location,match:t.computeRootMatch(this.state.location.pathname),staticContext:this.props.staticContext}},a.createElement(v.Provider,{children:this.props.children||null,value:this.props.history}))},t}(a.Component);a.Component;a.Component;var w={},k=1e4,x=0;function S(e,t){void 0===t&&(t={}),("string"==typeof t||Array.isArray(t))&&(t={path:t});var n=t,r=n.path,a=n.exact,i=void 0!==a&&a,o=n.strict,s=void 0!==o&&o,l=n.sensitive,c=void 0!==l&&l;return[].concat(r).reduce((function(t,n){if(!n&&""!==n)return null;if(t)return t;var r=function(e,t){var n=""+t.end+t.strict+t.sensitive,r=w[n]||(w[n]={});if(r[e])return r[e];var a=[],i={regexp:d()(e,a,t),keys:a};return x<k&&(r[e]=i,x++),i}(n,{end:i,strict:s,sensitive:c}),a=r.regexp,o=r.keys,l=a.exec(e);if(!l)return null;var u=l[0],p=l.slice(1),f=e===u;return i&&!f?null:{path:n,url:"/"===n&&""===u?"/":u,isExact:f,params:o.reduce((function(e,t,n){return e[t.name]=p[n],e}),{})}}),null)}var _=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.Z)(t,e),t.prototype.render=function(){var e=this;return a.createElement(y.Consumer,null,(function(t){t||(0,l.Z)(!1);var n=e.props.location||t.location,r=e.props.computedMatch?e.props.computedMatch:e.props.path?S(n.pathname,e.props):t.match,i=(0,c.Z)({},t,{location:n,match:r}),o=e.props,s=o.children,u=o.component,d=o.render;return Array.isArray(s)&&function(e){return 0===a.Children.count(e)}(s)&&(s=null),a.createElement(y.Provider,{value:i},i.match?s?"function"==typeof s?s(i):s:u?a.createElement(u,i):d?d(i):null:"function"==typeof s?s(i):null)}))},t}(a.Component);function E(e){return"/"===e.charAt(0)?e:"/"+e}function C(e,t){if(!e)return t;var n=E(e);return 0!==t.pathname.indexOf(n)?t:(0,c.Z)({},t,{pathname:t.pathname.substr(n.length)})}function T(e){return"string"==typeof e?e:(0,s.Ep)(e)}function j(e){return function(){(0,l.Z)(!1)}}function N(){}a.Component;var L=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.Z)(t,e),t.prototype.render=function(){var e=this;return a.createElement(y.Consumer,null,(function(t){t||(0,l.Z)(!1);var n,r,i=e.props.location||t.location;return a.Children.forEach(e.props.children,(function(e){if(null==r&&a.isValidElement(e)){n=e;var o=e.props.path||e.props.from;r=o?S(i.pathname,(0,c.Z)({},e.props,{path:o})):t.match}})),r?a.cloneElement(n,{location:i,computedMatch:r}):null}))},t}(a.Component);var A=a.useContext;function P(){return A(v)}function O(){return A(y).location}},5251:(e,t,n)=>{"use strict";var r=n(7294),a=Symbol.for("react.element"),i=Symbol.for("react.fragment"),o=Object.prototype.hasOwnProperty,s=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,l={key:!0,ref:!0,__self:!0,__source:!0};function c(e,t,n){var r,i={},c=null,u=null;for(r in void 0!==n&&(c=""+n),void 0!==t.key&&(c=""+t.key),void 0!==t.ref&&(u=t.ref),t)o.call(t,r)&&!l.hasOwnProperty(r)&&(i[r]=t[r]);if(e&&e.defaultProps)for(r in t=e.defaultProps)void 0===i[r]&&(i[r]=t[r]);return{$$typeof:a,type:e,key:c,ref:u,props:i,_owner:s.current}}t.Fragment=i,t.jsx=c,t.jsxs=c},2408:(e,t)=>{"use strict";var n=Symbol.for("react.element"),r=Symbol.for("react.portal"),a=Symbol.for("react.fragment"),i=Symbol.for("react.strict_mode"),o=Symbol.for("react.profiler"),s=Symbol.for("react.provider"),l=Symbol.for("react.context"),c=Symbol.for("react.forward_ref"),u=Symbol.for("react.suspense"),d=Symbol.for("react.memo"),p=Symbol.for("react.lazy"),f=Symbol.iterator;var h={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},m=Object.assign,g={};function v(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||h}function y(){}function b(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||h}v.prototype.isReactComponent={},v.prototype.setState=function(e,t){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")},v.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},y.prototype=v.prototype;var w=b.prototype=new y;w.constructor=b,m(w,v.prototype),w.isPureReactComponent=!0;var k=Array.isArray,x=Object.prototype.hasOwnProperty,S={current:null},_={key:!0,ref:!0,__self:!0,__source:!0};function E(e,t,r){var a,i={},o=null,s=null;if(null!=t)for(a in void 0!==t.ref&&(s=t.ref),void 0!==t.key&&(o=""+t.key),t)x.call(t,a)&&!_.hasOwnProperty(a)&&(i[a]=t[a]);var l=arguments.length-2;if(1===l)i.children=r;else if(1<l){for(var c=Array(l),u=0;u<l;u++)c[u]=arguments[u+2];i.children=c}if(e&&e.defaultProps)for(a in l=e.defaultProps)void 0===i[a]&&(i[a]=l[a]);return{$$typeof:n,type:e,key:o,ref:s,props:i,_owner:S.current}}function C(e){return"object"==typeof e&&null!==e&&e.$$typeof===n}var T=/\/+/g;function j(e,t){return"object"==typeof e&&null!==e&&null!=e.key?function(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,(function(e){return t[e]}))}(""+e.key):t.toString(36)}function N(e,t,a,i,o){var s=typeof e;"undefined"!==s&&"boolean"!==s||(e=null);var l=!1;if(null===e)l=!0;else switch(s){case"string":case"number":l=!0;break;case"object":switch(e.$$typeof){case n:case r:l=!0}}if(l)return o=o(l=e),e=""===i?"."+j(l,0):i,k(o)?(a="",null!=e&&(a=e.replace(T,"$&/")+"/"),N(o,t,a,"",(function(e){return e}))):null!=o&&(C(o)&&(o=function(e,t){return{$$typeof:n,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}(o,a+(!o.key||l&&l.key===o.key?"":(""+o.key).replace(T,"$&/")+"/")+e)),t.push(o)),1;if(l=0,i=""===i?".":i+":",k(e))for(var c=0;c<e.length;c++){var u=i+j(s=e[c],c);l+=N(s,t,a,u,o)}else if(u=function(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=f&&e[f]||e["@@iterator"])?e:null}(e),"function"==typeof u)for(e=u.call(e),c=0;!(s=e.next()).done;)l+=N(s=s.value,t,a,u=i+j(s,c++),o);else if("object"===s)throw t=String(e),Error("Objects are not valid as a React child (found: "+("[object Object]"===t?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.");return l}function L(e,t,n){if(null==e)return e;var r=[],a=0;return N(e,r,"","",(function(e){return t.call(n,e,a++)})),r}function A(e){if(-1===e._status){var t=e._result;(t=t()).then((function(t){0!==e._status&&-1!==e._status||(e._status=1,e._result=t)}),(function(t){0!==e._status&&-1!==e._status||(e._status=2,e._result=t)})),-1===e._status&&(e._status=0,e._result=t)}if(1===e._status)return e._result.default;throw e._result}var P={current:null},O={transition:null},R={ReactCurrentDispatcher:P,ReactCurrentBatchConfig:O,ReactCurrentOwner:S};t.Children={map:L,forEach:function(e,t,n){L(e,(function(){t.apply(this,arguments)}),n)},count:function(e){var t=0;return L(e,(function(){t++})),t},toArray:function(e){return L(e,(function(e){return e}))||[]},only:function(e){if(!C(e))throw Error("React.Children.only expected to receive a single React element child.");return e}},t.Component=v,t.Fragment=a,t.Profiler=o,t.PureComponent=b,t.StrictMode=i,t.Suspense=u,t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=R,t.cloneElement=function(e,t,r){if(null==e)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+e+".");var a=m({},e.props),i=e.key,o=e.ref,s=e._owner;if(null!=t){if(void 0!==t.ref&&(o=t.ref,s=S.current),void 0!==t.key&&(i=""+t.key),e.type&&e.type.defaultProps)var l=e.type.defaultProps;for(c in t)x.call(t,c)&&!_.hasOwnProperty(c)&&(a[c]=void 0===t[c]&&void 0!==l?l[c]:t[c])}var c=arguments.length-2;if(1===c)a.children=r;else if(1<c){l=Array(c);for(var u=0;u<c;u++)l[u]=arguments[u+2];a.children=l}return{$$typeof:n,type:e.type,key:i,ref:o,props:a,_owner:s}},t.createContext=function(e){return(e={$$typeof:l,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null,_defaultValue:null,_globalName:null}).Provider={$$typeof:s,_context:e},e.Consumer=e},t.createElement=E,t.createFactory=function(e){var t=E.bind(null,e);return t.type=e,t},t.createRef=function(){return{current:null}},t.forwardRef=function(e){return{$$typeof:c,render:e}},t.isValidElement=C,t.lazy=function(e){return{$$typeof:p,_payload:{_status:-1,_result:e},_init:A}},t.memo=function(e,t){return{$$typeof:d,type:e,compare:void 0===t?null:t}},t.startTransition=function(e){var t=O.transition;O.transition={};try{e()}finally{O.transition=t}},t.unstable_act=function(){throw Error("act(...) is not supported in production builds of React.")},t.useCallback=function(e,t){return P.current.useCallback(e,t)},t.useContext=function(e){return P.current.useContext(e)},t.useDebugValue=function(){},t.useDeferredValue=function(e){return P.current.useDeferredValue(e)},t.useEffect=function(e,t){return P.current.useEffect(e,t)},t.useId=function(){return P.current.useId()},t.useImperativeHandle=function(e,t,n){return P.current.useImperativeHandle(e,t,n)},t.useInsertionEffect=function(e,t){return P.current.useInsertionEffect(e,t)},t.useLayoutEffect=function(e,t){return P.current.useLayoutEffect(e,t)},t.useMemo=function(e,t){return P.current.useMemo(e,t)},t.useReducer=function(e,t,n){return P.current.useReducer(e,t,n)},t.useRef=function(e){return P.current.useRef(e)},t.useState=function(e){return P.current.useState(e)},t.useSyncExternalStore=function(e,t,n){return P.current.useSyncExternalStore(e,t,n)},t.useTransition=function(){return P.current.useTransition()},t.version="18.2.0"},7294:(e,t,n)=>{"use strict";e.exports=n(2408)},5893:(e,t,n)=>{"use strict";e.exports=n(5251)},53:(e,t)=>{"use strict";function n(e,t){var n=e.length;e.push(t);e:for(;0<n;){var r=n-1>>>1,a=e[r];if(!(0<i(a,t)))break e;e[r]=t,e[n]=a,n=r}}function r(e){return 0===e.length?null:e[0]}function a(e){if(0===e.length)return null;var t=e[0],n=e.pop();if(n!==t){e[0]=n;e:for(var r=0,a=e.length,o=a>>>1;r<o;){var s=2*(r+1)-1,l=e[s],c=s+1,u=e[c];if(0>i(l,n))c<a&&0>i(u,l)?(e[r]=u,e[c]=n,r=c):(e[r]=l,e[s]=n,r=s);else{if(!(c<a&&0>i(u,n)))break e;e[r]=u,e[c]=n,r=c}}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}if("object"==typeof performance&&"function"==typeof performance.now){var o=performance;t.unstable_now=function(){return o.now()}}else{var s=Date,l=s.now();t.unstable_now=function(){return s.now()-l}}var c=[],u=[],d=1,p=null,f=3,h=!1,m=!1,g=!1,v="function"==typeof setTimeout?setTimeout:null,y="function"==typeof clearTimeout?clearTimeout:null,b="undefined"!=typeof setImmediate?setImmediate:null;function w(e){for(var t=r(u);null!==t;){if(null===t.callback)a(u);else{if(!(t.startTime<=e))break;a(u),t.sortIndex=t.expirationTime,n(c,t)}t=r(u)}}function k(e){if(g=!1,w(e),!m)if(null!==r(c))m=!0,O(x);else{var t=r(u);null!==t&&R(k,t.startTime-e)}}function x(e,n){m=!1,g&&(g=!1,y(C),C=-1),h=!0;var i=f;try{for(w(n),p=r(c);null!==p&&(!(p.expirationTime>n)||e&&!N());){var o=p.callback;if("function"==typeof o){p.callback=null,f=p.priorityLevel;var s=o(p.expirationTime<=n);n=t.unstable_now(),"function"==typeof s?p.callback=s:p===r(c)&&a(c),w(n)}else a(c);p=r(c)}if(null!==p)var l=!0;else{var d=r(u);null!==d&&R(k,d.startTime-n),l=!1}return l}finally{p=null,f=i,h=!1}}"undefined"!=typeof navigator&&void 0!==navigator.scheduling&&void 0!==navigator.scheduling.isInputPending&&navigator.scheduling.isInputPending.bind(navigator.scheduling);var S,_=!1,E=null,C=-1,T=5,j=-1;function N(){return!(t.unstable_now()-j<T)}function L(){if(null!==E){var e=t.unstable_now();j=e;var n=!0;try{n=E(!0,e)}finally{n?S():(_=!1,E=null)}}else _=!1}if("function"==typeof b)S=function(){b(L)};else if("undefined"!=typeof MessageChannel){var A=new MessageChannel,P=A.port2;A.port1.onmessage=L,S=function(){P.postMessage(null)}}else S=function(){v(L,0)};function O(e){E=e,_||(_=!0,S())}function R(e,n){C=v((function(){e(t.unstable_now())}),n)}t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_continueExecution=function(){m||h||(m=!0,O(x))},t.unstable_forceFrameRate=function(e){0>e||125<e?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):T=0<e?Math.floor(1e3/e):5},t.unstable_getCurrentPriorityLevel=function(){return f},t.unstable_getFirstCallbackNode=function(){return r(c)},t.unstable_next=function(e){switch(f){case 1:case 2:case 3:var t=3;break;default:t=f}var n=f;f=t;try{return e()}finally{f=n}},t.unstable_pauseExecution=function(){},t.unstable_requestPaint=function(){},t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=f;f=e;try{return t()}finally{f=n}},t.unstable_scheduleCallback=function(e,a,i){var o=t.unstable_now();switch("object"==typeof i&&null!==i?i="number"==typeof(i=i.delay)&&0<i?o+i:o:i=o,e){case 1:var s=-1;break;case 2:s=250;break;case 5:s=1073741823;break;case 4:s=1e4;break;default:s=5e3}return e={id:d++,callback:a,priorityLevel:e,startTime:i,expirationTime:s=i+s,sortIndex:-1},i>o?(e.sortIndex=i,n(u,e),null===r(c)&&e===r(u)&&(g?(y(C),C=-1):g=!0,R(k,i-o))):(e.sortIndex=s,n(c,e),m||h||(m=!0,O(x))),e},t.unstable_shouldYield=N,t.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}},3840:(e,t,n)=>{"use strict";e.exports=n(53)},6774:e=>{e.exports=function(e,t,n,r){var a=n?n.call(r,e,t):void 0;if(void 0!==a)return!!a;if(e===t)return!0;if("object"!=typeof e||!e||"object"!=typeof t||!t)return!1;var i=Object.keys(e),o=Object.keys(t);if(i.length!==o.length)return!1;for(var s=Object.prototype.hasOwnProperty.bind(t),l=0;l<i.length;l++){var c=i[l];if(!s(c))return!1;var u=e[c],d=t[c];if(!1===(a=n?n.call(r,u,d,c):void 0)||void 0===a&&u!==d)return!1}return!0}},6809:(e,t,n)=>{"use strict";n.d(t,{default:()=>r});const r={title:"Interchain Security",tagline:"Interchain Security is a project to build a security layer for the Cosmos ecosystem.",url:"https://cosmos.github.io",baseUrl:"/interchain-security/",onBrokenLinks:"warn",onBrokenMarkdownLinks:"warn",favicon:"img/favicon.svg",trailingSlash:!1,organizationName:"cosmos",projectName:"interchain-security",i18n:{defaultLocale:"en",locales:["en"],path:"i18n",localeConfigs:{}},presets:[["classic",{docs:{sidebarPath:"/home/runner/work/interchain-security/interchain-security/docs/sidebars.js",routeBasePath:"/",versions:{current:{path:"/",label:"main",banner:"unreleased"},"v4.2.0-docs":{path:"/v4.2.0/",label:"v4.2.0",banner:"none"},"v5.0.0":{banner:"unreleased"}},remarkPlugins:[null],rehypePlugins:[null],exclude:["**/templates/*"]},theme:{customCss:"/home/runner/work/interchain-security/interchain-security/docs/src/css/custom.css"}}]],themeConfig:{image:"img/banner.png",docs:{sidebar:{autoCollapseCategories:!0,hideable:!1},versionPersistence:"localStorage"},colorMode:{defaultMode:"dark",disableSwitch:!1,respectPrefersColorScheme:!1},navbar:{title:"Interchain Security",hideOnScroll:!1,logo:{alt:"Interchain Security Logo",src:"/img/hub.svg",href:"/",target:"_self"},items:[{href:"https://github.com/cosmos/interchain-security",html:'<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="github-icon">\n <path fill-rule="evenodd" clip-rule="evenodd" d="M12 0.300049C5.4 0.300049 0 5.70005 0 12.3001C0 17.6001 3.4 22.1001 8.2 23.7001C8.8 23.8001 9 23.4001 9 23.1001C9 22.8001 9 22.1001 9 21.1001C5.7 21.8001 5 19.5001 5 19.5001C4.5 18.1001 3.7 17.7001 3.7 17.7001C2.5 17.0001 3.7 17.0001 3.7 17.0001C4.9 17.1001 5.5 18.2001 5.5 18.2001C6.6 20.0001 8.3 19.5001 9 19.2001C9.1 18.4001 9.4 17.9001 9.8 17.6001C7.1 17.3001 4.3 16.3001 4.3 11.7001C4.3 10.4001 4.8 9.30005 5.5 8.50005C5.5 8.10005 5 6.90005 5.7 5.30005C5.7 5.30005 6.7 5.00005 9 6.50005C10 6.20005 11 6.10005 12 6.10005C13 6.10005 14 6.20005 15 6.50005C17.3 4.90005 18.3 5.30005 18.3 5.30005C19 7.00005 18.5 8.20005 18.4 8.50005C19.2 9.30005 19.6 10.4001 19.6 11.7001C19.6 16.3001 16.8 17.3001 14.1 17.6001C14.5 18.0001 14.9 18.7001 14.9 19.8001C14.9 21.4001 14.9 22.7001 14.9 23.1001C14.9 23.4001 15.1 23.8001 15.7 23.7001C20.5 22.1001 23.9 17.6001 23.9 12.3001C24 5.70005 18.6 0.300049 12 0.300049Z" fill="currentColor"/>\n </svg>\n ',position:"right"},{type:"docsVersionDropdown",position:"left",dropdownActiveClassDisabled:!1,dropdownItemsAfter:[{href:"https://cosmos.github.io/interchain-security/legacy",label:"<= v3.x",target:"_blank"}],dropdownItemsBefore:[]}]},footer:{links:[{items:[{html:'<a href="https://cosmos.network"><img src="/interchain-security/img/logo-bw.svg" alt="Interchain Security Logo"></a>'}],title:null},{title:"Documentation",items:[{label:"Cosmos Hub",href:"https://hub.cosmos.network"},{label:"Cosmos SDK",href:"https://docs.cosmos.network"},{label:"Tendermint Core",href:"https://docs.tendermint.com"},{label:"IBC Go",href:"https://ibc.cosmos.network"}]},{title:"Community",items:[{label:"Blog",href:"https://blog.cosmos.network"},{label:"Forum",href:"https://forum.cosmos.network"},{label:"Discord",href:"https://discord.gg/cosmosnetwork"},{label:"Reddit",href:"https://reddit.com/r/cosmosnetwork"}]},{title:"Social",items:[{label:"Discord",href:"https://discord.gg/cosmosnetwork"},{label:"Twitter",href:"https://twitter.com/cosmos"},{label:"Youtube",href:"https://www.youtube.com/c/CosmosProject"},{label:"Telegram",href:"https://t.me/cosmosproject"}]}],copyright:"The development of Interchain Security is primarily led by Informal Systems. Funding for this development comes primarily from the Interchain Foundation, a Swiss non-profit.",style:"light"},prism:{theme:{plain:{color:"#393A34",backgroundColor:"#f6f8fa"},styles:[{types:["comment","prolog","doctype","cdata"],style:{color:"#999988",fontStyle:"italic"}},{types:["namespace"],style:{opacity:.7}},{types:["string","attr-value"],style:{color:"#e3116c"}},{types:["punctuation","operator"],style:{color:"#393A34"}},{types:["entity","url","symbol","number","boolean","variable","constant","property","regex","inserted"],style:{color:"#36acaa"}},{types:["atrule","keyword","attr-name","selector"],style:{color:"#00a4db"}},{types:["function","deleted","tag"],style:{color:"#d73a49"}},{types:["function-variable"],style:{color:"#6f42c1"}},{types:["tag","selector","keyword"],style:{color:"#00009f"}}]},darkTheme:{plain:{color:"#F8F8F2",backgroundColor:"#282A36"},styles:[{types:["prolog","constant","builtin"],style:{color:"rgb(189, 147, 249)"}},{types:["inserted","function"],style:{color:"rgb(80, 250, 123)"}},{types:["deleted"],style:{color:"rgb(255, 85, 85)"}},{types:["changed"],style:{color:"rgb(255, 184, 108)"}},{types:["punctuation","symbol"],style:{color:"rgb(248, 248, 242)"}},{types:["string","char","tag","selector"],style:{color:"rgb(255, 121, 198)"}},{types:["keyword","variable"],style:{color:"rgb(189, 147, 249)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(98, 114, 164)"}},{types:["attr-name"],style:{color:"rgb(241, 250, 140)"}}]},additionalLanguages:["protobuf","go-module","diff","go"],magicComments:[{className:"theme-code-block-highlighted-line",line:"highlight-next-line",block:{start:"highlight-start",end:"highlight-end"}}]},metadata:[],tableOfContents:{minHeadingLevel:2,maxHeadingLevel:3}},themes:["@you54f/theme-github-codeblock"],plugins:[null,["@docusaurus/plugin-client-redirects",{fromExtensions:["html"],toExtensions:["html"],redirects:[{from:["/main"],to:"/"}]}]],baseUrlIssueBanner:!0,onDuplicateRoutes:"warn",staticDirectories:["static"],customFields:{},scripts:[],headTags:[],stylesheets:[],clientModules:[],titleDelimiter:"|",noIndex:!1,markdown:{format:"mdx",mermaid:!1,mdx1Compat:{comments:!0,admonitions:!0,headingIds:!0}}}},7462:(e,t,n)=>{"use strict";function r(){return r=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},r.apply(this,arguments)}n.d(t,{Z:()=>r})},5068:(e,t,n)=>{"use strict";function r(e,t){return r=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},r(e,t)}function a(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,r(e,t)}n.d(t,{Z:()=>a})},3366:(e,t,n)=>{"use strict";function r(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}n.d(t,{Z:()=>r})},512:(e,t,n)=>{"use strict";function r(e){var t,n,a="";if("string"==typeof e||"number"==typeof e)a+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;t<e.length;t++)e[t]&&(n=r(e[t]))&&(a&&(a+=" "),a+=n);else for(t in e)e[t]&&(a&&(a+=" "),a+=t);return a}n.d(t,{Z:()=>a});const a=function(){for(var e,t,n=0,a="";n<arguments.length;)(e=arguments[n++])&&(t=r(e))&&(a&&(a+=" "),a+=t);return a}},2573:(e,t,n)=>{"use strict";n.d(t,{p1:()=>T,y$:()=>ee});var r,a,i,o,s,l,c,u=n(7294),d=n(512),p=Object.create,f=Object.defineProperty,h=Object.defineProperties,m=Object.getOwnPropertyDescriptor,g=Object.getOwnPropertyDescriptors,v=Object.getOwnPropertyNames,y=Object.getOwnPropertySymbols,b=Object.getPrototypeOf,w=Object.prototype.hasOwnProperty,k=Object.prototype.propertyIsEnumerable,x=(e,t,n)=>t in e?f(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,S=(e,t)=>{for(var n in t||(t={}))w.call(t,n)&&x(e,n,t[n]);if(y)for(var n of y(t))k.call(t,n)&&x(e,n,t[n]);return e},_=(e,t)=>h(e,g(t)),E=(e,t)=>{var n={};for(var r in e)w.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(null!=e&&y)for(var r of y(e))t.indexOf(r)<0&&k.call(e,r)&&(n[r]=e[r]);return n},C=(r={"../../node_modules/.pnpm/prismjs@1.29.0_patch_hash=vrxx3pzkik6jpmgpayxfjunetu/node_modules/prismjs/prism.js"(e,t){var n=function(){var e=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,n={},r={util:{encode:function e(t){return t instanceof a?new a(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function e(t,n){var a,i;switch(n=n||{},r.util.type(t)){case"Object":if(i=r.util.objId(t),n[i])return n[i];for(var o in a={},n[i]=a,t)t.hasOwnProperty(o)&&(a[o]=e(t[o],n));return a;case"Array":return i=r.util.objId(t),n[i]?n[i]:(a=[],n[i]=a,t.forEach((function(t,r){a[r]=e(t,n)})),a);default:return t}},getLanguage:function(t){for(;t;){var n=e.exec(t.className);if(n)return n[1].toLowerCase();t=t.parentElement}return"none"},setLanguage:function(t,n){t.className=t.className.replace(RegExp(e,"gi"),""),t.classList.add("language-"+n)},isActive:function(e,t,n){for(var r="no-"+t;e;){var a=e.classList;if(a.contains(t))return!0;if(a.contains(r))return!1;e=e.parentElement}return!!n}},languages:{plain:n,plaintext:n,text:n,txt:n,extend:function(e,t){var n=r.util.clone(r.languages[e]);for(var a in t)n[a]=t[a];return n},insertBefore:function(e,t,n,a){var i=(a=a||r.languages)[e],o={};for(var s in i)if(i.hasOwnProperty(s)){if(s==t)for(var l in n)n.hasOwnProperty(l)&&(o[l]=n[l]);n.hasOwnProperty(s)||(o[s]=i[s])}var c=a[e];return a[e]=o,r.languages.DFS(r.languages,(function(t,n){n===c&&t!=e&&(this[t]=o)})),o},DFS:function e(t,n,a,i){i=i||{};var o=r.util.objId;for(var s in t)if(t.hasOwnProperty(s)){n.call(t,s,t[s],a||s);var l=t[s],c=r.util.type(l);"Object"!==c||i[o(l)]?"Array"!==c||i[o(l)]||(i[o(l)]=!0,e(l,n,s,i)):(i[o(l)]=!0,e(l,n,null,i))}}},plugins:{},highlight:function(e,t,n){var i={code:e,grammar:t,language:n};if(r.hooks.run("before-tokenize",i),!i.grammar)throw new Error('The language "'+i.language+'" has no grammar.');return i.tokens=r.tokenize(i.code,i.grammar),r.hooks.run("after-tokenize",i),a.stringify(r.util.encode(i.tokens),i.language)},tokenize:function(e,t){var n=t.rest;if(n){for(var r in n)t[r]=n[r];delete t.rest}var a=new s;return l(a,a.head,e),o(e,a,t,a.head,0),function(e){for(var t=[],n=e.head.next;n!==e.tail;)t.push(n.value),n=n.next;return t}(a)},hooks:{all:{},add:function(e,t){var n=r.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=r.hooks.all[e];if(n&&n.length)for(var a,i=0;a=n[i++];)a(t)}},Token:a};function a(e,t,n,r){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length}function i(e,t,n,r){e.lastIndex=t;var a=e.exec(n);if(a&&r&&a[1]){var i=a[1].length;a.index+=i,a[0]=a[0].slice(i)}return a}function o(e,t,n,s,u,d){for(var p in n)if(n.hasOwnProperty(p)&&n[p]){var f=n[p];f=Array.isArray(f)?f:[f];for(var h=0;h<f.length;++h){if(d&&d.cause==p+","+h)return;var m=f[h],g=m.inside,v=!!m.lookbehind,y=!!m.greedy,b=m.alias;if(y&&!m.pattern.global){var w=m.pattern.toString().match(/[imsuy]*$/)[0];m.pattern=RegExp(m.pattern.source,w+"g")}for(var k=m.pattern||m,x=s.next,S=u;x!==t.tail&&!(d&&S>=d.reach);S+=x.value.length,x=x.next){var _=x.value;if(t.length>e.length)return;if(!(_ instanceof a)){var E,C=1;if(y){if(!(E=i(k,S,e,v))||E.index>=e.length)break;var T=E.index,j=E.index+E[0].length,N=S;for(N+=x.value.length;T>=N;)N+=(x=x.next).value.length;if(S=N-=x.value.length,x.value instanceof a)continue;for(var L=x;L!==t.tail&&(N<j||"string"==typeof L.value);L=L.next)C++,N+=L.value.length;C--,_=e.slice(S,N),E.index-=S}else if(!(E=i(k,0,_,v)))continue;T=E.index;var A=E[0],P=_.slice(0,T),O=_.slice(T+A.length),R=S+_.length;d&&R>d.reach&&(d.reach=R);var I=x.prev;if(P&&(I=l(t,I,P),S+=P.length),c(t,I,C),x=l(t,I,new a(p,g?r.tokenize(A,g):A,b,A)),O&&l(t,x,O),C>1){var F={cause:p+","+h,reach:R};o(e,t,n,x.prev,S,F),d&&F.reach>d.reach&&(d.reach=F.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function l(e,t,n){var r=t.next,a={value:n,prev:t,next:r};return t.next=a,r.prev=a,e.length++,a}function c(e,t,n){for(var r=t.next,a=0;a<n&&r!==e.tail;a++)r=r.next;t.next=r,r.prev=t,e.length-=a}return a.stringify=function e(t,n){if("string"==typeof t)return t;if(Array.isArray(t)){var a="";return t.forEach((function(t){a+=e(t,n)})),a}var i={type:t.type,content:e(t.content,n),tag:"span",classes:["token",t.type],attributes:{},language:n},o=t.alias;o&&(Array.isArray(o)?Array.prototype.push.apply(i.classes,o):i.classes.push(o)),r.hooks.run("wrap",i);var s="";for(var l in i.attributes)s+=" "+l+'="'+(i.attributes[l]||"").replace(/"/g,""")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'"'+s+">"+i.content+"</"+i.tag+">"},r}();t.exports=n,n.default=n}},function(){return a||(0,r[v(r)[0]])((a={exports:{}}).exports,a),a.exports}),T=((e,t,n)=>(n=null!=e?p(b(e)):{},((e,t,n,r)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let a of v(t))w.call(e,a)||a===n||f(e,a,{get:()=>t[a],enumerable:!(r=m(t,a))||r.enumerable});return e})(!t&&e&&e.__esModule?n:f(n,"default",{value:e,enumerable:!0}),e)))(C());T.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\s\S])*?-->/,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},T.languages.markup.tag.inside["attr-value"].inside.entity=T.languages.markup.entity,T.languages.markup.doctype.inside["internal-subset"].inside=T.languages.markup,T.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(T.languages.markup.tag,"addInlined",{value:function(e,t){var n;(t=((n=((n={})["language-"+t]={pattern:/(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,lookbehind:!0,inside:T.languages[t]},n.cdata=/^<!\[CDATA\[|\]\]>$/i,{"included-cdata":{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,inside:n}}))["language-"+t]={pattern:/[\s\S]+/,inside:T.languages[t]},{}))[e]={pattern:RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:n},T.languages.insertBefore("markup","cdata",t)}}),Object.defineProperty(T.languages.markup.tag,"addAttribute",{value:function(e,t){T.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:T.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),T.languages.html=T.languages.markup,T.languages.mathml=T.languages.markup,T.languages.svg=T.languages.markup,T.languages.xml=T.languages.extend("markup",{}),T.languages.ssml=T.languages.xml,T.languages.atom=T.languages.xml,T.languages.rss=T.languages.xml,i=T,o={pattern:/\\[\\(){}[\]^$+*?|.]/,alias:"escape"},l="(?:[^\\\\-]|"+(s=/\\(?:x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]+\}|0[0-7]{0,2}|[123][0-7]{2}|c[a-zA-Z]|.)/).source+")",l=RegExp(l+"-"+l),c={pattern:/(<|')[^<>']+(?=[>']$)/,lookbehind:!0,alias:"variable"},i.languages.regex={"char-class":{pattern:/((?:^|[^\\])(?:\\\\)*)\[(?:[^\\\]]|\\[\s\S])*\]/,lookbehind:!0,inside:{"char-class-negation":{pattern:/(^\[)\^/,lookbehind:!0,alias:"operator"},"char-class-punctuation":{pattern:/^\[|\]$/,alias:"punctuation"},range:{pattern:l,inside:{escape:s,"range-punctuation":{pattern:/-/,alias:"operator"}}},"special-escape":o,"char-set":{pattern:/\\[wsd]|\\p\{[^{}]+\}/i,alias:"class-name"},escape:s}},"special-escape":o,"char-set":{pattern:/\.|\\[wsd]|\\p\{[^{}]+\}/i,alias:"class-name"},backreference:[{pattern:/\\(?![123][0-7]{2})[1-9]/,alias:"keyword"},{pattern:/\\k<[^<>']+>/,alias:"keyword",inside:{"group-name":c}}],anchor:{pattern:/[$^]|\\[ABbGZz]/,alias:"function"},escape:s,group:[{pattern:/\((?:\?(?:<[^<>']+>|'[^<>']+'|[>:]|<?[=!]|[idmnsuxU]+(?:-[idmnsuxU]+)?:?))?/,alias:"punctuation",inside:{"group-name":c}},{pattern:/\)/,alias:"punctuation"}],quantifier:{pattern:/(?:[+*?]|\{\d+(?:,\d*)?\})[?+]?/,alias:"number"},alternation:{pattern:/\|/,alias:"keyword"}},T.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},T.languages.javascript=T.languages.extend("clike",{"class-name":[T.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),T.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,T.languages.insertBefore("javascript","keyword",{regex:{pattern:RegExp(/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source+/\//.source+"(?:"+/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source+"|"+/(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source+")"+/(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:T.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:T.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:T.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:T.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:T.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),T.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:T.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),T.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),T.languages.markup&&(T.languages.markup.tag.addInlined("script","javascript"),T.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),T.languages.js=T.languages.javascript,T.languages.actionscript=T.languages.extend("javascript",{keyword:/\b(?:as|break|case|catch|class|const|default|delete|do|dynamic|each|else|extends|final|finally|for|function|get|if|implements|import|in|include|instanceof|interface|internal|is|namespace|native|new|null|override|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|use|var|void|while|with)\b/,operator:/\+\+|--|(?:[+\-*\/%^]|&&?|\|\|?|<<?|>>?>?|[!=]=?)=?|[~?@]/}),T.languages.actionscript["class-name"].alias="function",delete T.languages.actionscript.parameter,delete T.languages.actionscript["literal-property"],T.languages.markup&&T.languages.insertBefore("actionscript","string",{xml:{pattern:/(^|[^.])<\/?\w+(?:\s+[^\s>\/=]+=("|')(?:\\[\s\S]|(?!\2)[^\\])*\2)*\s*\/?>/,lookbehind:!0,inside:T.languages.markup}}),function(e){var t=/#(?!\{).+/,n={pattern:/#\{[^}]+\}/,alias:"variable"};e.languages.coffeescript=e.languages.extend("javascript",{comment:t,string:[{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,inside:{interpolation:n}}],keyword:/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),e.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:t,interpolation:n}}}),e.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},script:{pattern:/[\s\S]+/,alias:"language-javascript",inside:e.languages.javascript}}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,greedy:!0,alias:"string"},{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string",inside:{interpolation:n}}]}),e.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/}),delete e.languages.coffeescript["template-string"],e.languages.coffee=e.languages.coffeescript}(T),function(e){var t=e.languages.javadoclike={parameter:{pattern:/(^[\t ]*(?:\/{3}|\*|\/\*\*)\s*@(?:arg|arguments|param)\s+)\w+/m,lookbehind:!0},keyword:{pattern:/(^[\t ]*(?:\/{3}|\*|\/\*\*)\s*|\{)@[a-z][a-zA-Z-]+\b/m,lookbehind:!0},punctuation:/[{}]/};Object.defineProperty(t,"addSupport",{value:function(t,n){(t="string"==typeof t?[t]:t).forEach((function(t){var r=function(e){e.inside||(e.inside={}),e.inside.rest=n},a="doc-comment";if(i=e.languages[t]){var i,o=i[a];if((o=o||(i=e.languages.insertBefore(t,"comment",{"doc-comment":{pattern:/(^|[^\\])\/\*\*[^/][\s\S]*?(?:\*\/|$)/,lookbehind:!0,alias:"comment"}}))[a])instanceof RegExp&&(o=i[a]={pattern:o}),Array.isArray(o))for(var s=0,l=o.length;s<l;s++)o[s]instanceof RegExp&&(o[s]={pattern:o[s]}),r(o[s]);else r(o)}}))}}),t.addSupport(["java","javascript","php"],t)}(T),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;(t=(e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:RegExp("@[\\w-](?:"+/[^;{\s"']|\s+(?!\s)/.source+"|"+t.source+")*?"+/(?:;|(?=\s*\{))/.source),inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css,e.languages.markup))&&(t.tag.addInlined("style","css"),t.tag.addAttribute("style","css"))}(T),function(e){var t=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,n=(t=(e.languages.css.selector={pattern:e.languages.css.selector.pattern,lookbehind:!0,inside:t={"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+/,class:/\.[-\w]+/,id:/#[-\w]+/,attribute:{pattern:RegExp("\\[(?:[^[\\]\"']|"+t.source+")*\\]"),greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)(?:(?!\s)[-*\w\xA0-\uFFFF])*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},"attr-name":{pattern:/^(\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+/,lookbehind:!0},"attr-value":[t,{pattern:/(=\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},"n-th":[{pattern:/(\(\s*)[+-]?\d*[\dn](?:\s*[+-]\s*\d+)?(?=\s*\))/,lookbehind:!0,inside:{number:/[\dn]+/,operator:/[+-]/}},{pattern:/(\(\s*)(?:even|odd)(?=\s*\))/i,lookbehind:!0}],combinator:/>|\+|~|\|\|/,punctuation:/[(),]/}},e.languages.css.atrule.inside["selector-function-argument"].inside=t,e.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*/i,lookbehind:!0}}),{pattern:/(\b\d+)(?:%|[a-z]+(?![\w-]))/,lookbehind:!0}),{pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0});e.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:{pattern:/\B#[\da-f]{3,8}\b/i,alias:"color"},color:[{pattern:/(^|[^\w-])(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|RebeccaPurple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)(?![\w-])/i,lookbehind:!0},{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:t,number:n,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:t,number:n})}(T),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",a=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-]<PLAIN>)(?:[ \t]*(?:(?![#:])<PLAIN>|:<PLAIN>))*/.source.replace(/<PLAIN>/g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),i=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function o(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<value>>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<<prop>>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<<prop>>/g,(function(){return r}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<<prop>>[ \t]+)?)<<key>>(?=\s*:\s)/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<key>>/g,(function(){return"(?:"+a+"|"+i+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:o(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:o(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:o(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:o(i),lookbehind:!0,greedy:!0},number:{pattern:o(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(T),function(e){var t=/(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source;function n(e){return e=e.replace(/<inner>/g,(function(){return t})),RegExp(/((?:^|[^\\])(?:\\{2})*)/.source+"(?:"+e+")")}var r=/(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source,a=/\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g,(function(){return r})),i=/\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source,o=(e.languages.markdown=e.languages.extend("markup",{}),e.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"front-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:e.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+a+i+"(?:"+a+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+a+i+")(?:"+a+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(r),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+a+")"+i+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+a+"$"),inside:{"table-header":{pattern:RegExp(r),alias:"important",inside:e.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n(/\b__(?:(?!_)<inner>|_(?:(?!_)<inner>)+_)+__\b|\*\*(?:(?!\*)<inner>|\*(?:(?!\*)<inner>)+\*)+\*\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/\b_(?:(?!_)<inner>|__(?:(?!_)<inner>)+__)+_\b|\*(?:(?!\*)<inner>|\*\*(?:(?!\*)<inner>)+\*\*)+\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~)<inner>)+\2/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:n(/!?\[(?:(?!\])<inner>)+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\])<inner>)+\])/.source),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(t){["url","bold","italic","strike","code-snippet"].forEach((function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])}))})),e.hooks.add("after-tokenize",(function(e){"markdown"!==e.language&&"md"!==e.language||function e(t){if(t&&"string"!=typeof t)for(var n=0,r=t.length;n<r;n++){var a,i=t[n];"code"!==i.type?e(i.content):(a=i.content[1],i=i.content[3],a&&i&&"code-language"===a.type&&"code-block"===i.type&&"string"==typeof a.content&&(a=a.content.replace(/\b#/g,"sharp").replace(/\b\+\+/g,"pp"),a="language-"+(a=(/[a-z][\w-]*/i.exec(a)||[""])[0].toLowerCase()),i.alias?"string"==typeof i.alias?i.alias=[i.alias,a]:i.alias.push(a):i.alias=[a]))}}(e.tokens)})),e.hooks.add("wrap",(function(t){if("code-block"===t.type){for(var n="",r=0,a=t.classes.length;r<a;r++){var i=t.classes[r];if(i=/language-(.+)/.exec(i)){n=i[1];break}}var c,u=e.languages[n];u?t.content=e.highlight(t.content.replace(o,"").replace(/&(\w{1,8}|#x?[\da-f]{1,8});/gi,(function(e,t){var n;return"#"===(t=t.toLowerCase())[0]?(n="x"===t[1]?parseInt(t.slice(2),16):Number(t.slice(1)),l(n)):s[t]||e})),u,n):n&&"none"!==n&&e.plugins.autoloader&&(c="md-"+(new Date).valueOf()+"-"+Math.floor(1e16*Math.random()),t.attributes.id=c,e.plugins.autoloader.loadLanguages(n,(function(){var t=document.getElementById(c);t&&(t.innerHTML=e.highlight(t.textContent,e.languages[n],n))})))}})),RegExp(e.languages.markup.tag.pattern.source,"gi")),s={amp:"&",lt:"<",gt:">",quot:'"'},l=String.fromCodePoint||String.fromCharCode;e.languages.md=e.languages.markdown}(T),T.languages.graphql={comment:/#.*/,description:{pattern:/(?:"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*")(?=\s*[a-z_])/i,greedy:!0,alias:"string",inside:{"language-markdown":{pattern:/(^"(?:"")?)(?!\1)[\s\S]+(?=\1$)/,lookbehind:!0,inside:T.languages.markdown}}},string:{pattern:/"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},number:/(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,boolean:/\b(?:false|true)\b/,variable:/\$[a-z_]\w*/i,directive:{pattern:/@[a-z_]\w*/i,alias:"function"},"attr-name":{pattern:/\b[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i,greedy:!0},"atom-input":{pattern:/\b[A-Z]\w*Input\b/,alias:"class-name"},scalar:/\b(?:Boolean|Float|ID|Int|String)\b/,constant:/\b[A-Z][A-Z_\d]*\b/,"class-name":{pattern:/(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*|:\s*|\[)[A-Z_]\w*/,lookbehind:!0},fragment:{pattern:/(\bfragment\s+|\.{3}\s*(?!on\b))[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-mutation":{pattern:/(\bmutation\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-query":{pattern:/(\bquery\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},keyword:/\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\b/,operator:/[!=|&]|\.{3}/,"property-query":/\w+(?=\s*\()/,object:/\w+(?=\s*\{)/,punctuation:/[!(){}\[\]:=,]/,property:/\w+/},T.hooks.add("after-tokenize",(function(e){if("graphql"===e.language)for(var t=e.tokens.filter((function(e){return"string"!=typeof e&&"comment"!==e.type&&"scalar"!==e.type})),n=0;n<t.length;){var r=t[n++];if("keyword"===r.type&&"mutation"===r.content){var a=[];if(d(["definition-mutation","punctuation"])&&"("===u(1).content){n+=2;var i=p(/^\($/,/^\)$/);if(-1===i)continue;for(;n<i;n++){var o=u(0);"variable"===o.type&&(f(o,"variable-input"),a.push(o.content))}n=i+1}if(d(["punctuation","property-query"])&&"{"===u(0).content&&(n++,f(u(0),"property-mutation"),0<a.length)){var s=p(/^\{$/,/^\}$/);if(-1!==s)for(var l=n;l<s;l++){var c=t[l];"variable"===c.type&&0<=a.indexOf(c.content)&&f(c,"variable-input")}}}}function u(e){return t[n+e]}function d(e,t){t=t||0;for(var n=0;n<e.length;n++){var r=u(n+t);if(!r||r.type!==e[n])return}return 1}function p(e,r){for(var a=1,i=n;i<t.length;i++){var o=t[i],s=o.content;if("punctuation"===o.type&&"string"==typeof s)if(e.test(s))a++;else if(r.test(s)&&0==--a)return i}return-1}function f(e,t){var n=e.alias;n?Array.isArray(n)||(e.alias=n=[n]):e.alias=n=[],n.push(t)}})),T.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},identifier:{pattern:/(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,greedy:!0,lookbehind:!0,inside:{punctuation:/^`|`$/}},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:FALSE|NULL|TRUE)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t=e.languages.javascript["template-string"],n=t.pattern.source,r=t.inside.interpolation,a=r.inside["interpolation-punctuation"],i=r.pattern.source;function o(t,r){if(e.languages[t])return{pattern:RegExp("((?:"+r+")\\s*)"+n),lookbehind:!0,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},"embedded-code":{pattern:/[\s\S]+/,alias:t}}}}function s(t,n,r){return t={code:t,grammar:n,language:r},e.hooks.run("before-tokenize",t),t.tokens=e.tokenize(t.code,t.grammar),e.hooks.run("after-tokenize",t),t.tokens}function l(t,n,o){var l=e.tokenize(t,{interpolation:{pattern:RegExp(i),lookbehind:!0}}),c=0,u={},d=(l=s(l.map((function(e){if("string"==typeof e)return e;var n,r;for(e=e.content;-1!==t.indexOf((r=c++,n="___"+o.toUpperCase()+"_"+r+"___")););return u[n]=e,n})).join(""),n,o),Object.keys(u));return c=0,function t(n){for(var i=0;i<n.length;i++){if(c>=d.length)return;var o,l,p,f,h,m,g,v=n[i];"string"==typeof v||"string"==typeof v.content?(o=d[c],-1!==(g=(m="string"==typeof v?v:v.content).indexOf(o))&&(++c,l=m.substring(0,g),h=u[o],p=void 0,(f={})["interpolation-punctuation"]=a,3===(f=e.tokenize(h,f)).length&&((p=[1,1]).push.apply(p,s(f[1],e.languages.javascript,"javascript")),f.splice.apply(f,p)),p=new e.Token("interpolation",f,r.alias,h),f=m.substring(g+o.length),h=[],l&&h.push(l),h.push(p),f&&(t(m=[f]),h.push.apply(h,m)),"string"==typeof v?(n.splice.apply(n,[i,1].concat(h)),i+=h.length-1):v.content=h)):(g=v.content,Array.isArray(g)?t(g):t([g]))}}(l),new e.Token(o,l,"language-"+o,t)}e.languages.javascript["template-string"]=[o("css",/\b(?:styled(?:\([^)]*\))?(?:\s*\.\s*\w+(?:\([^)]*\))*)*|css(?:\s*\.\s*(?:global|resolve))?|createGlobalStyle|keyframes)/.source),o("html",/\bhtml|\.\s*(?:inner|outer)HTML\s*\+?=/.source),o("svg",/\bsvg/.source),o("markdown",/\b(?:markdown|md)/.source),o("graphql",/\b(?:gql|graphql(?:\s*\.\s*experimental)?)/.source),o("sql",/\bsql/.source),t].filter(Boolean);var c={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function u(e){return"string"==typeof e?e:Array.isArray(e)?e.map(u).join(""):u(e.content)}e.hooks.add("after-tokenize",(function(t){t.language in c&&function t(n){for(var r=0,a=n.length;r<a;r++){var i,o,s,c=n[r];"string"!=typeof c&&(i=c.content,Array.isArray(i)?"template-string"===c.type?(c=i[1],3===i.length&&"string"!=typeof c&&"embedded-code"===c.type&&(o=u(c),c=c.alias,c=Array.isArray(c)?c[0]:c,s=e.languages[c])&&(i[1]=l(o,s,c))):t(i):"string"!=typeof i&&t([i]))}}(t.tokens)}))}(T),function(e){e.languages.typescript=e.languages.extend("javascript",{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var t=e.languages.extend("typescript",{});delete t["class-name"],e.languages.typescript["class-name"].inside=t,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t}}}}),e.languages.ts=e.languages.typescript}(T),function(e){var t=e.languages.javascript,n=/\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})+\}/.source,r="(@(?:arg|argument|param|property)\\s+(?:"+n+"\\s+)?)";e.languages.jsdoc=e.languages.extend("javadoclike",{parameter:{pattern:RegExp(r+/(?:(?!\s)[$\w\xA0-\uFFFF.])+(?=\s|$)/.source),lookbehind:!0,inside:{punctuation:/\./}}}),e.languages.insertBefore("jsdoc","keyword",{"optional-parameter":{pattern:RegExp(r+/\[(?:(?!\s)[$\w\xA0-\uFFFF.])+(?:=[^[\]]+)?\](?=\s|$)/.source),lookbehind:!0,inside:{parameter:{pattern:/(^\[)[$\w\xA0-\uFFFF\.]+/,lookbehind:!0,inside:{punctuation:/\./}},code:{pattern:/(=)[\s\S]*(?=\]$)/,lookbehind:!0,inside:t,alias:"language-javascript"},punctuation:/[=[\]]/}},"class-name":[{pattern:RegExp(/(@(?:augments|class|extends|interface|memberof!?|template|this|typedef)\s+(?:<TYPE>\s+)?)[A-Z]\w*(?:\.[A-Z]\w*)*/.source.replace(/<TYPE>/g,(function(){return n}))),lookbehind:!0,inside:{punctuation:/\./}},{pattern:RegExp("(@[a-z]+\\s+)"+n),lookbehind:!0,inside:{string:t.string,number:t.number,boolean:t.boolean,keyword:e.languages.typescript.keyword,operator:/=>|\.\.\.|[&|?:*]/,punctuation:/[.,;=<>{}()[\]]/}}],example:{pattern:/(@example\s+(?!\s))(?:[^@\s]|\s+(?!\s))+?(?=\s*(?:\*\s*)?(?:@\w|\*\/))/,lookbehind:!0,inside:{code:{pattern:/^([\t ]*(?:\*\s*)?)\S.*$/m,lookbehind:!0,inside:t,alias:"language-javascript"}}}}),e.languages.javadoclike.addSupport("javascript",e.languages.jsdoc)}(T),function(e){e.languages.flow=e.languages.extend("javascript",{}),e.languages.insertBefore("flow","keyword",{type:[{pattern:/\b(?:[Bb]oolean|Function|[Nn]umber|[Ss]tring|[Ss]ymbol|any|mixed|null|void)\b/,alias:"class-name"}]}),e.languages.flow["function-variable"].pattern=/(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=\s*(?:function\b|(?:\([^()]*\)(?:\s*:\s*\w+)?|(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/i,delete e.languages.flow.parameter,e.languages.insertBefore("flow","operator",{"flow-punctuation":{pattern:/\{\||\|\}/,alias:"punctuation"}}),Array.isArray(e.languages.flow.keyword)||(e.languages.flow.keyword=[e.languages.flow.keyword]),e.languages.flow.keyword.unshift({pattern:/(^|[^$]\b)(?:Class|declare|opaque|type)\b(?!\$)/,lookbehind:!0},{pattern:/(^|[^$]\B)\$(?:Diff|Enum|Exact|Keys|ObjMap|PropertyType|Record|Shape|Subtype|Supertype|await)\b(?!\$)/,lookbehind:!0})}(T),T.languages.n4js=T.languages.extend("javascript",{keyword:/\b(?:Array|any|boolean|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|false|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|module|new|null|number|package|private|protected|public|return|set|static|string|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/}),T.languages.insertBefore("n4js","constant",{annotation:{pattern:/@+\w+/,alias:"operator"}}),T.languages.n4jsd=T.languages.n4js,function(e){function t(e,t){return RegExp(e.replace(/<ID>/g,(function(){return/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/.source})),t)}e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|(?:Weak)?(?:Map|Set)|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.insertBefore("javascript","keyword",{imports:{pattern:t(/(\bimport\b\s*)(?:<ID>(?:\s*,\s*(?:\*\s*as\s+<ID>|\{[^{}]*\}))?|\*\s*as\s+<ID>|\{[^{}]*\})(?=\s*\bfrom\b)/.source),lookbehind:!0,inside:e.languages.javascript},exports:{pattern:t(/(\bexport\b\s*)(?:\*(?:\s*as\s+<ID>)?(?=\s*\bfrom\b)|\{[^{}]*\})/.source),lookbehind:!0,inside:e.languages.javascript}}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\b(?:await|break|catch|continue|do|else|finally|for|if|return|switch|throw|try|while|yield)\b/,alias:"control-flow"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:t(/(\.\s*)#?<ID>/.source),lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|(?:local|session)Storage|location|navigator|performance|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var n=["function","function-variable","method","method-variable","property-access"],r=0;r<n.length;r++){var a=n[r],i=e.languages.javascript[a];a=(i="RegExp"===e.util.type(i)?e.languages.javascript[a]={pattern:i}:i).inside||{};(i.inside=a)["maybe-class-name"]=/^[A-Z][\s\S]*/}}(T),function(e){var t=e.util.clone(e.languages.javascript),n=/(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source,r=/(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source,a=/(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;function i(e,t){return e=e.replace(/<S>/g,(function(){return n})).replace(/<BRACES>/g,(function(){return r})).replace(/<SPREAD>/g,(function(){return a})),RegExp(e,t)}function o(t){for(var n=[],r=0;r<t.length;r++){var a=t[r],i=!1;"string"!=typeof a&&("tag"===a.type&&a.content[0]&&"tag"===a.content[0].type?"</"===a.content[0].content[0].content?0<n.length&&n[n.length-1].tagName===s(a.content[0].content[1])&&n.pop():"/>"!==a.content[a.content.length-1].content&&n.push({tagName:s(a.content[0].content[1]),openedBraces:0}):0<n.length&&"punctuation"===a.type&&"{"===a.content?n[n.length-1].openedBraces++:0<n.length&&0<n[n.length-1].openedBraces&&"punctuation"===a.type&&"}"===a.content?n[n.length-1].openedBraces--:i=!0),(i||"string"==typeof a)&&0<n.length&&0===n[n.length-1].openedBraces&&(i=s(a),r<t.length-1&&("string"==typeof t[r+1]||"plain-text"===t[r+1].type)&&(i+=s(t[r+1]),t.splice(r+1,1)),0<r&&("string"==typeof t[r-1]||"plain-text"===t[r-1].type)&&(i=s(t[r-1])+i,t.splice(r-1,1),r--),t[r]=new e.Token("plain-text",i,null,i)),a.content&&"string"!=typeof a.content&&o(a.content)}}a=i(a).source,e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=i(/<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:i(/<SPREAD>/.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:i(/=<BRACES>/.source),alias:"language-javascript",inside:{"script-punctuation":{pattern:/^=(?=\{)/,alias:"punctuation"},rest:e.languages.jsx}}},e.languages.jsx.tag);var s=function(e){return e?"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(s).join(""):""};e.hooks.add("after-tokenize",(function(e){"jsx"!==e.language&&"tsx"!==e.language||o(e.tokens)}))}(T),function(e){var t=e.util.clone(e.languages.typescript);(t=(e.languages.tsx=e.languages.extend("jsx",t),delete e.languages.tsx.parameter,delete e.languages.tsx["literal-property"],e.languages.tsx.tag)).pattern=RegExp(/(^|[^\w$]|(?=<\/))/.source+"(?:"+t.pattern.source+")",t.pattern.flags),t.lookbehind=!0}(T),T.languages.swift={comment:{pattern:/(^|[^\\:])(?:\/\/.*|\/\*(?:[^/*]|\/(?!\*)|\*(?!\/)|\/\*(?:[^*]|\*(?!\/))*\*\/)*\*\/)/,lookbehind:!0,greedy:!0},"string-literal":[{pattern:RegExp(/(^|[^"#])/.source+"(?:"+/"(?:\\(?:\((?:[^()]|\([^()]*\))*\)|\r\n|[^(])|[^\\\r\n"])*"/.source+"|"+/"""(?:\\(?:\((?:[^()]|\([^()]*\))*\)|[^(])|[^\\"]|"(?!""))*"""/.source+")"+/(?!["#])/.source),lookbehind:!0,greedy:!0,inside:{interpolation:{pattern:/(\\\()(?:[^()]|\([^()]*\))*(?=\))/,lookbehind:!0,inside:null},"interpolation-punctuation":{pattern:/^\)|\\\($/,alias:"punctuation"},punctuation:/\\(?=[\r\n])/,string:/[\s\S]+/}},{pattern:RegExp(/(^|[^"#])(#+)/.source+"(?:"+/"(?:\\(?:#+\((?:[^()]|\([^()]*\))*\)|\r\n|[^#])|[^\\\r\n])*?"/.source+"|"+/"""(?:\\(?:#+\((?:[^()]|\([^()]*\))*\)|[^#])|[^\\])*?"""/.source+")\\2"),lookbehind:!0,greedy:!0,inside:{interpolation:{pattern:/(\\#+\()(?:[^()]|\([^()]*\))*(?=\))/,lookbehind:!0,inside:null},"interpolation-punctuation":{pattern:/^\)|\\#+\($/,alias:"punctuation"},string:/[\s\S]+/}}],directive:{pattern:RegExp(/#/.source+"(?:"+/(?:elseif|if)\b/.source+"(?:[ \t]*"+/(?:![ \t]*)?(?:\b\w+\b(?:[ \t]*\((?:[^()]|\([^()]*\))*\))?|\((?:[^()]|\([^()]*\))*\))(?:[ \t]*(?:&&|\|\|))?/.source+")+|"+/(?:else|endif)\b/.source+")"),alias:"property",inside:{"directive-name":/^#\w+/,boolean:/\b(?:false|true)\b/,number:/\b\d+(?:\.\d+)*\b/,operator:/!|&&|\|\||[<>]=?/,punctuation:/[(),]/}},literal:{pattern:/#(?:colorLiteral|column|dsohandle|file(?:ID|Literal|Path)?|function|imageLiteral|line)\b/,alias:"constant"},"other-directive":{pattern:/#\w+\b/,alias:"property"},attribute:{pattern:/@\w+/,alias:"atrule"},"function-definition":{pattern:/(\bfunc\s+)\w+/,lookbehind:!0,alias:"function"},label:{pattern:/\b(break|continue)\s+\w+|\b[a-zA-Z_]\w*(?=\s*:\s*(?:for|repeat|while)\b)/,lookbehind:!0,alias:"important"},keyword:/\b(?:Any|Protocol|Self|Type|actor|as|assignment|associatedtype|associativity|async|await|break|case|catch|class|continue|convenience|default|defer|deinit|didSet|do|dynamic|else|enum|extension|fallthrough|fileprivate|final|for|func|get|guard|higherThan|if|import|in|indirect|infix|init|inout|internal|is|isolated|lazy|left|let|lowerThan|mutating|none|nonisolated|nonmutating|open|operator|optional|override|postfix|precedencegroup|prefix|private|protocol|public|repeat|required|rethrows|return|right|safe|self|set|some|static|struct|subscript|super|switch|throw|throws|try|typealias|unowned|unsafe|var|weak|where|while|willSet)\b/,boolean:/\b(?:false|true)\b/,nil:{pattern:/\bnil\b/,alias:"constant"},"short-argument":/\$\d+\b/,omit:{pattern:/\b_\b/,alias:"keyword"},number:/\b(?:[\d_]+(?:\.[\de_]+)?|0x[a-f0-9_]+(?:\.[a-f0-9p_]+)?|0b[01_]+|0o[0-7_]+)\b/i,"class-name":/\b[A-Z](?:[A-Z_\d]*[a-z]\w*)?\b/,function:/\b[a-z_]\w*(?=\s*\()/i,constant:/\b(?:[A-Z_]{2,}|k[A-Z][A-Za-z_]+)\b/,operator:/[-+*/%=!<>&|^~?]+|\.[.\-+*/%=!<>&|^~?]+/,punctuation:/[{}[\]();,.:\\]/},T.languages.swift["string-literal"].forEach((function(e){e.inside.interpolation.inside=T.languages.swift})),function(e){e.languages.kotlin=e.languages.extend("clike",{keyword:{pattern:/(^|[^.])\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\b/,lookbehind:!0},function:[{pattern:/(?:`[^\r\n`]+`|\b\w+)(?=\s*\()/,greedy:!0},{pattern:/(\.)(?:`[^\r\n`]+`|\w+)(?=\s*\{)/,lookbehind:!0,greedy:!0}],number:/\b(?:0[xX][\da-fA-F]+(?:_[\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?[fFL]?)\b/,operator:/\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/}),delete e.languages.kotlin["class-name"];var t={"interpolation-punctuation":{pattern:/^\$\{?|\}$/,alias:"punctuation"},expression:{pattern:/[\s\S]+/,inside:e.languages.kotlin}};e.languages.insertBefore("kotlin","string",{"string-literal":[{pattern:/"""(?:[^$]|\$(?:(?!\{)|\{[^{}]*\}))*?"""/,alias:"multiline",inside:{interpolation:{pattern:/\$(?:[a-z_]\w*|\{[^{}]*\})/i,inside:t},string:/[\s\S]+/}},{pattern:/"(?:[^"\\\r\n$]|\\.|\$(?:(?!\{)|\{[^{}]*\}))*"/,alias:"singleline",inside:{interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$(?:[a-z_]\w*|\{[^{}]*\})/i,lookbehind:!0,inside:t},string:/[\s\S]+/}}],char:{pattern:/'(?:[^'\\\r\n]|\\(?:.|u[a-fA-F0-9]{0,4}))'/,greedy:!0}}),delete e.languages.kotlin.string,e.languages.insertBefore("kotlin","keyword",{annotation:{pattern:/\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/,alias:"builtin"}}),e.languages.insertBefore("kotlin","function",{label:{pattern:/\b\w+@|@\w+\b/,alias:"symbol"}}),e.languages.kt=e.languages.kotlin,e.languages.kts=e.languages.kotlin}(T),T.languages.c=T.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),T.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),T.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},T.languages.c.string],char:T.languages.c.char,comment:T.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:T.languages.c}}}}),T.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete T.languages.c.boolean,T.languages.objectivec=T.languages.extend("c",{string:{pattern:/@?"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},keyword:/\b(?:asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|in|inline|int|long|register|return|self|short|signed|sizeof|static|struct|super|switch|typedef|typeof|union|unsigned|void|volatile|while)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/,operator:/-[->]?|\+\+?|!=?|<<?=?|>>?=?|==?|&&?|\|\|?|[~^%?*\/@]/}),delete T.languages.objectivec["class-name"],T.languages.objc=T.languages.objectivec,T.languages.reason=T.languages.extend("clike",{string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},"class-name":/\b[A-Z]\w*/,keyword:/\b(?:and|as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|method|module|mutable|new|nonrec|object|of|open|or|private|rec|sig|struct|switch|then|to|try|type|val|virtual|when|while|with)\b/,operator:/\.{3}|:[:=]|\|>|->|=(?:==?|>)?|<=?|>=?|[|^?'#!~`]|[+\-*\/]\.?|\b(?:asr|land|lor|lsl|lsr|lxor|mod)\b/}),T.languages.insertBefore("reason","class-name",{char:{pattern:/'(?:\\x[\da-f]{2}|\\o[0-3][0-7][0-7]|\\\d{3}|\\.|[^'\\\r\n])'/,greedy:!0},constructor:/\b[A-Z]\w*\b(?!\s*\.)/,label:{pattern:/\b[a-z]\w*(?=::)/,alias:"symbol"}}),delete T.languages.reason.function,function(e){for(var t=/\/\*(?:[^*/]|\*(?!\/)|\/(?!\*)|<self>)*\*\//.source,n=0;n<2;n++)t=t.replace(/<self>/g,(function(){return t}));t=t.replace(/<self>/g,(function(){return/[^\s\S]/.source})),e.languages.rust={comment:[{pattern:RegExp(/(^|[^\\])/.source+t),lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/b?"(?:\\[\s\S]|[^\\"])*"|b?r(#*)"(?:[^"]|"(?!\1))*"\1/,greedy:!0},char:{pattern:/b?'(?:\\(?:x[0-7][\da-fA-F]|u\{(?:[\da-fA-F]_*){1,6}\}|.)|[^\\\r\n\t'])'/,greedy:!0},attribute:{pattern:/#!?\[(?:[^\[\]"]|"(?:\\[\s\S]|[^\\"])*")*\]/,greedy:!0,alias:"attr-name",inside:{string:null}},"closure-params":{pattern:/([=(,:]\s*|\bmove\s*)\|[^|]*\||\|[^|]*\|(?=\s*(?:\{|->))/,lookbehind:!0,greedy:!0,inside:{"closure-punctuation":{pattern:/^\||\|$/,alias:"punctuation"},rest:null}},"lifetime-annotation":{pattern:/'\w+/,alias:"symbol"},"fragment-specifier":{pattern:/(\$\w+:)[a-z]+/,lookbehind:!0,alias:"punctuation"},variable:/\$\w+/,"function-definition":{pattern:/(\bfn\s+)\w+/,lookbehind:!0,alias:"function"},"type-definition":{pattern:/(\b(?:enum|struct|trait|type|union)\s+)\w+/,lookbehind:!0,alias:"class-name"},"module-declaration":[{pattern:/(\b(?:crate|mod)\s+)[a-z][a-z_\d]*/,lookbehind:!0,alias:"namespace"},{pattern:/(\b(?:crate|self|super)\s*)::\s*[a-z][a-z_\d]*\b(?:\s*::(?:\s*[a-z][a-z_\d]*\s*::)*)?/,lookbehind:!0,alias:"namespace",inside:{punctuation:/::/}}],keyword:[/\b(?:Self|abstract|as|async|await|become|box|break|const|continue|crate|do|dyn|else|enum|extern|final|fn|for|if|impl|in|let|loop|macro|match|mod|move|mut|override|priv|pub|ref|return|self|static|struct|super|trait|try|type|typeof|union|unsafe|unsized|use|virtual|where|while|yield)\b/,/\b(?:bool|char|f(?:32|64)|[ui](?:8|16|32|64|128|size)|str)\b/],function:/\b[a-z_]\w*(?=\s*(?:::\s*<|\())/,macro:{pattern:/\b\w+!/,alias:"property"},constant:/\b[A-Z_][A-Z_\d]+\b/,"class-name":/\b[A-Z]\w*\b/,namespace:{pattern:/(?:\b[a-z][a-z_\d]*\s*::\s*)*\b[a-z][a-z_\d]*\s*::(?!\s*<)/,inside:{punctuation:/::/}},number:/\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(?:(?:\d(?:_?\d)*)?\.)?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)(?:_?(?:f32|f64|[iu](?:8|16|32|64|size)?))?\b/,boolean:/\b(?:false|true)\b/,punctuation:/->|\.\.=|\.{1,3}|::|[{}[\];(),:]/,operator:/[-+*\/%!^]=?|=[=>]?|&[&=]?|\|[|=]?|<<?=?|>>?=?|[@?]/},e.languages.rust["closure-params"].inside.rest=e.languages.rust,e.languages.rust.attribute.inside.string=e.languages.rust.string}(T),T.languages.go=T.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),T.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete T.languages.go["class-name"],function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source.replace(/<keyword>/g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(T),T.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},T.languages.python["string-interpolation"].inside.interpolation.inside.rest=T.languages.python,T.languages.py=T.languages.python;((e,t)=>{for(var n in t)f(e,n,{get:t[n],enumerable:!0})})({},{dracula:()=>j,duotoneDark:()=>N,duotoneLight:()=>L,github:()=>A,jettwaveDark:()=>H,jettwaveLight:()=>q,nightOwl:()=>P,nightOwlLight:()=>O,oceanicNext:()=>F,okaidia:()=>D,oneDark:()=>V,oneLight:()=>W,palenight:()=>M,shadesOfPurple:()=>z,synthwave84:()=>B,ultramin:()=>$,vsDark:()=>U,vsLight:()=>Z});var j={plain:{color:"#F8F8F2",backgroundColor:"#282A36"},styles:[{types:["prolog","constant","builtin"],style:{color:"rgb(189, 147, 249)"}},{types:["inserted","function"],style:{color:"rgb(80, 250, 123)"}},{types:["deleted"],style:{color:"rgb(255, 85, 85)"}},{types:["changed"],style:{color:"rgb(255, 184, 108)"}},{types:["punctuation","symbol"],style:{color:"rgb(248, 248, 242)"}},{types:["string","char","tag","selector"],style:{color:"rgb(255, 121, 198)"}},{types:["keyword","variable"],style:{color:"rgb(189, 147, 249)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(98, 114, 164)"}},{types:["attr-name"],style:{color:"rgb(241, 250, 140)"}}]},N={plain:{backgroundColor:"#2a2734",color:"#9a86fd"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#6c6783"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#e09142"}},{types:["property","function"],style:{color:"#9a86fd"}},{types:["tag-id","selector","atrule-id"],style:{color:"#eeebff"}},{types:["attr-name"],style:{color:"#c4b9fe"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","atrule","placeholder","variable"],style:{color:"#ffcc99"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#c4b9fe"}}]},L={plain:{backgroundColor:"#faf8f5",color:"#728fcb"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#b6ad9a"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#063289"}},{types:["property","function"],style:{color:"#b29762"}},{types:["tag-id","selector","atrule-id"],style:{color:"#2d2006"}},{types:["attr-name"],style:{color:"#896724"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","atrule"],style:{color:"#728fcb"}},{types:["placeholder","variable"],style:{color:"#93abdc"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#896724"}}]},A={plain:{color:"#393A34",backgroundColor:"#f6f8fa"},styles:[{types:["comment","prolog","doctype","cdata"],style:{color:"#999988",fontStyle:"italic"}},{types:["namespace"],style:{opacity:.7}},{types:["string","attr-value"],style:{color:"#e3116c"}},{types:["punctuation","operator"],style:{color:"#393A34"}},{types:["entity","url","symbol","number","boolean","variable","constant","property","regex","inserted"],style:{color:"#36acaa"}},{types:["atrule","keyword","attr-name","selector"],style:{color:"#00a4db"}},{types:["function","deleted","tag"],style:{color:"#d73a49"}},{types:["function-variable"],style:{color:"#6f42c1"}},{types:["tag","selector","keyword"],style:{color:"#00009f"}}]},P={plain:{color:"#d6deeb",backgroundColor:"#011627"},styles:[{types:["changed"],style:{color:"rgb(162, 191, 252)",fontStyle:"italic"}},{types:["deleted"],style:{color:"rgba(239, 83, 80, 0.56)",fontStyle:"italic"}},{types:["inserted","attr-name"],style:{color:"rgb(173, 219, 103)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(99, 119, 119)",fontStyle:"italic"}},{types:["string","url"],style:{color:"rgb(173, 219, 103)"}},{types:["variable"],style:{color:"rgb(214, 222, 235)"}},{types:["number"],style:{color:"rgb(247, 140, 108)"}},{types:["builtin","char","constant","function"],style:{color:"rgb(130, 170, 255)"}},{types:["punctuation"],style:{color:"rgb(199, 146, 234)"}},{types:["selector","doctype"],style:{color:"rgb(199, 146, 234)",fontStyle:"italic"}},{types:["class-name"],style:{color:"rgb(255, 203, 139)"}},{types:["tag","operator","keyword"],style:{color:"rgb(127, 219, 202)"}},{types:["boolean"],style:{color:"rgb(255, 88, 116)"}},{types:["property"],style:{color:"rgb(128, 203, 196)"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)"}}]},O={plain:{color:"#403f53",backgroundColor:"#FBFBFB"},styles:[{types:["changed"],style:{color:"rgb(162, 191, 252)",fontStyle:"italic"}},{types:["deleted"],style:{color:"rgba(239, 83, 80, 0.56)",fontStyle:"italic"}},{types:["inserted","attr-name"],style:{color:"rgb(72, 118, 214)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(152, 159, 177)",fontStyle:"italic"}},{types:["string","builtin","char","constant","url"],style:{color:"rgb(72, 118, 214)"}},{types:["variable"],style:{color:"rgb(201, 103, 101)"}},{types:["number"],style:{color:"rgb(170, 9, 130)"}},{types:["punctuation"],style:{color:"rgb(153, 76, 195)"}},{types:["function","selector","doctype"],style:{color:"rgb(153, 76, 195)",fontStyle:"italic"}},{types:["class-name"],style:{color:"rgb(17, 17, 17)"}},{types:["tag"],style:{color:"rgb(153, 76, 195)"}},{types:["operator","property","keyword","namespace"],style:{color:"rgb(12, 150, 155)"}},{types:["boolean"],style:{color:"rgb(188, 84, 84)"}}]},R="#c5a5c5",I="#8dc891",F={plain:{backgroundColor:"#282c34",color:"#ffffff"},styles:[{types:["attr-name"],style:{color:R}},{types:["attr-value"],style:{color:I}},{types:["comment","block-comment","prolog","doctype","cdata","shebang"],style:{color:"#999999"}},{types:["property","number","function-name","constant","symbol","deleted"],style:{color:"#5a9bcf"}},{types:["boolean"],style:{color:"#ff8b50"}},{types:["tag"],style:{color:"#fc929e"}},{types:["string"],style:{color:I}},{types:["punctuation"],style:{color:I}},{types:["selector","char","builtin","inserted"],style:{color:"#D8DEE9"}},{types:["function"],style:{color:"#79b6f2"}},{types:["operator","entity","url","variable"],style:{color:"#d7deea"}},{types:["keyword"],style:{color:R}},{types:["atrule","class-name"],style:{color:"#FAC863"}},{types:["important"],style:{fontWeight:"400"}},{types:["bold"],style:{fontWeight:"bold"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["namespace"],style:{opacity:.7}}]},D={plain:{color:"#f8f8f2",backgroundColor:"#272822"},styles:[{types:["changed"],style:{color:"rgb(162, 191, 252)",fontStyle:"italic"}},{types:["deleted"],style:{color:"#f92672",fontStyle:"italic"}},{types:["inserted"],style:{color:"rgb(173, 219, 103)",fontStyle:"italic"}},{types:["comment"],style:{color:"#8292a2",fontStyle:"italic"}},{types:["string","url"],style:{color:"#a6e22e"}},{types:["variable"],style:{color:"#f8f8f2"}},{types:["number"],style:{color:"#ae81ff"}},{types:["builtin","char","constant","function","class-name"],style:{color:"#e6db74"}},{types:["punctuation"],style:{color:"#f8f8f2"}},{types:["selector","doctype"],style:{color:"#a6e22e",fontStyle:"italic"}},{types:["tag","operator","keyword"],style:{color:"#66d9ef"}},{types:["boolean"],style:{color:"#ae81ff"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)",opacity:.7}},{types:["tag","property"],style:{color:"#f92672"}},{types:["attr-name"],style:{color:"#a6e22e !important"}},{types:["doctype"],style:{color:"#8292a2"}},{types:["rule"],style:{color:"#e6db74"}}]},M={plain:{color:"#bfc7d5",backgroundColor:"#292d3e"},styles:[{types:["comment"],style:{color:"rgb(105, 112, 152)",fontStyle:"italic"}},{types:["string","inserted"],style:{color:"rgb(195, 232, 141)"}},{types:["number"],style:{color:"rgb(247, 140, 108)"}},{types:["builtin","char","constant","function"],style:{color:"rgb(130, 170, 255)"}},{types:["punctuation","selector"],style:{color:"rgb(199, 146, 234)"}},{types:["variable"],style:{color:"rgb(191, 199, 213)"}},{types:["class-name","attr-name"],style:{color:"rgb(255, 203, 107)"}},{types:["tag","deleted"],style:{color:"rgb(255, 85, 114)"}},{types:["operator"],style:{color:"rgb(137, 221, 255)"}},{types:["boolean"],style:{color:"rgb(255, 88, 116)"}},{types:["keyword"],style:{fontStyle:"italic"}},{types:["doctype"],style:{color:"rgb(199, 146, 234)",fontStyle:"italic"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)"}},{types:["url"],style:{color:"rgb(221, 221, 221)"}}]},z={plain:{color:"#9EFEFF",backgroundColor:"#2D2A55"},styles:[{types:["changed"],style:{color:"rgb(255, 238, 128)"}},{types:["deleted"],style:{color:"rgba(239, 83, 80, 0.56)"}},{types:["inserted"],style:{color:"rgb(173, 219, 103)"}},{types:["comment"],style:{color:"rgb(179, 98, 255)",fontStyle:"italic"}},{types:["punctuation"],style:{color:"rgb(255, 255, 255)"}},{types:["constant"],style:{color:"rgb(255, 98, 140)"}},{types:["string","url"],style:{color:"rgb(165, 255, 144)"}},{types:["variable"],style:{color:"rgb(255, 238, 128)"}},{types:["number","boolean"],style:{color:"rgb(255, 98, 140)"}},{types:["attr-name"],style:{color:"rgb(255, 180, 84)"}},{types:["keyword","operator","property","namespace","tag","selector","doctype"],style:{color:"rgb(255, 157, 0)"}},{types:["builtin","char","constant","function","class-name"],style:{color:"rgb(250, 208, 0)"}}]},B={plain:{backgroundColor:"linear-gradient(to bottom, #2a2139 75%, #34294f)",backgroundImage:"#34294f",color:"#f92aad",textShadow:"0 0 2px #100c0f, 0 0 5px #dc078e33, 0 0 10px #fff3"},styles:[{types:["comment","block-comment","prolog","doctype","cdata"],style:{color:"#495495",fontStyle:"italic"}},{types:["punctuation"],style:{color:"#ccc"}},{types:["tag","attr-name","namespace","number","unit","hexcode","deleted"],style:{color:"#e2777a"}},{types:["property","selector"],style:{color:"#72f1b8",textShadow:"0 0 2px #100c0f, 0 0 10px #257c5575, 0 0 35px #21272475"}},{types:["function-name"],style:{color:"#6196cc"}},{types:["boolean","selector-id","function"],style:{color:"#fdfdfd",textShadow:"0 0 2px #001716, 0 0 3px #03edf975, 0 0 5px #03edf975, 0 0 8px #03edf975"}},{types:["class-name","maybe-class-name","builtin"],style:{color:"#fff5f6",textShadow:"0 0 2px #000, 0 0 10px #fc1f2c75, 0 0 5px #fc1f2c75, 0 0 25px #fc1f2c75"}},{types:["constant","symbol"],style:{color:"#f92aad",textShadow:"0 0 2px #100c0f, 0 0 5px #dc078e33, 0 0 10px #fff3"}},{types:["important","atrule","keyword","selector-class"],style:{color:"#f4eee4",textShadow:"0 0 2px #393a33, 0 0 8px #f39f0575, 0 0 2px #f39f0575"}},{types:["string","char","attr-value","regex","variable"],style:{color:"#f87c32"}},{types:["parameter"],style:{fontStyle:"italic"}},{types:["entity","url"],style:{color:"#67cdcc"}},{types:["operator"],style:{color:"ffffffee"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["entity"],style:{cursor:"help"}},{types:["inserted"],style:{color:"green"}}]},$={plain:{color:"#282a2e",backgroundColor:"#ffffff"},styles:[{types:["comment"],style:{color:"rgb(197, 200, 198)"}},{types:["string","number","builtin","variable"],style:{color:"rgb(150, 152, 150)"}},{types:["class-name","function","tag","attr-name"],style:{color:"rgb(40, 42, 46)"}}]},U={plain:{color:"#9CDCFE",backgroundColor:"#1E1E1E"},styles:[{types:["prolog"],style:{color:"rgb(0, 0, 128)"}},{types:["comment"],style:{color:"rgb(106, 153, 85)"}},{types:["builtin","changed","keyword","interpolation-punctuation"],style:{color:"rgb(86, 156, 214)"}},{types:["number","inserted"],style:{color:"rgb(181, 206, 168)"}},{types:["constant"],style:{color:"rgb(100, 102, 149)"}},{types:["attr-name","variable"],style:{color:"rgb(156, 220, 254)"}},{types:["deleted","string","attr-value","template-punctuation"],style:{color:"rgb(206, 145, 120)"}},{types:["selector"],style:{color:"rgb(215, 186, 125)"}},{types:["tag"],style:{color:"rgb(78, 201, 176)"}},{types:["tag"],languages:["markup"],style:{color:"rgb(86, 156, 214)"}},{types:["punctuation","operator"],style:{color:"rgb(212, 212, 212)"}},{types:["punctuation"],languages:["markup"],style:{color:"#808080"}},{types:["function"],style:{color:"rgb(220, 220, 170)"}},{types:["class-name"],style:{color:"rgb(78, 201, 176)"}},{types:["char"],style:{color:"rgb(209, 105, 105)"}}]},Z={plain:{color:"#000000",backgroundColor:"#ffffff"},styles:[{types:["comment"],style:{color:"rgb(0, 128, 0)"}},{types:["builtin"],style:{color:"rgb(0, 112, 193)"}},{types:["number","variable","inserted"],style:{color:"rgb(9, 134, 88)"}},{types:["operator"],style:{color:"rgb(0, 0, 0)"}},{types:["constant","char"],style:{color:"rgb(129, 31, 63)"}},{types:["tag"],style:{color:"rgb(128, 0, 0)"}},{types:["attr-name"],style:{color:"rgb(255, 0, 0)"}},{types:["deleted","string"],style:{color:"rgb(163, 21, 21)"}},{types:["changed","punctuation"],style:{color:"rgb(4, 81, 165)"}},{types:["function","keyword"],style:{color:"rgb(0, 0, 255)"}},{types:["class-name"],style:{color:"rgb(38, 127, 153)"}}]},H={plain:{color:"#f8fafc",backgroundColor:"#011627"},styles:[{types:["prolog"],style:{color:"#000080"}},{types:["comment"],style:{color:"#6A9955"}},{types:["builtin","changed","keyword","interpolation-punctuation"],style:{color:"#569CD6"}},{types:["number","inserted"],style:{color:"#B5CEA8"}},{types:["constant"],style:{color:"#f8fafc"}},{types:["attr-name","variable"],style:{color:"#9CDCFE"}},{types:["deleted","string","attr-value","template-punctuation"],style:{color:"#cbd5e1"}},{types:["selector"],style:{color:"#D7BA7D"}},{types:["tag"],style:{color:"#0ea5e9"}},{types:["tag"],languages:["markup"],style:{color:"#0ea5e9"}},{types:["punctuation","operator"],style:{color:"#D4D4D4"}},{types:["punctuation"],languages:["markup"],style:{color:"#808080"}},{types:["function"],style:{color:"#7dd3fc"}},{types:["class-name"],style:{color:"#0ea5e9"}},{types:["char"],style:{color:"#D16969"}}]},q={plain:{color:"#0f172a",backgroundColor:"#f1f5f9"},styles:[{types:["prolog"],style:{color:"#000080"}},{types:["comment"],style:{color:"#6A9955"}},{types:["builtin","changed","keyword","interpolation-punctuation"],style:{color:"#0c4a6e"}},{types:["number","inserted"],style:{color:"#B5CEA8"}},{types:["constant"],style:{color:"#0f172a"}},{types:["attr-name","variable"],style:{color:"#0c4a6e"}},{types:["deleted","string","attr-value","template-punctuation"],style:{color:"#64748b"}},{types:["selector"],style:{color:"#D7BA7D"}},{types:["tag"],style:{color:"#0ea5e9"}},{types:["tag"],languages:["markup"],style:{color:"#0ea5e9"}},{types:["punctuation","operator"],style:{color:"#475569"}},{types:["punctuation"],languages:["markup"],style:{color:"#808080"}},{types:["function"],style:{color:"#0e7490"}},{types:["class-name"],style:{color:"#0ea5e9"}},{types:["char"],style:{color:"#D16969"}}]},V={plain:{backgroundColor:"hsl(220, 13%, 18%)",color:"hsl(220, 14%, 71%)",textShadow:"0 1px rgba(0, 0, 0, 0.3)"},styles:[{types:["comment","prolog","cdata"],style:{color:"hsl(220, 10%, 40%)"}},{types:["doctype","punctuation","entity"],style:{color:"hsl(220, 14%, 71%)"}},{types:["attr-name","class-name","maybe-class-name","boolean","constant","number","atrule"],style:{color:"hsl(29, 54%, 61%)"}},{types:["keyword"],style:{color:"hsl(286, 60%, 67%)"}},{types:["property","tag","symbol","deleted","important"],style:{color:"hsl(355, 65%, 65%)"}},{types:["selector","string","char","builtin","inserted","regex","attr-value"],style:{color:"hsl(95, 38%, 62%)"}},{types:["variable","operator","function"],style:{color:"hsl(207, 82%, 66%)"}},{types:["url"],style:{color:"hsl(187, 47%, 55%)"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"hsl(220, 14%, 71%)"}}]},W={plain:{backgroundColor:"hsl(230, 1%, 98%)",color:"hsl(230, 8%, 24%)"},styles:[{types:["comment","prolog","cdata"],style:{color:"hsl(230, 4%, 64%)"}},{types:["doctype","punctuation","entity"],style:{color:"hsl(230, 8%, 24%)"}},{types:["attr-name","class-name","boolean","constant","number","atrule"],style:{color:"hsl(35, 99%, 36%)"}},{types:["keyword"],style:{color:"hsl(301, 63%, 40%)"}},{types:["property","tag","symbol","deleted","important"],style:{color:"hsl(5, 74%, 59%)"}},{types:["selector","string","char","builtin","inserted","regex","attr-value","punctuation"],style:{color:"hsl(119, 34%, 47%)"}},{types:["variable","operator","function"],style:{color:"hsl(221, 87%, 60%)"}},{types:["url"],style:{color:"hsl(198, 99%, 37%)"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"hsl(230, 8%, 24%)"}}]},G=(e,t)=>{const{plain:n}=e,r=e.styles.reduce(((e,n)=>{const{languages:r,style:a}=n;return r&&!r.includes(t)||n.types.forEach((t=>{const n=S(S({},e[t]),a);e[t]=n})),e}),{});return r.root=n,r.plain=_(S({},n),{backgroundColor:void 0}),r},Y=/\r\n|\r|\n/,Q=e=>{0===e.length?e.push({types:["plain"],content:"\n",empty:!0}):1===e.length&&""===e[0].content&&(e[0].content="\n",e[0].empty=!0)},K=(e,t)=>{const n=e.length;return n>0&&e[n-1]===t?e:e.concat(t)},X=e=>{const t=[[]],n=[e],r=[0],a=[e.length];let i=0,o=0,s=[];const l=[s];for(;o>-1;){for(;(i=r[o]++)<a[o];){let e,c=t[o];const u=n[o][i];if("string"==typeof u?(c=o>0?c:["plain"],e=u):(c=K(c,u.type),u.alias&&(c=K(c,u.alias)),e=u.content),"string"!=typeof e){o++,t.push(c),n.push(e),r.push(0),a.push(e.length);continue}const d=e.split(Y),p=d.length;s.push({types:c,content:d[0]});for(let t=1;t<p;t++)Q(s),l.push(s=[]),s.push({types:c,content:d[t]})}o--,t.pop(),n.pop(),r.pop(),a.pop()}return Q(s),l},J=({children:e,language:t,code:n,theme:r,prism:a})=>{const i=t.toLowerCase(),o=((e,t)=>{const[n,r]=(0,u.useState)(G(t,e)),a=(0,u.useRef)(),i=(0,u.useRef)();return(0,u.useEffect)((()=>{t===a.current&&e===i.current||(a.current=t,i.current=e,r(G(t,e)))}),[e,t]),n})(i,r),s=(e=>(0,u.useCallback)((t=>{var n=t,{className:r,style:a,line:i}=n,o=E(n,["className","style","line"]);const s=_(S({},o),{className:(0,d.Z)("token-line",r)});return"object"==typeof e&&"plain"in e&&(s.style=e.plain),"object"==typeof a&&(s.style=S(S({},s.style||{}),a)),s}),[e]))(o),l=(e=>{const t=(0,u.useCallback)((({types:t,empty:n})=>{if(null!=e)return 1===t.length&&"plain"===t[0]?null!=n?{display:"inline-block"}:void 0:1===t.length&&null!=n?e[t[0]]:Object.assign(null!=n?{display:"inline-block"}:{},...t.map((t=>e[t])))}),[e]);return(0,u.useCallback)((e=>{var n=e,{token:r,className:a,style:i}=n,o=E(n,["token","className","style"]);const s=_(S({},o),{className:(0,d.Z)("token",...r.types,a),children:r.content,style:t(r)});return null!=i&&(s.style=S(S({},s.style||{}),i)),s}),[t])})(o),c=(({prism:e,code:t,grammar:n,language:r})=>{const a=(0,u.useRef)(e);return(0,u.useMemo)((()=>{if(null==n)return X([t]);const e={code:t,grammar:n,language:r,tokens:[]};return a.current.hooks.run("before-tokenize",e),e.tokens=a.current.tokenize(t,n),a.current.hooks.run("after-tokenize",e),X(e.tokens)}),[t,n,r])})({prism:a,language:i,code:n,grammar:a.languages[i]});return e({tokens:c,className:`prism-code language-${i}`,style:null!=o?o.root:{},getLineProps:s,getTokenProps:l})},ee=e=>(0,u.createElement)(J,_(S({},e),{prism:e.prism||T,theme:e.theme||U,code:e.code,language:e.language}))},8776:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=!0,a="Invariant failed";function i(e,t){if(!e){if(r)throw new Error(a);var n="function"==typeof t?t():t,i=n?"".concat(a,": ").concat(n):a;throw new Error(i)}}},7529:e=>{"use strict";e.exports={}},6887:e=>{"use strict";e.exports=JSON.parse('{"/interchain-security/-a71":{"__comp":"5e95c892","__context":{"plugin":"ff0782b1"}},"/interchain-security/v4.2.0-03e":{"__comp":"a7bd4aaa","version":"ab367a53"},"/interchain-security/v4.2.0-c06":{"__comp":"a94703ab"},"/interchain-security/v4.2.0-c8a":{"__comp":"17896441","content":"99394557"},"/interchain-security/v4.2.0/adrs/adr-001-key-assignment-c79":{"__comp":"17896441","content":"98891868"},"/interchain-security/v4.2.0/adrs/adr-002-throttle-ec7":{"__comp":"17896441","content":"6df65b06"},"/interchain-security/v4.2.0/adrs/adr-003-equivocation-gov-proposal-a0f":{"__comp":"17896441","content":"7380b9fa"},"/interchain-security/v4.2.0/adrs/adr-004-denom-dos-fixes-ba0":{"__comp":"17896441","content":"829e00bf"},"/interchain-security/v4.2.0/adrs/adr-005-cryptographic-equivocation-verification-74f":{"__comp":"17896441","content":"e005c37e"},"/interchain-security/v4.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop-83c":{"__comp":"17896441","content":"7aa430a8"},"/interchain-security/v4.2.0/adrs/adr-008-throttle-retries-e78":{"__comp":"17896441","content":"2a9fa04d"},"/interchain-security/v4.2.0/adrs/adr-009-soft-opt-out-24f":{"__comp":"17896441","content":"e0ad375d"},"/interchain-security/v4.2.0/adrs/adr-010-standalone-changeover-854":{"__comp":"17896441","content":"b8e16dc5"},"/interchain-security/v4.2.0/adrs/adr-011-improving-test-confidence-5cf":{"__comp":"17896441","content":"b8d345cd"},"/interchain-security/v4.2.0/adrs/adr-012-separate-releasing-448":{"__comp":"17896441","content":"af3e09f2"},"/interchain-security/v4.2.0/adrs/adr-013-equivocation-slashing-0de":{"__comp":"17896441","content":"b2a29569"},"/interchain-security/v4.2.0/adrs/adr-014-epochs-1d2":{"__comp":"17896441","content":"6b8df643"},"/interchain-security/v4.2.0/adrs/adr-015-partial-set-security-0f9":{"__comp":"17896441","content":"b93225b7"},"/interchain-security/v4.2.0/adrs/adr-template-83a":{"__comp":"17896441","content":"fc26cd25"},"/interchain-security/v4.2.0/adrs/intro-cf8":{"__comp":"17896441","content":"ea42cb80"},"/interchain-security/v4.2.0/consumer-development/app-integration-3ff":{"__comp":"17896441","content":"a95292b9"},"/interchain-security/v4.2.0/consumer-development/changeover-procedure-05c":{"__comp":"17896441","content":"94b74966"},"/interchain-security/v4.2.0/consumer-development/consumer-chain-governance-04a":{"__comp":"17896441","content":"8d3b6fe8"},"/interchain-security/v4.2.0/consumer-development/consumer-genesis-transformation-70d":{"__comp":"17896441","content":"5fa9786a"},"/interchain-security/v4.2.0/consumer-development/offboarding-5bb":{"__comp":"17896441","content":"6382e28e"},"/interchain-security/v4.2.0/consumer-development/onboarding-9f8":{"__comp":"17896441","content":"e5b5a87b"},"/interchain-security/v4.2.0/faq-45b":{"__comp":"17896441","content":"867425db"},"/interchain-security/v4.2.0/features/key-assignment-42d":{"__comp":"17896441","content":"c551d695"},"/interchain-security/v4.2.0/features/partial-set-security-be3":{"__comp":"17896441","content":"ded5fac2"},"/interchain-security/v4.2.0/features/power-shaping-71f":{"__comp":"17896441","content":"3f869ff5"},"/interchain-security/v4.2.0/features/proposals-3b6":{"__comp":"17896441","content":"a088363e"},"/interchain-security/v4.2.0/features/reward-distribution-f4c":{"__comp":"17896441","content":"3ec9db48"},"/interchain-security/v4.2.0/features/slashing-ad1":{"__comp":"17896441","content":"e50733a4"},"/interchain-security/v4.2.0/introduction/overview-348":{"__comp":"17896441","content":"3f3637cb"},"/interchain-security/v4.2.0/introduction/params-432":{"__comp":"17896441","content":"852eba87"},"/interchain-security/v4.2.0/introduction/technical-specification-77c":{"__comp":"17896441","content":"b22483fb"},"/interchain-security/v4.2.0/introduction/terminology-de3":{"__comp":"17896441","content":"1ae81764"},"/interchain-security/v4.2.0/validators/changeover-procedure-e1e":{"__comp":"17896441","content":"536acd9c"},"/interchain-security/v4.2.0/validators/joining-neutron-402":{"__comp":"17896441","content":"2510f7b4"},"/interchain-security/v4.2.0/validators/joining-stride-63b":{"__comp":"17896441","content":"ae015673"},"/interchain-security/v4.2.0/validators/joining-testnet-476":{"__comp":"17896441","content":"405e8773"},"/interchain-security/v4.2.0/validators/overview-689":{"__comp":"17896441","content":"287de311"},"/interchain-security/v4.2.0/validators/partial-set-security-for-validators-1d8":{"__comp":"17896441","content":"75f9ba63"},"/interchain-security/v4.2.0/validators/withdraw_rewards-cbb":{"__comp":"17896441","content":"97662a95"},"/interchain-security/v5.0.0-49c":{"__comp":"a7bd4aaa","version":"06b45df8"},"/interchain-security/v5.0.0-8b2":{"__comp":"a94703ab"},"/interchain-security/v5.0.0-77d":{"__comp":"17896441","content":"21cfc626"},"/interchain-security/v5.0.0/adrs/adr-001-key-assignment-2b0":{"__comp":"17896441","content":"a6888f58"},"/interchain-security/v5.0.0/adrs/adr-002-throttle-f23":{"__comp":"17896441","content":"a8cc50aa"},"/interchain-security/v5.0.0/adrs/adr-003-equivocation-gov-proposal-32c":{"__comp":"17896441","content":"da448d6e"},"/interchain-security/v5.0.0/adrs/adr-004-denom-dos-fixes-329":{"__comp":"17896441","content":"caea946b"},"/interchain-security/v5.0.0/adrs/adr-005-cryptographic-equivocation-verification-284":{"__comp":"17896441","content":"4edefe03"},"/interchain-security/v5.0.0/adrs/adr-007-pause-unbonding-on-eqv-prop-652":{"__comp":"17896441","content":"d2e13769"},"/interchain-security/v5.0.0/adrs/adr-008-throttle-retries-212":{"__comp":"17896441","content":"491e9485"},"/interchain-security/v5.0.0/adrs/adr-009-soft-opt-out-d57":{"__comp":"17896441","content":"72e9af3b"},"/interchain-security/v5.0.0/adrs/adr-010-standalone-changeover-542":{"__comp":"17896441","content":"aa5e9d52"},"/interchain-security/v5.0.0/adrs/adr-011-improving-test-confidence-9a5":{"__comp":"17896441","content":"1097399d"},"/interchain-security/v5.0.0/adrs/adr-012-separate-releasing-be6":{"__comp":"17896441","content":"624b8b53"},"/interchain-security/v5.0.0/adrs/adr-013-equivocation-slashing-2b3":{"__comp":"17896441","content":"d0088cb9"},"/interchain-security/v5.0.0/adrs/adr-014-epochs-d93":{"__comp":"17896441","content":"ff9311cc"},"/interchain-security/v5.0.0/adrs/adr-015-partial-set-security-641":{"__comp":"17896441","content":"c1444bce"},"/interchain-security/v5.0.0/adrs/adr-template-f5d":{"__comp":"17896441","content":"21dfdb60"},"/interchain-security/v5.0.0/adrs/intro-374":{"__comp":"17896441","content":"2ed06975"},"/interchain-security/v5.0.0/consumer-development/app-integration-117":{"__comp":"17896441","content":"ed5b9256"},"/interchain-security/v5.0.0/consumer-development/changeover-procedure-afb":{"__comp":"17896441","content":"26981f24"},"/interchain-security/v5.0.0/consumer-development/consumer-chain-governance-4f4":{"__comp":"17896441","content":"c3827980"},"/interchain-security/v5.0.0/consumer-development/consumer-genesis-transformation-a7a":{"__comp":"17896441","content":"1ca82e41"},"/interchain-security/v5.0.0/consumer-development/offboarding-f26":{"__comp":"17896441","content":"9b334c7f"},"/interchain-security/v5.0.0/consumer-development/onboarding-834":{"__comp":"17896441","content":"8a86a05c"},"/interchain-security/v5.0.0/faq-8d9":{"__comp":"17896441","content":"61e9b0fd"},"/interchain-security/v5.0.0/features/key-assignment-cf8":{"__comp":"17896441","content":"d0d80f5c"},"/interchain-security/v5.0.0/features/proposals-873":{"__comp":"17896441","content":"bdf2101f"},"/interchain-security/v5.0.0/features/reward-distribution-66f":{"__comp":"17896441","content":"9c202c81"},"/interchain-security/v5.0.0/features/slashing-ed3":{"__comp":"17896441","content":"434502c4"},"/interchain-security/v5.0.0/introduction/overview-caf":{"__comp":"17896441","content":"5cee3276"},"/interchain-security/v5.0.0/introduction/params-ace":{"__comp":"17896441","content":"f0745980"},"/interchain-security/v5.0.0/introduction/technical-specification-0bb":{"__comp":"17896441","content":"2c92eef1"},"/interchain-security/v5.0.0/introduction/terminology-b9d":{"__comp":"17896441","content":"16d4e57d"},"/interchain-security/v5.0.0/upgrading/migrate_v4_v5-197":{"__comp":"17896441","content":"53123775"},"/interchain-security/v5.0.0/validators/changeover-procedure-3fc":{"__comp":"17896441","content":"9fa21ee5"},"/interchain-security/v5.0.0/validators/joining-neutron-668":{"__comp":"17896441","content":"6cc1db80"},"/interchain-security/v5.0.0/validators/joining-stride-6dd":{"__comp":"17896441","content":"83f6d28d"},"/interchain-security/v5.0.0/validators/joining-testnet-e66":{"__comp":"17896441","content":"99c91eb8"},"/interchain-security/v5.0.0/validators/overview-943":{"__comp":"17896441","content":"5cdffc34"},"/interchain-security/v5.0.0/validators/withdraw_rewards-f93":{"__comp":"17896441","content":"f8a7cbf6"},"/interchain-security/-e1b":{"__comp":"a7bd4aaa","version":"935f2afb"},"/interchain-security/-255":{"__comp":"a94703ab"},"/interchain-security/adrs/adr-001-key-assignment-b01":{"__comp":"17896441","content":"54e4400b"},"/interchain-security/adrs/adr-002-throttle-049":{"__comp":"17896441","content":"bbea31d2"},"/interchain-security/adrs/adr-003-equivocation-gov-proposal-d6f":{"__comp":"17896441","content":"46057b98"},"/interchain-security/adrs/adr-004-denom-dos-fixes-9f0":{"__comp":"17896441","content":"ac4ec955"},"/interchain-security/adrs/adr-005-cryptographic-equivocation-verification-97a":{"__comp":"17896441","content":"4c7d82ee"},"/interchain-security/adrs/adr-007-pause-unbonding-on-eqv-prop-309":{"__comp":"17896441","content":"ded36896"},"/interchain-security/adrs/adr-008-throttle-retries-cde":{"__comp":"17896441","content":"775e2592"},"/interchain-security/adrs/adr-009-soft-opt-out-126":{"__comp":"17896441","content":"903c2771"},"/interchain-security/adrs/adr-010-standalone-changeover-8ee":{"__comp":"17896441","content":"d0d0ba0d"},"/interchain-security/adrs/adr-011-improving-test-confidence-6de":{"__comp":"17896441","content":"68191a78"},"/interchain-security/adrs/adr-012-separate-releasing-711":{"__comp":"17896441","content":"d21f9ede"},"/interchain-security/adrs/adr-013-equivocation-slashing-f62":{"__comp":"17896441","content":"6f71328c"},"/interchain-security/adrs/adr-014-epochs-4bf":{"__comp":"17896441","content":"a09d3327"},"/interchain-security/adrs/adr-015-partial-set-security-638":{"__comp":"17896441","content":"6b52739c"},"/interchain-security/adrs/adr-016-securityaggregation-5e9":{"__comp":"17896441","content":"e69e9c61"},"/interchain-security/adrs/adr-017-allowing-inactive-validators-0eb":{"__comp":"17896441","content":"e2ddbbfd"},"/interchain-security/adrs/intro-130":{"__comp":"17896441","content":"a2707102"},"/interchain-security/consumer-development/app-integration-634":{"__comp":"17896441","content":"d784d738"},"/interchain-security/consumer-development/changeover-procedure-39d":{"__comp":"17896441","content":"70938a03"},"/interchain-security/consumer-development/consumer-chain-governance-f51":{"__comp":"17896441","content":"f5589540"},"/interchain-security/consumer-development/consumer-genesis-transformation-491":{"__comp":"17896441","content":"425bba28"},"/interchain-security/consumer-development/offboarding-b9a":{"__comp":"17896441","content":"dc9efaba"},"/interchain-security/consumer-development/onboarding-81f":{"__comp":"17896441","content":"95875ea0"},"/interchain-security/faq-e46":{"__comp":"17896441","content":"00147ff4"},"/interchain-security/features/democracy-modules-0d1":{"__comp":"17896441","content":"69416719"},"/interchain-security/features/key-assignment-6a8":{"__comp":"17896441","content":"07d76e7d"},"/interchain-security/features/partial-set-security-15b":{"__comp":"17896441","content":"bfc97f30"},"/interchain-security/features/power-shaping-157":{"__comp":"17896441","content":"9be59c75"},"/interchain-security/features/proposals-85e":{"__comp":"17896441","content":"d1daeca6"},"/interchain-security/features/reward-distribution-133":{"__comp":"17896441","content":"578fb1aa"},"/interchain-security/features/slashing-e4f":{"__comp":"17896441","content":"4106f1c5"},"/interchain-security/introduction/overview-287":{"__comp":"17896441","content":"7616f23a"},"/interchain-security/introduction/params-aae":{"__comp":"17896441","content":"3672b5b7"},"/interchain-security/introduction/technical-specification-e7d":{"__comp":"17896441","content":"cf411473"},"/interchain-security/introduction/terminology-11e":{"__comp":"17896441","content":"bc8b8418"},"/interchain-security/upgrading/migrate_v4_v5-578":{"__comp":"17896441","content":"4179ee03"},"/interchain-security/validators/changeover-procedure-e7d":{"__comp":"17896441","content":"c2cfb320"},"/interchain-security/validators/joining-neutron-3d1":{"__comp":"17896441","content":"0cb1d302"},"/interchain-security/validators/joining-stride-b1f":{"__comp":"17896441","content":"ae63551b"},"/interchain-security/validators/joining-testnet-82d":{"__comp":"17896441","content":"4f50acdf"},"/interchain-security/validators/overview-ccb":{"__comp":"17896441","content":"f6addb2b"},"/interchain-security/validators/partial-set-security-for-validators-a1e":{"__comp":"17896441","content":"700b5f22"},"/interchain-security/validators/withdraw_rewards-2b7":{"__comp":"17896441","content":"758625d4"},"/interchain-security/-725":{"__comp":"17896441","content":"4edc808e"}}')}},e=>{e.O(0,[532],(()=>{return t=7221,e(e.s=t);var t}));e.O()}]); \ No newline at end of file diff --git a/assets/js/main.11e71de7.js.LICENSE.txt b/assets/js/main.11e71de7.js.LICENSE.txt new file mode 100644 index 0000000000..91dc894998 --- /dev/null +++ b/assets/js/main.11e71de7.js.LICENSE.txt @@ -0,0 +1,64 @@ +/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress + * @license MIT */ + +/*! Bundled license information: + +prismjs/prism.js: + (** + * Prism: Lightweight, robust, elegant syntax highlighting + * + * @license MIT <https://opensource.org/licenses/MIT> + * @author Lea Verou <https://lea.verou.me> + * @namespace + * @public + *) +*/ + +/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * @license React + * react-jsx-runtime.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * @license React + * scheduler.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** @license React v16.13.1 + * react-is.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ diff --git a/assets/js/runtime~main.c3149791.js b/assets/js/runtime~main.c3149791.js new file mode 100644 index 0000000000..ac89a3eb84 --- /dev/null +++ b/assets/js/runtime~main.c3149791.js @@ -0,0 +1 @@ +(()=>{"use strict";var e,a,d,b,c,f={},t={};function r(e){var a=t[e];if(void 0!==a)return a.exports;var d=t[e]={exports:{}};return f[e].call(d.exports,d,d.exports,r),d.exports}r.m=f,e=[],r.O=(a,d,b,c)=>{if(!d){var f=1/0;for(i=0;i<e.length;i++){d=e[i][0],b=e[i][1],c=e[i][2];for(var t=!0,o=0;o<d.length;o++)(!1&c||f>=c)&&Object.keys(r.O).every((e=>r.O[e](d[o])))?d.splice(o--,1):(t=!1,c<f&&(f=c));if(t){e.splice(i--,1);var n=b();void 0!==n&&(a=n)}}return a}c=c||0;for(var i=e.length;i>0&&e[i-1][2]>c;i--)e[i]=e[i-1];e[i]=[d,b,c]},r.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return r.d(a,{a:a}),a},d=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,b){if(1&b&&(e=this(e)),8&b)return e;if("object"==typeof e&&e){if(4&b&&e.__esModule)return e;if(16&b&&"function"==typeof e.then)return e}var c=Object.create(null);r.r(c);var f={};a=a||[null,d({}),d([]),d(d)];for(var t=2&b&&e;"object"==typeof t&&!~a.indexOf(t);t=d(t))Object.getOwnPropertyNames(t).forEach((a=>f[a]=()=>e[a]));return f.default=()=>e,r.d(c,f),c},r.d=(e,a)=>{for(var d in a)r.o(a,d)&&!r.o(e,d)&&Object.defineProperty(e,d,{enumerable:!0,get:a[d]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((a,d)=>(r.f[d](e,a),a)),[])),r.u=e=>"assets/js/"+({35:"f6addb2b",52:"21cfc626",53:"935f2afb",109:"bbea31d2",320:"3672b5b7",321:"758625d4",411:"434502c4",457:"a2707102",709:"d0088cb9",787:"a8cc50aa",842:"4106f1c5",903:"72e9af3b",918:"4edefe03",1038:"2ed06975",1085:"0cb1d302",1118:"425bba28",1163:"8d3b6fe8",1324:"dc9efaba",1429:"c2cfb320",1483:"26981f24",1660:"6382e28e",1840:"e0ad375d",1877:"7380b9fa",1937:"e50733a4",1996:"5cee3276",2108:"ae015673",2110:"00147ff4",2189:"07d76e7d",2234:"53123775",2247:"7616f23a",2262:"1ae81764",2323:"578fb1aa",2341:"5fa9786a",2344:"54e4400b",2383:"ded5fac2",2473:"852eba87",2527:"f8a7cbf6",2558:"2510f7b4",2883:"e005c37e",3153:"cf411473",3158:"2c92eef1",3159:"46057b98",3297:"ac4ec955",3500:"9fa21ee5",3596:"3f3637cb",3670:"2a9fa04d",3713:"caea946b",3784:"ab367a53",3813:"95875ea0",3845:"d1daeca6",3859:"97662a95",4117:"ea42cb80",4173:"4edc808e",4244:"aa5e9d52",4279:"536acd9c",4335:"6b8df643",4341:"b8d345cd",4366:"6df65b06",4368:"a94703ab",4438:"68191a78",4440:"af3e09f2",4470:"3f869ff5",4533:"b22483fb",4635:"c551d695",4704:"bc8b8418",4744:"da448d6e",4895:"5cdffc34",4932:"d21f9ede",4964:"98891868",5032:"c3827980",5051:"ff9311cc",5056:"ae63551b",5112:"99c91eb8",5118:"9b334c7f",5180:"405e8773",5296:"75f9ba63",5313:"e5b5a87b",5387:"16d4e57d",5402:"61e9b0fd",5457:"70938a03",5474:"a95292b9",5612:"700b5f22",5776:"c1444bce",5932:"21dfdb60",5938:"8a86a05c",6054:"903c2771",6073:"4179ee03",6420:"9be59c75",6499:"f5589540",6530:"a088363e",6548:"1097399d",6625:"9c202c81",6673:"94b74966",6705:"b8e16dc5",6784:"491e9485",6873:"69416719",6882:"e69e9c61",7143:"f0745980",7144:"b93225b7",7184:"287de311",7333:"d784d738",7375:"775e2592",7429:"ded36896",7487:"a6888f58",7506:"7aa430a8",7534:"83f6d28d",7540:"ff0782b1",7617:"1ca82e41",7649:"4c7d82ee",7918:"17896441",7943:"bdf2101f",8081:"ed5b9256",8233:"3ec9db48",8270:"a09d3327",8382:"d2e13769",8477:"867425db",8518:"a7bd4aaa",8560:"6f71328c",8714:"6cc1db80",8718:"829e00bf",8772:"d0d0ba0d",8864:"b2a29569",8892:"e2ddbbfd",9198:"fc26cd25",9253:"bfc97f30",9419:"6b52739c",9599:"06b45df8",9661:"5e95c892",9709:"624b8b53",9815:"4f50acdf",9897:"99394557",9982:"d0d80f5c"}[e]||e)+"."+{35:"aca89816",52:"8729733a",53:"78bd90f6",109:"43863e88",320:"7d4ba869",321:"17c5d74a",411:"8d5a5d14",457:"27890462",709:"e41155f8",787:"4e815e71",842:"c90c0bfb",903:"840537aa",918:"b3451047",1038:"0d9c3801",1085:"fabe1b41",1118:"90680342",1163:"e2b00793",1324:"5a3ab637",1429:"3bf8a73b",1483:"3de9a95d",1660:"7f81451b",1772:"531d94c5",1840:"01b8369f",1877:"932b3293",1937:"f44db361",1996:"e8f98637",2108:"fbf9e71e",2110:"0b3ca866",2189:"195c3194",2234:"fe1cc72c",2247:"837a872f",2262:"482af898",2323:"9d55eaef",2341:"fa4ac172",2344:"e2f60025",2383:"f0ee3953",2473:"e3d2f27b",2527:"7e411975",2558:"823faae0",2883:"7aec7bcf",3153:"69556536",3158:"232084f8",3159:"17b22c1f",3297:"d4051eb8",3500:"9bb946f7",3596:"463b9af5",3670:"fa9a65c7",3713:"e5a1de44",3784:"c91aaa68",3813:"a97a223d",3845:"bfecf8bd",3859:"fa11ce6a",4117:"f06fff1b",4173:"176093f8",4244:"e1985f6a",4279:"29001796",4335:"b0ee3105",4341:"3f23582b",4366:"eb6ae8e7",4368:"3856b628",4438:"4b39d7fe",4440:"5eacecf7",4470:"5e0f39e2",4533:"fc7b3cc6",4635:"fa70b161",4704:"63027b8e",4744:"641c7bd2",4895:"eacf780d",4932:"fc07846e",4964:"9f022861",5032:"f880929a",5051:"0e55d588",5056:"40097d02",5112:"ebba5ec5",5118:"4eb2d589",5180:"a6ffe47d",5296:"bf714c2a",5313:"c1818ef8",5387:"c5b611b1",5402:"babea3e2",5457:"0a87b3b7",5474:"5acfbcd2",5612:"48455c22",5776:"54c826a6",5932:"4f19dea1",5938:"a622c0e8",6054:"18b9a08b",6073:"b3fced4f",6420:"cfc66a57",6499:"4abf59ac",6530:"e8d00cce",6548:"6cf69a51",6625:"4de6f0b5",6673:"577b76d7",6705:"a2560616",6784:"2134357d",6873:"7aa395e3",6882:"942ce78c",7143:"e1109473",7144:"6c538bb2",7184:"83f8008b",7333:"71e628a7",7375:"0e85c471",7429:"f0182e76",7487:"4bb14d96",7506:"3f0c815c",7534:"5a6df8c0",7540:"cbedc7fd",7617:"07ae1c1e",7649:"1a561975",7918:"407f320a",7943:"feae5bf3",8081:"caab0441",8233:"3a34695e",8270:"4f88cf6f",8382:"80866211",8477:"d47ee539",8518:"687d6c08",8560:"dbe2f06e",8714:"b94c8d42",8718:"265639bf",8772:"87d75440",8864:"d74a382c",8892:"d395360c",9198:"e6be4cde",9253:"ec5561cc",9419:"dc8af5b8",9599:"830faa04",9661:"e9a018bf",9709:"ef004408",9815:"f5850848",9897:"c883f412",9982:"af276b99"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),b={},c="website:",r.l=(e,a,d,f)=>{if(b[e])b[e].push(a);else{var t,o;if(void 0!==d)for(var n=document.getElementsByTagName("script"),i=0;i<n.length;i++){var u=n[i];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==c+d){t=u;break}}t||(o=!0,(t=document.createElement("script")).charset="utf-8",t.timeout=120,r.nc&&t.setAttribute("nonce",r.nc),t.setAttribute("data-webpack",c+d),t.src=e),b[e]=[a];var l=(a,d)=>{t.onerror=t.onload=null,clearTimeout(s);var c=b[e];if(delete b[e],t.parentNode&&t.parentNode.removeChild(t),c&&c.forEach((e=>e(d))),a)return a(d)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:t}),12e4);t.onerror=l.bind(null,t.onerror),t.onload=l.bind(null,t.onload),o&&document.head.appendChild(t)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/interchain-security/",r.gca=function(e){return e={17896441:"7918",53123775:"2234",69416719:"6873",98891868:"4964",99394557:"9897",f6addb2b:"35","21cfc626":"52","935f2afb":"53",bbea31d2:"109","3672b5b7":"320","758625d4":"321","434502c4":"411",a2707102:"457",d0088cb9:"709",a8cc50aa:"787","4106f1c5":"842","72e9af3b":"903","4edefe03":"918","2ed06975":"1038","0cb1d302":"1085","425bba28":"1118","8d3b6fe8":"1163",dc9efaba:"1324",c2cfb320:"1429","26981f24":"1483","6382e28e":"1660",e0ad375d:"1840","7380b9fa":"1877",e50733a4:"1937","5cee3276":"1996",ae015673:"2108","00147ff4":"2110","07d76e7d":"2189","7616f23a":"2247","1ae81764":"2262","578fb1aa":"2323","5fa9786a":"2341","54e4400b":"2344",ded5fac2:"2383","852eba87":"2473",f8a7cbf6:"2527","2510f7b4":"2558",e005c37e:"2883",cf411473:"3153","2c92eef1":"3158","46057b98":"3159",ac4ec955:"3297","9fa21ee5":"3500","3f3637cb":"3596","2a9fa04d":"3670",caea946b:"3713",ab367a53:"3784","95875ea0":"3813",d1daeca6:"3845","97662a95":"3859",ea42cb80:"4117","4edc808e":"4173",aa5e9d52:"4244","536acd9c":"4279","6b8df643":"4335",b8d345cd:"4341","6df65b06":"4366",a94703ab:"4368","68191a78":"4438",af3e09f2:"4440","3f869ff5":"4470",b22483fb:"4533",c551d695:"4635",bc8b8418:"4704",da448d6e:"4744","5cdffc34":"4895",d21f9ede:"4932",c3827980:"5032",ff9311cc:"5051",ae63551b:"5056","99c91eb8":"5112","9b334c7f":"5118","405e8773":"5180","75f9ba63":"5296",e5b5a87b:"5313","16d4e57d":"5387","61e9b0fd":"5402","70938a03":"5457",a95292b9:"5474","700b5f22":"5612",c1444bce:"5776","21dfdb60":"5932","8a86a05c":"5938","903c2771":"6054","4179ee03":"6073","9be59c75":"6420",f5589540:"6499",a088363e:"6530","1097399d":"6548","9c202c81":"6625","94b74966":"6673",b8e16dc5:"6705","491e9485":"6784",e69e9c61:"6882",f0745980:"7143",b93225b7:"7144","287de311":"7184",d784d738:"7333","775e2592":"7375",ded36896:"7429",a6888f58:"7487","7aa430a8":"7506","83f6d28d":"7534",ff0782b1:"7540","1ca82e41":"7617","4c7d82ee":"7649",bdf2101f:"7943",ed5b9256:"8081","3ec9db48":"8233",a09d3327:"8270",d2e13769:"8382","867425db":"8477",a7bd4aaa:"8518","6f71328c":"8560","6cc1db80":"8714","829e00bf":"8718",d0d0ba0d:"8772",b2a29569:"8864",e2ddbbfd:"8892",fc26cd25:"9198",bfc97f30:"9253","6b52739c":"9419","06b45df8":"9599","5e95c892":"9661","624b8b53":"9709","4f50acdf":"9815",d0d80f5c:"9982"}[e]||e,r.p+r.u(e)},(()=>{var e={1303:0,532:0};r.f.j=(a,d)=>{var b=r.o(e,a)?e[a]:void 0;if(0!==b)if(b)d.push(b[2]);else if(/^(1303|532)$/.test(a))e[a]=0;else{var c=new Promise(((d,c)=>b=e[a]=[d,c]));d.push(b[2]=c);var f=r.p+r.u(a),t=new Error;r.l(f,(d=>{if(r.o(e,a)&&(0!==(b=e[a])&&(e[a]=void 0),b)){var c=d&&("load"===d.type?"missing":d.type),f=d&&d.target&&d.target.src;t.message="Loading chunk "+a+" failed.\n("+c+": "+f+")",t.name="ChunkLoadError",t.type=c,t.request=f,b[1](t)}}),"chunk-"+a,a)}},r.O.j=a=>0===e[a];var a=(a,d)=>{var b,c,f=d[0],t=d[1],o=d[2],n=0;if(f.some((a=>0!==e[a]))){for(b in t)r.o(t,b)&&(r.m[b]=t[b]);if(o)var i=o(r)}for(a&&a(d);n<f.length;n++)c=f[n],r.o(e,c)&&e[c]&&e[c][0](),e[c]=0;return r.O(i)},d=self.webpackChunkwebsite=self.webpackChunkwebsite||[];d.forEach(a.bind(null,0)),d.push=a.bind(null,d.push.bind(d))})()})(); \ No newline at end of file diff --git a/consumer-development/app-integration.html b/consumer-development/app-integration.html new file mode 100644 index 0000000000..7d3efb19db --- /dev/null +++ b/consumer-development/app-integration.html @@ -0,0 +1,33 @@ +<!doctype html> +<html lang="en" dir="ltr" class="docs-wrapper plugin-docs plugin-id-default docs-version-current docs-doc-page docs-doc-id-consumer-development/app-integration" data-has-hydrated="false"> +<head> +<meta charset="UTF-8"> +<meta name="generator" content="Docusaurus v3.0.1"> +<title data-rh="true">Developing an ICS consumer chain | Interchain Security + + + + +
Version: main

Developing an ICS consumer chain

+

When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol. +To help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications.

+

Basic consumer chain

+

The source code for the example app can be found here.

+

Please note that consumer chains do not implement the staking module - part of the validator set of the provider is replicated over to the consumer, +meaning that the consumer uses a subset of provider validator set and the stake of the validators on the provider determines their stake on the consumer. +Note that after the introduction of Partial Set Security, not all the provider validators have to validate a consumer chain (e.g., if top_N != 100).

+

Your chain should import the consumer module from x/consumer and register it in the correct places in your app.go. +The x/consumer module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in. +You should not need to manage or override any code from the x/consumer module.

+

Democracy consumer chain

+

The source code for the example app can be found here.

+

This type of consumer chain wraps the basic CosmosSDK x/distribution, x/staking and x/governance modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system.

+

This allows the consumer chain to leverage those modules while also using the x/consumer module.

+

With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.

+

Standalone chain to consumer chain changeover

+

See the standalone chain to consumer chain changeover guide for more information on how to transition your standalone chain to a consumer chain.

+ + \ No newline at end of file diff --git a/consumer-development/app-integration.html.html b/consumer-development/app-integration.html.html new file mode 100644 index 0000000000..a61c3cf109 --- /dev/null +++ b/consumer-development/app-integration.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/consumer-development/changeover-procedure.html b/consumer-development/changeover-procedure.html new file mode 100644 index 0000000000..acaa856035 --- /dev/null +++ b/consumer-development/changeover-procedure.html @@ -0,0 +1,139 @@ + + + + + +Changeover Procedure | Interchain Security + + + + +
Version: main

Changeover Procedure

+

Chains that were not initially launched as consumers of Interchain Security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.

+

The relevant protocol specifications are available below:

+ +

Overview

+

Standalone to consumer changeover procedure can roughly be separated into 4 parts:

+

1. ConsumerAddition proposal submitted to the provider chain

+

The proposal is equivalent to the "normal" ConsumerAddition proposal submitted by new consumer chains.

+

However, here are the most important notes and differences between a new consumer chain and a standalone chain performing a changeover:

+
    +
  • chain_id must be equal to the standalone chain id
  • +
  • initial_height field has additional rules to abide by:
  • +
+
caution
{
...
"initial_height" : {
// must correspond to current revision number of standalone chain
// e.g. stride-1 => "revision_number": 1
"revision_number": 1,

// must correspond to a height that is at least 1 block after the upgrade
// that will add the `consumer` module to the standalone chain
// e.g. "upgrade_height": 100 => "revision_height": 101
"revision_height": 1,
},
...
}

RevisionNumber: 0, RevisionHeight: 111

+
    +
  • +

    genesis_hash can be safely ignored because the chain is already running. A hash of the standalone chain's initial genesis may be used

    +
  • +
  • +

    binary_hash may not be available ahead of time. All chains performing the changeover go through rigorous testing - if bugs are caught and fixed the hash listed in the proposal may not be the most recent one.

    +
  • +
  • +

    spawn_time listed in the proposal MUST be before the upgrade_height listed in the upgrade proposal on the standalone chain.

    +
  • +
+
caution

spawn_time must occur before the upgrade_height on the standalone chain is reached because the provider chain must generate the ConsumerGenesis that contains the validator set that will be used after the changeover.

+
    +
  • +

    unbonding_period must correspond to the value used on the standalone chain. Otherwise, the clients used for the ccv protocol may be incorrectly initialized.

    +
  • +
  • +

    distribution_transmission_channel should be set.

    +
  • +
+
note

Populating distribution_transmission_channel will enable the standalone chain to reuse one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ibc denom that may already be in use.

If the parameter is not set, a new channel will be created.

+
    +
  • +

    ccv_timeout_period has no important notes

    +
  • +
  • +

    transfer_timeout_period has no important notes

    +
  • +
  • +

    consumer_redistribution_fraction has no important notes

    +
  • +
  • +

    blocks_per_distribution_transmission has no important notes

    +
  • +
  • +

    historical_entries has no important notes

    +
  • +
+

2. upgrade proposal on standalone chain

+

The standalone chain creates an upgrade proposal to include the interchain-security/x/ccv/consumer module.

+
caution

The upgrade height in the proposal should correspond to a height that is after the spawn_time in the consumer addition proposal submitted to the provider chain.

+

Otherwise, the upgrade is indistinguishable from a regular on-chain upgrade proposal.

+

3. spawn time is reached

+

When the spawn_time is reached on the provider it will generate a ConsumerGenesis that contains the validator set that will supersede the standalone validator set.

+

This ConsumerGenesis must be available on the standalone chain during the on-chain upgrade.

+

4. standalone chain upgrade

+

Performing the on-chain upgrade on the standalone chain will add the ccv/consumer module and allow the chain to become a consumer of Interchain Security.

+
caution

The ConsumerGenesis must be exported to a file and placed in the correct folder on the standalone chain before the upgrade.

The file must be placed at the exact specified location, otherwise the upgrade will not be executed correctly.

Usually the file is placed in $NODE_HOME/config, but the file name and the exact directory is dictated by the upgrade code on the standalone chain.

    +
  • please check exact instructions provided by the standalone chain team
  • +
+

After the genesis.json file has been made available, the process is equivalent to a normal on-chain upgrade. The standalone validator set will sign the next couple of blocks before transferring control to provider validator set.

+

The standalone validator set can still be slashed for any infractions if evidence is submitted within the unboding_period.

+

Notes

+

The changeover procedure may be updated in the future to create a seamless way of providing the validator set information to the standalone chain.

+

Onboarding Checklist

+

This onboarding checklist is slightly different from the one under Onboarding

+

Additionally, you can check the testnet repo for a comprehensive guide on preparing and launching consumer chains.

+

1. Complete testing & integration

+
    +
  • test integration with gaia
  • +
  • test your protocol with supported relayer versions (minimum hermes 1.4.1)
  • +
  • test the changeover procedure
  • +
  • reach out to the ICS team if you are facing issues
  • +
+

2. Create an Onboarding Repository

+

To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain.

+

This should include (at minimum):

+
    +
  • genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see Transform Consumer Genesis)
  • +
  • information about relevant seed/peer nodes you are running
  • +
  • relayer information (compatible versions)
  • +
  • copy of your governance proposal (as JSON)
  • +
  • a script showing how to start your chain and connect to peers (optional)
  • +
  • take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable
  • +
+

Example of such a repository can be found here.

+

3. Submit a ConsumerChainAddition Governance Proposal to the provider

+

Before you submit a ConsumerChainAddition proposal, please provide a spawn_time that is before the upgrade_height of the upgrade that will introduce the ccv module to your chain.

+
danger

If the spawn_time happens after your upgrade_height the provider will not be able to communicate the new validator set to be used after the changeover.

+

Additionally, reach out to the community via the forum to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers.

+
    +
  • determine your chain's spawn time
  • +
  • determine consumer chain parameters to be put in the proposal
  • +
  • take note to include a link to your onboarding repository
  • +
+

Example of a consumer chain addition proposal (compare with the ConsumerAdditionProposal in the ICS Provider Proposals section for chains that launch as consumers):

+
// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain or add a standalone chain.
// If it passes, then a subset (i.e., depends on `top_N` and on the power shaping parameters) of validators on the provider chain are expected
// to validate the consumer chain at spawn time. It is recommended that spawn time occurs after the proposal end time and that it is
// scheduled to happen before the standalone chain upgrade that sill introduce the ccv module.
{
// Title of the proposal
"title": "Changeover Standalone chain",
// Description of the proposal
// format the text as a .md file and include the file in your onboarding repository
"description": ".md description of your chain and all other relevant information",
// Proposed chain-id of the new consumer chain.
// Must be unique from all other consumer chain ids of the executing provider chain.
"chain_id": "standalone-1",
// Initial height of new consumer chain.
"initial_height" : {
// must correspond to current revision number of standalone chain
// e.g. standalone-1 => "revision_number": 1
"revision_number": 1,

// must correspond to a height that is at least 1 block after the upgrade
// that will add the `consumer` module to the standalone chain
// e.g. "upgrade_height": 100 => "revision_height": 101
"revision_number": 1,
},
// Hash of the consumer chain genesis state without the consumer CCV module genesis params.
// => not relevant for changeover procedure
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
// Hash of the consumer chain binary that should be run by validators on standalone chain upgrade
// => not relevant for changeover procedure as it may become stale
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
// Unbonding period for the consumer chain.
// It should should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
// IBC transfer packets will timeout after this interval elapses.
"transfer_timeout_period": 1800000000000,
// The fraction of tokens allocated to the consumer redistribution address during distribution events.
// The fraction is a string representing a decimal number. For example "0.75" would represent 75%.
// The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.
"consumer_redistribution_fraction": "0.75",
// BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.
// eg. send rewards to the provider every 1000 blocks
"blocks_per_distribution_transmission": 1000,
// The number of historical info entries to persist in store.
// This param is a part of the cosmos sdk staking module. In the case of
// a ccv enabled consumer chain, the ccv module acts as the staking module.
"historical_entries": 10000,
// The ID of a token transfer channel used for the Reward Distribution
// sub-protocol. If DistributionTransmissionChannel == "", a new transfer
// channel is created on top of the same connection as the CCV channel.
// Note that transfer_channel_id is the ID of the channel end on the consumer chain.
// it is most relevant for chains performing a standalone to consumer changeover
// in order to maintain the existing ibc transfer channel
"distribution_transmission_channel": "channel-123" // NOTE: use existing transfer channel if available
// Corresponds to the percentage of validators that have to validate the chain under the Top N case.
// For example, 53 corresponds to a Top 53% chain, meaning that the top 53% provider validators by voting power
// have to validate the proposed consumer chain. top_N can either be 0 or any value in [50, 100].
// A chain can join with top_N == 0 as an Opt In chain, or with top_N ∈ [50, 100] as a Top N chain.
"top_N": 95,
// Corresponds to the maximum power (percentage-wise) a validator can have on the consumer chain. For instance, if
// `validators_power_cap` is set to 32, it means that no validator can have more than 32% of the voting power on the
// consumer chain. Note that this might not be feasible. For example, think of a consumer chain with only
// 5 validators and with `validators_power_cap` set to 10%. In such a scenario, at least one validator would need
// to have more than 20% of the total voting power. Therefore, `validators_power_cap` operates on a best-effort basis.
"validators_power_cap": 0,
// Corresponds to the maximum number of validators that can validate a consumer chain.
// Only applicable to Opt In chains. Setting `validator_set_cap` on a Top N chain is a no-op.
"validator_set_cap": 0,
// Corresponds to a list of provider consensus addresses of validators that are the ONLY ones that can validate
// the consumer chain.
"allowlist": [],
// Corresponds to a list of provider consensus addresses of validators that CANNOT validate the consumer chain.
"denylist": []
}
+
info

As seen in the ConsumerAdditionProposal example above, the changeover procedure can be used together with Partial Set Security. +This means, that a standalone chain can choose to only be validated by some of the validators of the provider chain by setting top_N appropriately, or by +additionally setting a validators-power cap, validator-set cap, etc. by using the power-shaping parameters.

+

3. Submit an Upgrade Proposal & Prepare for Changeover

+

This proposal should add the ccv consumer module to your chain.

+
    +
  • proposal upgrade_height must happen after spawn_time in the ConsumerAdditionProposal
  • +
  • advise validators about the exact procedure for your chain and point them to your onboarding repository
  • +
+

4. Upgrade time 🚀

+
    +
  • after spawn_time, request ConsumerGenesis from the provider and place it in <CURRENT_USER_HOME_DIR>/.sovereign/config/genesis.json
  • +
  • upgrade the binary to the one listed in your UpgradeProposal
  • +
+

The chain starts after at least 66.67% of standalone voting power comes online. The consumer chain is considered interchain secured once the "old" validator set signs a couple of blocks and transfers control to the provider validator set.

+
    +
  • provide a repo with onboarding instructions for validators (it should already be listed in the proposal)
  • +
  • genesis.json after spawn_time obtained from provider (MUST contain the initial validator set)
  • +
  • maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)
  • +
+ + \ No newline at end of file diff --git a/consumer-development/changeover-procedure.html.html b/consumer-development/changeover-procedure.html.html new file mode 100644 index 0000000000..2c66a33d78 --- /dev/null +++ b/consumer-development/changeover-procedure.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/consumer-development/consumer-chain-governance.html b/consumer-development/consumer-chain-governance.html new file mode 100644 index 0000000000..646db1c5b4 --- /dev/null +++ b/consumer-development/consumer-chain-governance.html @@ -0,0 +1,26 @@ + + + + + +Consumer Chain Governance | Interchain Security + + + + +
Version: main

Consumer Chain Governance

+

Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We'll cover what these are in the "Whitelist" section below.

+

Democracy module

+

The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy.

+

Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus.

+

For an example, see the Democracy Consumer

+

CosmWasm

+

There are several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain.

+

For an example, see Neutron.

+

The Whitelist

+

Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see Neutron's whitelist.

+ + \ No newline at end of file diff --git a/consumer-development/consumer-chain-governance.html.html b/consumer-development/consumer-chain-governance.html.html new file mode 100644 index 0000000000..37fee83114 --- /dev/null +++ b/consumer-development/consumer-chain-governance.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/consumer-development/consumer-genesis-transformation.html b/consumer-development/consumer-genesis-transformation.html new file mode 100644 index 0000000000..28daf65fdd --- /dev/null +++ b/consumer-development/consumer-genesis-transformation.html @@ -0,0 +1,41 @@ + + + + + +Consumer Genesis Transformation | Interchain Security + + + + +
Version: main

Consumer Genesis Transformation

+

Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentation on Onboarding and Changeover). +In case that the provider chain is running an older version of the InterChainSecurity (ICS) module than the consumer chain - or vice versa - the exported CCV data might need to be transformed to the format supported by the ICS implementation run on the consumer chain. This is the case if the consumer chain runs version 4 of ICS or later and the provider is running version 3 or older of the ICS module.

+

Check the compatibility notes for known incompatibilities between provider and consumer versions and indications if a consumer genesis transformation is required.

+

To transform such CCV data follow the instructions below

+

1. Prerequisite

+
    +
  • used provider and consumer versions require transformation step as indicated in in the compatibility notes
  • +
  • interchain-security-cd application supports the versions used by the consumer and provider
  • +
+

2. Export the CCV data

+

Export the CCV data from the provider chain as described in the Onboarding and Changeover your following. +As a result the CCV data will be stored in a file in JSON format.

+

3. Transform CCV data

+

To transform the CCV data

+
    +
  • to the format supported by the current version of the consumer run the following command: +
    interchain-security-cd genesis transform [genesis-file]
    +where 'genesis-file' is the path to the file containing the CCV data exported in step 2. +As a result the CCV data in the new format will be written to standard output.
  • +
  • a specific target version of a consumer run the following command: +
    interchain-security-cd genesis transform --to <target_version> [genesis-file]

    +where <target_version is the ICS version the consumer chain is running. +Use interchain-security-cd genesis transform --help to get more details about supported target versions and more.
  • +
+

Use the new CCV data as described in the procedure you're following.

+ + \ No newline at end of file diff --git a/consumer-development/consumer-genesis-transformation.html.html b/consumer-development/consumer-genesis-transformation.html.html new file mode 100644 index 0000000000..90add743f4 --- /dev/null +++ b/consumer-development/consumer-genesis-transformation.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/consumer-development/offboarding.html b/consumer-development/offboarding.html new file mode 100644 index 0000000000..27ee3d17de --- /dev/null +++ b/consumer-development/offboarding.html @@ -0,0 +1,19 @@ + + + + + +Offboarding Checklist | Interchain Security + + + + +
Version: main

Consumer Offboarding

+

To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).

+
// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.
// If it passes, all the consumer chain's state is removed from the provider chain. The outstanding unbonding
// operation funds are released.
{
// the title of the proposal
"title": "This was a great chain",
"description": "Here is a .md formatted string specifying removal details",
// the chain-id of the consumer chain to be stopped
"chain_id": "consumerchain-1",
// the time on the provider chain at which all validators are responsible to stop their consumer chain validator node
"stop_time": "2023-03-07T12:40:00.000000Z",
}
+

More information will be listed in a future version of this document.

+ + \ No newline at end of file diff --git a/consumer-development/offboarding.html.html b/consumer-development/offboarding.html.html new file mode 100644 index 0000000000..f163abd589 --- /dev/null +++ b/consumer-development/offboarding.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/consumer-development/onboarding.html b/consumer-development/onboarding.html new file mode 100644 index 0000000000..03799c727f --- /dev/null +++ b/consumer-development/onboarding.html @@ -0,0 +1,61 @@ + + + + + +Onboarding Checklist | Interchain Security + + + + +
Version: main

Consumer Onboarding Checklist

+

The following checklists will aid in onboarding a new consumer chain to interchain security.

+

Additionally, you can check the testnet repo for a comprehensive guide on preparing and launching consumer chains.

+

1. Complete testing & integration

+
    +
  • test integration with gaia
  • +
  • test your protocol with supported relayer versions (minimum hermes 1.4.1)
  • +
  • reach out to the ICS team if you are facing issues
  • +
+

2. Create an Onboarding Repository

+

To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain.

+

This should include (at minimum):

+
    +
  • genesis.json without CCV data (before the proposal passes)
  • +
  • genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see Transform Consumer Genesis)
  • +
  • information about relevant seed/peer nodes you are running
  • +
  • relayer information (compatible versions)
  • +
  • copy of your governance proposal (as JSON)
  • +
  • a script showing how to start your chain and connect to peers (optional)
  • +
  • take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable
  • +
+

Example of such a repository can be found here.

+

3. Submit a Governance Proposal

+

Before you submit a ConsumerChainAddition proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch. +If possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues.

+

Additionally, reach out to the community via the forum to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers.

+
    +
  • determine your chain's spawn time
  • +
  • determine consumer chain parameters to be put in the proposal
  • +
  • take note to include a link to your onboarding repository
  • +
  • describe the purpose and benefits of running your chain
  • +
  • determine whether your chain should be an Opt-In chain or a Top N chain (see Partial Set Security)
  • +
  • if desired, decide on power-shaping parameters (see Power Shaping)
  • +
+

Example of a consumer chain addition proposal.

+
// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.
// If it passes, if the top_N parameter is not equal to 0, the top N% of validators by voting power on the provider chain are expected to validate the consumer chain at spawn time.
// Otherwise, only validators that opted in during the proposal period are expected to validate the consumer chain at spawn time.
// It is recommended that spawn time occurs after the proposal end time.
{
// Title of the proposal
"title": "Add consumer chain",
// Description of the proposal
// format the text as a .md file and include the file in your onboarding repository
"description": ".md description of your chain and all other relevant information",
// Proposed chain-id of the new consumer chain.
// Must be unique from all other consumer chain ids of the executing provider chain.
"chain_id": "newchain-1",
// Initial height of new consumer chain.
// For a completely new chain, this will be {0,1}.
"initial_height" : {
"revision_height": 0,
"revision_number": 1,
},
// Hash of the consumer chain genesis state without the consumer CCV module genesis params.
// It is used for off-chain confirmation of genesis.json validity by validators and other parties.
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
// Hash of the consumer chain binary that should be run by validators on chain initialization.
// It is used for off-chain confirmation of binary validity by validators and other parties.
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",
// Time on the provider chain at which the consumer chain genesis is finalized and validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
// Unbonding period for the consumer chain.
// It should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
// IBC transfer packets will timeout after this interval elapses.
"transfer_timeout_period": 1800000000000,
// The fraction of tokens allocated to the consumer redistribution address during distribution events.
// The fraction is a string representing a decimal number. For example "0.75" would represent 75%.
// The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.
"consumer_redistribution_fraction": "0.75",
// BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.
// eg. send rewards to the provider every 1000 blocks
"blocks_per_distribution_transmission": 1000,
// The number of historical info entries to persist in store.
// This param is a part of the cosmos sdk staking module. In the case of
// a ccv enabled consumer chain, the ccv module acts as the staking module.
"historical_entries": 10000,
// The ID of a token transfer channel used for the Reward Distribution
// sub-protocol. If DistributionTransmissionChannel == "", a new transfer
// channel is created on top of the same connection as the CCV channel.
// Note that transfer_channel_id is the ID of the channel end on the consumer chain.
// it is most relevant for chains performing a standalone to consumer changeover
// in order to maintain the existing ibc transfer channel
"distribution_transmission_channel": "channel-123",
// Corresponds to the percentage of validators that have to validate the chain under the Top N case.
// For example, 53 corresponds to a Top 53% chain, meaning that the top 53% provider validators by voting power
// have to validate the proposed consumer chain. top_N can either be 0 or any value in [50, 100].
// A chain can join with top_N == 0 as an Opt In chain, or with top_N ∈ [50, 100] as a Top N chain.
"top_N": 95,
// Corresponds to the maximum power (percentage-wise) a validator can have on the consumer chain. For instance, if
// `validators_power_cap` is set to 32, it means that no validator can have more than 32% of the voting power on the
// consumer chain. Note that this might not be feasible. For example, think of a consumer chain with only
// 5 validators and with `validators_power_cap` set to 10%. In such a scenario, at least one validator would need
// to have more than 20% of the total voting power. Therefore, `validators_power_cap` operates on a best-effort basis.
"validators_power_cap": 0,
// Corresponds to the maximum number of validators that can validate a consumer chain.
// Only applicable to Opt In chains. Setting `validator_set_cap` on a Top N chain is a no-op.
"validator_set_cap": 0,
// Corresponds to a list of provider consensus addresses of validators that are the ONLY ones that can validate
// the consumer chain.
"allowlist": [],
// Corresponds to a list of provider consensus addresses of validators that CANNOT validate the consumer chain.
"denylist": []
}
+

4. Launch

+

The consumer chain starts after at least 66.67% of its voting power comes online. +Note that this means 66.67% of the voting power in the consumer validator set, which will be comprised of all validators that either opted in to the chain or are part of the top N% of the provider chain (and are thus automatically opted in). +The consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer

+
    +
  • provide a repo with onboarding instructions for validators (it should already be listed in the proposal)
  • +
  • genesis.json with ccv data populated (MUST contain the initial validator set)
  • +
  • maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)
  • +
  • have a block explorer in place to track chain activity & health
  • +
+ + \ No newline at end of file diff --git a/consumer-development/onboarding.html.html b/consumer-development/onboarding.html.html new file mode 100644 index 0000000000..bebf94e716 --- /dev/null +++ b/consumer-development/onboarding.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/faq.html b/faq.html new file mode 100644 index 0000000000..0430a7f405 --- /dev/null +++ b/faq.html @@ -0,0 +1,90 @@ + + + + + +Frequently Asked Questions | Interchain Security + + + + +
Version: main

Frequently Asked Questions

What is a consumer chain?

+

Consumer chain is a blockchain operated by (a subset of) the validators of the provider chain. The ICS protocol ensures that the consumer chain gets information about which validators should run it (informs consumer chain about the current state of the validator set and the opted in validators for this consumer chain on the provider).

+

Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements.

+

What happens to consumer if provider is down?

+

In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set.

+

The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness.

+

However, if the trusting_period (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain. +This means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about.

+

Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point. +At the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.

+

What happens to provider if consumer is down?

+

Consumer chains do not impact the provider chain. +The ICS protocol is concerned only with validator set management, and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events).

+

Can I run the provider and consumer chains on the same machine?

+

Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation.

+

Can the consumer chain have its own token?

+

As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees.

+

How are Tx fees paid on consumer?

+

The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations.

+

Are there any restrictions the consumer chains need to abide by?

+

No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way. +The only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain.

+

What's in it for the validators and stakers?

+

The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by ConsumerRedistributionFraction. The rewards are distributed (sent to the provider) every BlocksPerDistributionTransmission.

+
note

ConsumerRedistributionFraction and BlocksPerDistributionTransmission are parameters defined in the ConsumerAdditionProposal used to create the consumer chain. These parameters can be changed via consumer chain governance.

+

Can the consumer chain have its own governance?

+

Yes.

+

In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.

+

Validators can also be representatives but representatives are not required to run validator nodes.

+

This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance.

+

Can validators opt out of validating a consumer chain?

+

A validator can always opt out from an Opt-In consumer chain. +A validator can only opt out from a Top N chain if the validator does not belong to the top N% validators.

+

How does Slashing work?

+

Validators that perform an equivocation or a light-client attack on a consumer chain are slashed on the provider chain. +We achieve this by submitting the proof of the equivocation or the light-client attack to the provider chain (see slashing).

+

Can Consumer Chains perform Software Upgrades?

+

Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM).

+

Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module.

+

How can I connect to the testnets?

+

Check out the Joining Interchain Security testnet section.

+

How do I start using ICS?

+

To become a consumer chain use this checklist and check the App integration section

+

Which relayers are supported?

+

Currently supported versions:

+
    +
  • Hermes 1.8.0
  • +
+

How does key delegation work in ICS?

+

You can check the Key Assignment Guide for specific instructions.

+

How does Partial Set Security work?

+

Partial Set Security allows a provider chain to share only a subset of its validator set with a consumer chain. This subset can be determined by the top N% validators by voting power, or by validators opting in to validate the consumer chain. Partial Set Security allows for flexible tradeoffs between security, decentralization, and the budget a consumer chain spends on rewards to validators.

+

See the Partial Set Security section for more information.

+

How does a validator know which consumers chains it has to validate?

+

In order for a validator to keep track of all the chains it has to validate, the validator can use the +has-to-validate query.

+

How many chains can a validator opt in to?

+

There is no limit in the number of consumers chains a validator can choose to opt in to.

+

Can validators assign a consensus keys while a consumer-addition proposal is in voting period?

+

Yes, see the Key Assignment Guide for more information.

+

Can validators assign a consensus key during the voting period for a consumer-addition proposal if they are not in the top N?

+

Yes.

+

Can validators opt in to an Opt-in or Top N chain after its consumer-addition proposal voting period is over but before the spawn time?

+

Yes.

+

Can validators opt in to an Opt-in chain after the spawn time if nobody else opted in?

+

No, the consumer chain will not be added if nobody opted in by the spawn time. At least one validator, regardless of its voting power, must opt in before the spawn time arrives in order for the chain can start.

+

Can all validators opt out of an Opt-in chain?

+

Yes, the consumer chain will halt with an ERR CONSENSUS FAILURE error after the opt-out message for the last validator is received.

+

Can validators set a commission rate for chains they have not opted in to?

+

Yes, and this is useful for validators that are not in the top N% of the provider chain, but might move into the top N% in the future. +By setting the commission rate ahead of time, they can make sure that they immediately have a commission rate of their choosing as soon as they are in the top N%.

+

Can a consumer chain modify its power shaping parameters?

+

Yes, by issuing a ConsumerModificationProposal.

+

Can a Top N consumer chain become Opt-In or vice versa?

+

Yes, by issuing a ConsumerModificationProposal.

+ + \ No newline at end of file diff --git a/faq.html.html b/faq.html.html new file mode 100644 index 0000000000..bfb81c3089 --- /dev/null +++ b/faq.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/features/democracy-modules.html b/features/democracy-modules.html new file mode 100644 index 0000000000..2730138400 --- /dev/null +++ b/features/democracy-modules.html @@ -0,0 +1,72 @@ + + + + + +Democracy modules | Interchain Security + + + + +
Version: main

Democracy modules

+

This section is relevant for chains transitioning from a standalone chain and new consumer chains that require some functionality from the x/staking module.

+

The democracy modules comprise x/staking, x/distribution and x/governance with overrides and extensions required for normal operation when participating in interchain security.

+

The modules are plug-and-play and only require small wiring changes to be enabled.

+

For a full integration check the consumer-democracy example app.

+

Staking

+

The democracy staking module allows the cosmos-sdk x/staking module to be used alongside the interchain security consumer module.

+

The module uses overrides that allow the full x/staking functionality with one notable difference - the staking module will no longer be used to provide the consensus validator set.

+

Implications for consumer chains

+

The x/ccv/democracy/staking allows consumer chains to separate governance from block production.

+
info

The validator set coming from the provider chain does not need to participate in governance - they only provide infrastructure (create blocks and maintain consensus).

+

Governators (aka. Governors)

+

Validators registered with the x/staking module become "Governators".

+

Unlike Validators, Governators are not required to run any chain infastructure since they are not signing any blocks.

+

However, Governators retain a subset of the validator properties:

+
    +
  • new Governators can be created (via MsgCreateValidator)
  • +
  • Governators can accept delegations
  • +
  • Governators can vote on governance proposals (with their self stake and delegations)
  • +
  • Governators earn token rewards
  • +
+

With these changes, Governators can become community advocates that can specialize in chain governance and they get rewarded for their participation the same way the validators do.

+

Additionally, Governators can choose to provide additional infrastructure such as RPC/API access points, archive nodes, indexers and similar software.

+

Tokenomics

+

The consumer chain's token will remain a governance and reward token. The token's parameters (inflation, max supply, burn rate) are not affected.

+
info

Staking rewards are distributed to all Governators and their delegators after distributing the rewards to the provider chain's validator set.

+

Integration

+

The x/ccv/democracy/staking module provides these x/staking overrides:

+

// InitGenesis delegates the InitGenesis call to the underlying x/staking module,
// however, it returns no validator updates as validators are tracked via the
// consumer chain's x/cvv/consumer module and so this module is not responsible for returning the initial validator set.
func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate {
var genesisState types.GenesisState

cdc.MustUnmarshalJSON(data, &genesisState)
_ = am.keeper.InitGenesis(ctx, &genesisState) // run staking InitGenesis

return []abci.ValidatorUpdate{} // do not return validator updates
}

// EndBlock delegates the EndBlock call to the underlying x/staking module.
// However, no validator updates are returned as validators are tracked via the
// consumer chain's x/cvv/consumer module.
func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
_ = am.keeper.BlockValidatorUpdates(ctx) // perform staking BlockValidatorUpdates
return []abci.ValidatorUpdate{} // do not return validator updates
}
+

To integrate the democracy/staking follow this guide:

+

1. confirm that no modules are returning validator updates

+
tip

Only the x/ccv/consumer module should be returning validator updates.

+

If some of your modules are returning validator updates please disable them while maintaining your business logic:

+
func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate {
var genesisState types.GenesisState

cdc.MustUnmarshalJSON(data, &genesisState)
- return am.keeper.InitGenesis(ctx, &genesisState)
+ _ = am.keeper.InitGenesis(ctx, &genesisState) // run InitGenesis but drop the result
+ return []abci.ValidatorUpdate{} // return empty validator updates
}


func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
- return am.keeper.BlockValidatorUpdates(ctx)
+ _ = am.keeper.BlockValidatorUpdates(ctx) // perform staking BlockValidatorUpdates
+ return []abci.ValidatorUpdate{} // return empty validator updates
}
+

2. wire the module in app.go

+

You do not need to remove the cosmos-sdk StakingKeeper from your wiring.

+
import (
...
+ ccvstaking "github.com/cosmos/interchain-security/v4/x/ccv/democracy/staking"
)

var (
// replace the staking.AppModuleBasic
ModuleBasics = module.NewBasicManager(
auth.AppModuleBasic{},
genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator),
bank.AppModuleBasic{},
capability.AppModuleBasic{},
- sdkstaking.AppModuleBasic{},
+ ccvstaking.AppModuleBasic{}, // replace sdkstaking
...
)
)


func NewApp(...) {
...

// use sdk StakingKeepeer
app.StakingKeeper = stakingkeeper.NewKeeper(
appCodec,
keys[stakingtypes.StoreKey],
app.AccountKeeper,
app.BankKeeper,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

app.MintKeeper = mintkeeper.NewKeeper(
appCodec,
keys[minttypes.StoreKey],
app.StakingKeeper,
app.AccountKeeper,
app.BankKeeper,
authtypes.FeeCollectorName,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

// no changes required for the distribution keeper
app.DistrKeeper = distrkeeper.NewKeeper(
appCodec,
keys[distrtypes.StoreKey],
app.AccountKeeper,
app.BankKeeper,
app.StakingKeeper, // keep StakingKeeper!
authtypes.FeeCollectorName,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

+ // pre-initialize ConsumerKeeper to satsfy ibckeeper.NewKeeper
+ app.ConsumerKeeper = consumerkeeper.NewNonZeroKeeper(
+ appCodec,
+ keys[consumertypes.StoreKey],
+ app.GetSubspace(consumertypes.ModuleName),
+ )
+
+ app.IBCKeeper = ibckeeper.NewKeeper(
+ appCodec,
+ keys[ibchost.StoreKey],
+ app.GetSubspace(ibchost.ModuleName),
+ &app.ConsumerKeeper,
+ app.UpgradeKeeper,
+ scopedIBCKeeper,
+ )
+
+ // Create CCV consumer and modules
+ app.ConsumerKeeper = consumerkeeper.NewKeeper(
+ appCodec,
+ keys[consumertypes.StoreKey],
+ app.GetSubspace(consumertypes.ModuleName),
+ scopedIBCConsumerKeeper,
+ app.IBCKeeper.ChannelKeeper,
+ &app.IBCKeeper.PortKeeper,
+ app.IBCKeeper.ConnectionKeeper,
+ app.IBCKeeper.ClientKeeper,
+ app.SlashingKeeper,
+ app.BankKeeper,
+ app.AccountKeeper,
+ &app.TransferKeeper,
+ app.IBCKeeper,
+ authtypes.FeeCollectorName,
+ )
+
+ // Setting the standalone staking keeper is only needed for standalone to consumer changeover chains
+ // New chains using the democracy/staking do not need to set this
+ app.ConsumerKeeper.SetStandaloneStakingKeeper(app.StakingKeeper)



// change the slashing keeper dependency
app.SlashingKeeper = slashingkeeper.NewKeeper(
appCodec,
legacyAmino,
keys[slashingtypes.StoreKey],
- app.StakingKeeper,
+ &app.ConsumerKeeper, // ConsumerKeeper implements StakingKeeper interface
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

// register slashing module StakingHooks to the consumer keeper
+ app.ConsumerKeeper = *app.ConsumerKeeper.SetHooks(app.SlashingKeeper.Hooks())
+ consumerModule := consumer.NewAppModule(app.ConsumerKeeper, app.GetSubspace(consumertypes.ModuleName))

// register the module with module manager
// replace the x/staking module
app.MM = module.NewManager(
...
- sdkstaking.NewAppModule(appCodec, &app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)),
+ ccvstaking.NewAppModule(appCodec, *app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)),
...
)
}
+

Governance

+

The x/ccv/democracy/governance module extends the x/governance module with the functionality to filter proposals.

+
tip

Consumer chains can limit in the types of governance proposals that can be executed on chain to avoid inadvertent changes to interchain security protocol that could affect security properties.

+

The module uses AnteHandler to limit the types of proposals that can be executed.

+

Integration

+

Add new AnteHandler to your app.

+

// app/ante/forbidden_proposals.go
package ante

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"

"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
"github.com/cosmos/cosmos-sdk/x/params/types/proposal"
)

type ForbiddenProposalsDecorator struct {
isLegacyProposalWhitelisted func(govv1beta1.Content) bool
isModuleWhiteList func(string) bool
}

func NewForbiddenProposalsDecorator(
whiteListFn func(govv1beta1.Content) bool,
isModuleWhiteList func(string) bool,
) ForbiddenProposalsDecorator {
return ForbiddenProposalsDecorator{
isLegacyProposalWhitelisted: whiteListFn,
isModuleWhiteList: isModuleWhiteList,
}
}

func (decorator ForbiddenProposalsDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
currHeight := ctx.BlockHeight()

for _, msg := range tx.GetMsgs() {
// if the message is MsgSubmitProposal, check if proposal is whitelisted
submitProposalMgs, ok := msg.(*govv1.MsgSubmitProposal)
if !ok {
continue
}

messages := submitProposalMgs.GetMessages()
for _, message := range messages {
if sdkMsg, isLegacyProposal := message.GetCachedValue().(*govv1.MsgExecLegacyContent); isLegacyProposal {
// legacy gov proposal content
content, err := govv1.LegacyContentFromMessage(sdkMsg)
if err != nil {
return ctx, fmt.Errorf("tx contains invalid LegacyContent")
}
if !decorator.isLegacyProposalWhitelisted(content) {
return ctx, fmt.Errorf("tx contains unsupported proposal message types at height %d", currHeight)
}
continue
}
// not legacy gov proposal content and not whitelisted
if !decorator.isModuleWhiteList(message.TypeUrl) {
return ctx, fmt.Errorf("tx contains unsupported proposal message types at height %d", currHeight)
}
}
}

return next(ctx, tx, simulate)
}

func IsProposalWhitelisted(content v1beta1.Content) bool {
switch c := content.(type) {
case *proposal.ParameterChangeProposal:
return isLegacyParamChangeWhitelisted(c.Changes)

default:
return false
}
}

func isLegacyParamChangeWhitelisted(paramChanges []proposal.ParamChange) bool {
for _, paramChange := range paramChanges {
_, found := LegacyWhitelistedParams[legacyParamChangeKey{Subspace: paramChange.Subspace, Key: paramChange.Key}]
if !found {
return false
}
}
return true
}

type legacyParamChangeKey struct {
Subspace, Key string
}

// Legacy params can be whitelisted
var LegacyWhitelistedParams = map[legacyParamChangeKey]struct{}{
{Subspace: ibctransfertypes.ModuleName, Key: "SendEnabled"}: {},
{Subspace: ibctransfertypes.ModuleName, Key: "ReceiveEnabled"}: {},
}

// New proposal types can be whitelisted
var WhiteListModule = map[string]struct{}{
"/cosmos.gov.v1.MsgUpdateParams": {},
"/cosmos.bank.v1beta1.MsgUpdateParams": {},
"/cosmos.staking.v1beta1.MsgUpdateParams": {},
"/cosmos.distribution.v1beta1.MsgUpdateParams": {},
"/cosmos.mint.v1beta1.MsgUpdateParams": {},
}

func IsModuleWhiteList(typeUrl string) bool {
_, found := WhiteListModule[typeUrl]
return found
}
+

Add the AnteHandler to the list of supported antehandlers:

+
// app/ante_handler.go
package app

import (
...

+ democracyante "github.com/cosmos/interchain-security/v4/app/consumer-democracy/ante"
+ consumerante "github.com/cosmos/interchain-security/v4/app/consumer/ante"
+ icsconsumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper"
)

type HandlerOptions struct {
ante.HandlerOptions

IBCKeeper *ibckeeper.Keeper
+ ConsumerKeeper ibcconsumerkeeper.Keeper
}

func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
....

anteDecorators := []sdk.AnteDecorator{
...
+ consumerante.NewMsgFilterDecorator(options.ConsumerKeeper),
+ consumerante.NewDisabledModulesDecorator("/cosmos.evidence", "/cosmos.slashing"),
+ democracyante.NewForbiddenProposalsDecorator(IsProposalWhitelisted, IsModuleWhiteList),
...
}

return sdk.ChainAnteDecorators(anteDecorators...), nil
}
+

Wire the module in app.go.

+
// app/app.go
package app
import (
...
sdkgov "github.com/cosmos/cosmos-sdk/x/gov"
govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"

+ ccvgov "github.com/cosmos/interchain-security/v4/x/ccv/democracy/governance"
)

var (

// use sdk governance module
ModuleBasics = module.NewBasicManager(
...
sdkgov.NewAppModuleBasic(
[]govclient.ProposalHandler{
paramsclient.ProposalHandler,
upgradeclient.LegacyProposalHandler,
upgradeclient.LegacyCancelProposalHandler,
},
),
)
)

func NewApp(...) {
// retain sdk gov router and keeper registrations
sdkgovRouter := govv1beta1.NewRouter()
sdkgovRouter.
AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler).
AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)).
AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(&app.UpgradeKeeper))
govConfig := govtypes.DefaultConfig()

app.GovKeeper = *govkeeper.NewKeeper(
appCodec,
keys[govtypes.StoreKey],
app.AccountKeeper,
app.BankKeeper,
app.StakingKeeper,
app.MsgServiceRouter(),
govConfig,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

app.GovKeeper.SetLegacyRouter(sdkgovRouter)


// register the module with module manager
// replace the x/gov module
app.MM = module.NewManager(
- sdkgov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper, IsProposalWhitelisted, app.GetSubspace(govtypes.ModuleName), IsModuleWhiteList),
+ ccvgov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper, IsProposalWhitelisted, app.GetSubspace(govtypes.ModuleName), IsModuleWhiteList),
...
)
}
+

Distribution

+
tip

The democracy/distribution module allows the consumer chain to send rewards to the provider chain while retaining the x/distribution module for internal reward distribution to Governators and stakers.

+

How it works

+

First, a % of rewards to be distributed to the provider chain's validator set is calculated and sent to the provider chain. Only opted-in validators from the provider chain will receive the consumer rewards.

+

Second, the remaining rewards get distributed to the consumer chain's Governators and their delegators.

+
info

The % that is sent to the provider chain corresponds to 1 - ConsumerRedistributionFraction.

e.g. ConsumerRedistributionFraction = "0.75"

means that the consumer chain retains 75% of the rewards, while 25% gets sent to the provider chain to be distributed as rewards to provider chain validators.

+

Integration

+

Change the wiring in app.go

+
import (
...
distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper"
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
sdkdistr "github.com/cosmos/cosmos-sdk/x/distribution"

+ ccvdistr "github.com/cosmos/interchain-security/v4/x/ccv/democracy/distribution"
)

var (
// replace sdk distribution AppModuleBasic
ModuleBasics = module.NewBasicManager(
auth.AppModuleBasic{},
genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator),
bank.AppModuleBasic{},
capability.AppModuleBasic{},
ccvstaking.AppModuleBasic{}, // make sure you first swap the staking keeper
mint.AppModuleBasic{},
- sdkdistr.AppModuleBasic{},
+ ccvdistr.AppModuleBasic{},
)
)

func NewApp(...) {
....

app.DistrKeeper = distrkeeper.NewKeeper(
appCodec,
keys[distrtypes.StoreKey],
app.AccountKeeper,
app.BankKeeper,
app.StakingKeeper, // connect to sdk StakingKeeper
consumertypes.ConsumerRedistributeName,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

// register with the module manager
app.MM = module.NewManager(
...
- sdkdistr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, *app.StakingKeeper, authtypes.FeeCollectorName, app.GetSubspace(distrtypes.ModuleName)),

+ ccvdistr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, *app.StakingKeeper, authtypes.FeeCollectorName, app.GetSubspace(distrtypes.ModuleName)),
ccvstaking.NewAppModule(appCodec, *app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)),
...
)
}
+ + \ No newline at end of file diff --git a/features/democracy-modules.html.html b/features/democracy-modules.html.html new file mode 100644 index 0000000000..b02c501731 --- /dev/null +++ b/features/democracy-modules.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/features/key-assignment.html b/features/key-assignment.html new file mode 100644 index 0000000000..53199411cc --- /dev/null +++ b/features/key-assignment.html @@ -0,0 +1,59 @@ + + + + + +Key Assignment | Interchain Security + + + + +
Version: main

Key Assignment

+

Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate. +There are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains.

+

The feature is outlined in this ADR-001

+

By sending an AssignConsumerKey transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator.

+
tip

Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity.

+

Rules

+
    +
  • a key can be assigned as soon as the consumer addition proposal is submitted to the provider
  • +
  • validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider
  • +
  • validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X
  • +
  • a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain
  • +
+
tip

Validators can use a different key for each consumer chain.

+

Adding a key

+

First, create a new node on the consumer chain using the equivalent:

+
consumerd init <moniker>
+

Then query your node for the consensus key.

+
consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}
+

Then, make an assign-consensus-key transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain.

+
gaiad tx provider assign-consensus-key <consumer-chain-id> '<pubkey>' --from <tx-signer> --home <home_dir> --gas 900000 -b sync -y -o json
+
    +
  • consumer-chain-id is the string identifier of the consumer chain, as assigned on the provider chain
  • +
  • consumer-pub-key has the following format {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}
  • +
+

Check that the key was assigned correctly by querying the provider:

+
gaiad query provider validator-consumer-key <consumer-chain-id> cosmosvalcons1e....3xsj3ayzf4uv6
+

You must use a valcons address. You can obtain it by querying your node on the provider gaiad tendermint show-address

+

OR

+
gaiad query provider validator-provider-key <consumer-chain-id> consumervalcons1e....123asdnoaisdao
+

You must use a valcons address. You can obtain it by querying your node on the consumer consumerd tendermint show-address

+

OR

+
gaiad query provider all-pairs-valconsensus-address <consumer-chain-id>
+

You just need to use the chainId of consumer to query all pairs valconsensus address with consumer-pub-key for each of pair

+

Changing a key

+

To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied

+

Removing a key

+

To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the Adding a key section and using your provider consensus key.

+
warning

Validators are strongly recommended to assign a separate key for each consumer chain +and not reuse the provider key across consumer chains for security reasons.

+

Querying proposed consumer chains

+

To query the consumer addition proposals that are in the voting period, you can use the following command on the provider:

+
gaiad query provider list-proposed-consumer-chains
+

This query is valuable for staying informed about when keys can be assigned to newly proposed consumer chains.

+ + \ No newline at end of file diff --git a/features/key-assignment.html.html b/features/key-assignment.html.html new file mode 100644 index 0000000000..95b971c22f --- /dev/null +++ b/features/key-assignment.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/features/partial-set-security.html b/features/partial-set-security.html new file mode 100644 index 0000000000..9e5fc292a1 --- /dev/null +++ b/features/partial-set-security.html @@ -0,0 +1,32 @@ + + + + + +Partial Set Security | Interchain Security + + + + +
Version: main

Partial Set Security

+

Partial Set Security (PSS) allows consumer chains to leverage only a subset of validators from the provider chain, which offers more flexibility than the traditional Replicated Security model. By introducing the top_N parameter, each consumer chain can choose the extent of security needed:

+
    +
  • +

    Top N: Requires the top N% validators from the provider chain to secure the consumer chain. This guarantees that the validators with the most power on the provider will validate the consumer chain, while others can voluntarily opt in.

    +
  • +
  • +

    Opt-In: If the top_N parameter is set to zero, no validator is mandated to secure the consumer chain. Instead, any validator from the provider chain can opt in using a dedicated transaction.

    +
  • +
+

An advantage of a Top N chain is that the consumer chain is guaranteed to receive at least a certain fraction of the market cap of the provider chain in security. In turn, this chain needs to be approved by governance, since validators will be forced to run the chain. Thus, Top N chains should typically expect to need to provide a strong case for why they should be added to the provider chain, and they should make sure they offer enough rewards to incentivize validators and delegators to vote for their proposal.

+

Opt-In chains, on the other hand, are more flexible. While for technical reasons, they are also currently added via governance proposals, since validators are never forced to validate these chains and simply opt in if they want to, they should typically expect to get their proposals approved much more easily compared to Top N chains, since validators that do not want to validate the chain can simply choose not to opt in. +However, opt in chains do not get a fixed amount of security as a relation of the market cap of the provider as top N chains do, so opt in chains might want to keep an eye on how many validators have opted in to validate their chain and adjust their reward emissions accordingly to incentivize validators.

+
tip

Partial Set Security is handled only by the provider chain - the consumer chains are simply sent validator sets, and they are not aware that this represents only a subset of the provider chain's validator set.

+
caution

Both Opt In and Top N chains currently require a governance proposal to be added to the provider chain.

For Top N chains, this is also the long term vision for how they are launched.

For Opt In chains, this is a temporary measure to prevent issues around chain ID squatting, i.e. someone could spuriously register many desirable chain IDs of upcoming consumer chain and simply deny legitimate consumer chains from using them. Eventually, the plan is to allow launching Opt In chains permissionlessly without going through governance, with quality control being handled by the market of validators deciding which chains they would like to validate on.

+
tip

A running Top N consumer chain might want to become an Opt-In chain or vice versa. This can be achieved by issuing +a ConsumerModificationProposal.

+ + \ No newline at end of file diff --git a/features/partial-set-security.html.html b/features/partial-set-security.html.html new file mode 100644 index 0000000000..8d902b98dc --- /dev/null +++ b/features/partial-set-security.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/features/power-shaping.html b/features/power-shaping.html new file mode 100644 index 0000000000..1d43f3beab --- /dev/null +++ b/features/power-shaping.html @@ -0,0 +1,67 @@ + + + + + +Power Shaping | Interchain Security + + + + +
Version: main

Power Shaping

+

To give consumer chains more flexibility in choosing their validator set, Interchain Security offers +several "power shaping" mechanisms for consumer chains.

+

These are:

+
    +
  1. Capping the size of the validator set: The consumer chain can specify a maximum number of validators it +wants to have in its validator set. This can be used to limit the number of validators in the set, which can +be useful for chains that want to have a smaller validator set for faster blocks or lower overhead. If more validators +than the maximum size have opted in on a consumer chain, only the validators with the highest power, up to the specified +maximum, will validate the consumer chain.
  2. +
+
info

This is only applicable to Opt In chains (chains with Top N = 0).

+
    +
  1. Capping the fraction of power any single validator can have: The consumer chain can specify a maximum fraction +of the total voting power that any single validator in its validator set should have. +This is a security measure with the intention of making it harder for a single large validator to take over a consumer chain. This mitigates the risk of an Opt In chain with only a few validators being dominated by a validator with a large amount of stake opting in. +For example, setting this fraction to e.g. 33% would mean that no single validator can have more than 33% of the total voting power, +and thus there is no single validator who would stop the chain by going offline.
  2. +
+
info

This is a soft cap, and the actual power of a validator can exceed this fraction if the validator set is small (e.g. there are only 3 validators and the cap is 20%).

+
info

Rewards are distributed proportionally to validators with respect to their capped voting power on the consumer, +not their total voting power on the provider.

+
    +
  1. Allowlist and denylist: The consumer chain can specify a list of validators that are allowed or disallowed from participating in the validator set. If an allowlist is set, all validators not on the allowlist cannot validate the consumer chain. If a validator is on both lists, the denylist takes precedence, that is, they cannot validate the consumer chain. If neither list is set, all validators are able to validate the consumer chain.
  2. +
+
warning

Note that if denylisting is used in a Top N consumer chain, then the chain might not be secured by N% of the total provider's +power. For example, consider that the top validator V on the provider chain has 10% of the voting power, and we have a Top 50% consumer chain, +then if V is denylisted, the consumer chain would only be secured by at least 40% of the provider's power.

+

All these mechanisms are set by the consumer chain in the ConsumerAdditionProposal. They operate solely on the provider chain, meaning the consumer chain simply receives the validator set after these rules have been applied and does not have any knowledge about whether they are applied.

+

Each of these mechanisms is set during the consumer addition proposal (see Onboarding), and is currently immutable after the chain has been added.

+

The values can be seen by querying the list of consumer chains:

+
interchain-security-pd query provider list-consumer-chains
+

Guidelines for setting power shaping parameters

+

When setting power shaping parameters, please consider the following guidelines:

+
    +
  • Do not cap the validator set size too low: Notice that this number is the *maximum number of validators that will ever validate the consumer chain. If this number is too low, the chain will be very limited in the +amount of stake that secures it. The validator set size cap should only be used if there are strong reasons to prefer fewer validators. Consider that setting the cap will mean that +even if the whole validator set of the provider wants to validate on the chain, some validators will simply not be able to.
  • +
  • Capping the fraction of power any single validator can have is a decent security measure, but it's good to be aware of the interactions with the size of the validator set. +For example, if there are only 3 validators, and the cap is 20%, this will not be possible (since even splitting the power fairly would mean that each validator has 33% of the power, so is above the cap). +However, the cap can be a good measure to prevent a single large validator from essentially taking over the chain. +In general, values under 33% make sense (since a validator that has 33% of the chains power would halt the chain if they go offline). +Notice that the smaller this value is, the more the original voting power gets distorted, which could discourage large validators from deciding to opt in to the chain.
  • +
  • If the allowlist is empty, all validators can validate the chain. If it is non empty, then only validators on the allowlist can validate the chain. +Thus, an allowlist containing too few validators is a security risk. In particular, consider that if the validators on the allowlist lose a lot of stake or stop being validators, +an allowlist that is too short can very quickly become outdated and leave too few validators, or validators with too little stake, to secure the chain in a decentralized way.
  • +
  • If the denylist is too full, this can likewise be problematic. If too many large validators are denylisted, the chain might not be secured by a large enough fraction of the provider's power, in particular when +the power distribution on the provider shifts and the denylisted validators gain more power.
  • +
+

In general, when setting these parameters, consider that the voting power distribution in the future might be very different from the one right now, +and that the chain should be secure even if the power distribution changes significantly.

+
tip

The power shaping parameters of a running consumer chain can be changed through a ConsumerModificationProposal.

+ + \ No newline at end of file diff --git a/features/power-shaping.html.html b/features/power-shaping.html.html new file mode 100644 index 0000000000..48eaf5d737 --- /dev/null +++ b/features/power-shaping.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/features/proposals.html b/features/proposals.html new file mode 100644 index 0000000000..ab3f9a6815 --- /dev/null +++ b/features/proposals.html @@ -0,0 +1,54 @@ + + + + + +ICS Provider Proposals | Interchain Security + + + + +
Version: main

ICS Provider Proposals

+

Interchain security module introduces new proposal types to the provider.

+

The proposals are used to propose upcoming interchain security events through governance.

+

ConsumerAdditionProposal

+
info

If you are preparing a ConsumerAdditionProposal you can find more information in the consumer onboarding checklist.

+

Proposal type used to suggest adding a new consumer chain.

+

When proposals of this type are passed and the spawn_time specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain.

+

Minimal example:

+
{
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
"title": "Add consumer chain",
"description": ".md description of your chain and all other relevant information",
"chain_id": "newchain-1",
"initial_height" : {
"revision_height": 0,
"revision_number": 1,
},
// Unbonding period for the consumer chain.
// It should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
"transfer_timeout_period": 1800000000000,
"consumer_redistribution_fraction": "0.75",
"blocks_per_distribution_transmission": 1000,
"historical_entries": 10000,
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",
"distribution_transmission_channel": "channel-123",
"top_N": 95,
"validators_power_cap": 0,
"validator_set_cap": 0,
"allowlist": [],
"denylist": []
}
+

More examples can be found in the interchain security testnet repository here and here.

+

ConsumerRemovalProposal

+

Proposal type used to suggest removing an existing consumer chain.

+

When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain. +After the consumer chain removal, the chain in question will no longer be secured by the provider's validator set.

+
info

The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain. +Additional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set. +More information will be made available in the Consumer Offboarding Checklist.

+

Minimal example:

+
{
// the time on the provider chain at which all validators are responsible to stop their consumer chain validator node
"stop_time": "2023-03-07T12:40:00.000000Z",
// the chain-id of the consumer chain to be stopped
"chain_id": "consumerchain-1",
"title": "This was a great chain",
"description": "Here is a .md formatted string specifying removal details"
}
+

ConsumerModificationProposal

+

Proposal type used to change the power shaping parameters of a running consumer chain, as well as to change a Top N running +consumer chain to an Opt-In chain and vice versa.

+

When a ConsumerModificationProposal passes for a running consumer chain, the consumer chain would change all its +parameters to the ones passed in the ConsumerModificationProposal.

+

Assume, a chain-1 is a Top N chain. If the following ConsumerModificationProposal passes, then chain-1 would become +an Opt-In chain with a 40% validators power cap, a maximum number of 30 validators, and one denylisted validator.

+
{
"title": "Modify consumer chain",
"description": ".md description of your chain and all other relevant information",
"chain_id": "chain-1",
"top_N": 0,
"validators_power_cap": 40,
"validator_set_cap": 30,
"allowlist": [],
"denylist": ["cosmosvalcons1qmq08eruchr5sf5s3rwz7djpr5a25f7xw4mceq"]
}
+
warning

If top_N, validators_power_cap, or some other argument is not included in the proposal, then it is considered +that the default value is set for this argument. For example, if a Top 50% chain wants to only modify validators_power_cap +from 35 to 40, then the ConsumerModificationProposal would still need to include that top_N is 50. Otherwise +top_N would be set to its default value of 0, and the chain would become an Opt-In chain.

To be safe, always include top_N and all the power shaping parameters in your ConsumerModificationProposal.

+

ChangeRewardDenomProposal

+

Proposal type used to mutate the set of denoms accepted by the provider as rewards.

+
tip

A ChangeRewardDenomProposal will only be accepted on the provider chain if at least one of the denomsToAdd or denomsToRemove fields is populated with at least one denom. Also, a denom cannot be repeated in both sets.

+

Minimal example:

+
{
"title": "Add uatom as a reward denom",
"description": "Here is more information about the proposal",
"denomsToAdd": ["uatom"],
"denomsToRemove": []
}
+
tip

Besides native provider denoms (e.g., uatom for the Cosmos Hub), please use the ibc/* denom trace format. +For example, for untrn transferred over the path transfer/channel-569, the denom trace +can be queried using the following command:

> gaiad query ibc-transfer denom-hash transfer/channel-569/untrn
hash: 0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5

Then use the resulting hash in the ChangeRewardDenomProposal, e.g.,

{
"title": "Add untrn as a reward denom",
"description": "Here is more information about the proposal",
"denomsToAdd": ["ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5"],
"denomsToRemove": []
}
+ + \ No newline at end of file diff --git a/features/proposals.html.html b/features/proposals.html.html new file mode 100644 index 0000000000..fdc0d8054b --- /dev/null +++ b/features/proposals.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/features/reward-distribution.html b/features/reward-distribution.html new file mode 100644 index 0000000000..55aaff47c9 --- /dev/null +++ b/features/reward-distribution.html @@ -0,0 +1,33 @@ + + + + + +Reward Distribution | Interchain Security + + + + +
Version: main

Reward Distribution

+

Sending and distributing rewards from consumer chains to the provider chain is handled by the Reward Distribution sub-protocol.

+

Consumer chains have the option of sharing (a portion of) their block rewards (inflation tokens and fees) with the provider chain validators and delegators. +In Interchain Security, block rewards are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel. +This channel is created during consumer chain initialization, unless it is provided via the ConsumerAdditionProposal when adding a new consumer chain. +For more details, see the reward distribution parameters.

+
tip

Providing an IBC transfer channel (see DistributionTransmissionChannel) enables a consumer chain to re-use one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ibc denom that may already be in use. +This is especially important for standalone chains transitioning to become consumer chains. +For more details, see the changeover procedure.

+

Reward distribution on the provider is handled by the distribution module.

+

Whitelisting Reward Denoms

+

The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the ConsumerRewardsPool. +To avoid spam, the provider must whitelist denoms before accepting them as ICS rewards. +Only whitelisted denoms are transferred from the ConsumerRewardsPool to the FeePoolAddress, to be distributed to delegators and validators. +The whitelisted denoms can be adjusted through governance by sending a ChangeRewardDenomProposal.

+

To query the list of whitelisted reward denoms on the Cosmos Hub, use the following command:

+
> gaiad q provider registered-consumer-reward-denoms
denoms:
- ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5
- ibc/6B8A3F5C2AD51CD6171FA41A7E8C35AD594AB69226438DB94450436EA57B3A89
- uatom
+
tip

Use the following command to get a human readable denom from the ibc/* denom trace format:

>  gaiad query ibc-transfer denom-trace ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5
denom_trace:
base_denom: untrn
path: transfer/channel-569
+ + \ No newline at end of file diff --git a/features/reward-distribution.html.html b/features/reward-distribution.html.html new file mode 100644 index 0000000000..96e09a30c6 --- /dev/null +++ b/features/reward-distribution.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/features/slashing.html b/features/slashing.html new file mode 100644 index 0000000000..72f425916a --- /dev/null +++ b/features/slashing.html @@ -0,0 +1,48 @@ + + + + + +Consumer Initiated Slashing | Interchain Security + + + + +
Version: main

Consumer Initiated Slashing

+

A consumer chain is essentially a regular Cosmos-SDK based chain that uses the Interchain Security module to achieve economic security by stake deposited on the provider chain, instead of its own chain. +In essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake).

+

To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized. +Any infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains.

+

In the current implementation there are two important changes brought by the Interchain Security module.

+

Downtime Infractions

+

Downtime infractions are reported by consumer chains and are acted upon on the provider as soon as the provider receives the infraction evidence.

+

Instead of slashing, the provider will only jail offending validator for the duration of time established by the chain parameters.

+
info

Slash throttling (sometimes called jail throttling) mechanism ensures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider.

+

Note that validators are only jailed for downtime on consumer chains that they opted-in to validate on, +or in the case of Top N chains, where they are automatically opted in by being in the Top N% of the validator set on the provider.

+

Equivocation Infractions

+

Equivocation infractions are reported by external agents (e.g., relayers) that can submit to the provider evidence of light client or double signing attacks observed on a consumer chain. +The evidence is submitted by sending MsgSubmitConsumerMisbehaviour or MsgSubmitConsumerDoubleVoting transactions to the provider. +When valid evidence is received, the malicious validators are slashed, jailed, and tombstoned on the provider. +This is enabled through the cryptographic verification of equivocation feature. +For more details, see ADR-005 and ADR-013.

+

Report equivocation infractions through CLI

+

The ICS provider module offers two commands for submitting evidence of misbehavior originating from a consumer chain. +Below are two examples illustrating the process on Cosmos Hub.

+

Use the following command to submit evidence of double signing attacks:

+
gaiad tx provider submit-consumer-double-voting [path/to/evidence.json] [path/to/infraction_header.json] --from node0 --home ../node0 --chain-id $CID 
+
Example of evidence.json
{
"vote_a": {
"type": 1,
"height": 25,
"round": 0,
"block_id": {
"hash": "tBBWTqjECl31S/clZGoxLdDqs93kTvy3qhpPqET/laY=",
"part_set_header": {
"total": 1,
"hash": "ai2qCLgVZAFph4FJ4Cqw5QW1GZKR4zjOv0bI/Um5AIc="
}
},
"timestamp": "2023-11-20T12:57:54.565207Z",
"validator_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",
"signature": "y9yILm9hmv45BZwAaaq9mS1FpH7QeAIJ5Jkcc3U2/k5uks9cuqr4NTIwaIrqMSMKwxVyqiR56xmCT59a6AngAA=="
},
"vote_b": {
"type": 1,
"height": 25,
"round": 0,
"block_id": {
"hash": "3P06pszgPatuIdLTP5fDWiase4SYHIq9YXGSbRk9/50=",
"part_set_header": {
"total": 1,
"hash": "S+SbOMxFRzfeNNpX9/jyFMz94VwBKk7Dpx6ZyvSYyNU="
}
},
"timestamp": "2023-11-20T12:57:54.599273Z",
"validator_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",
"validator_index": 0,
"signature": "DGFcn4Um1t2kXW60+JhMk5cj7ZFdE5goKVOGiZkLwnNv43+6aGmOWjoq0SHYVzM4MwSwOwbhgZNbkWX+EHGUBw=="
},
"total_voting_power": 300,
"validator_power": 100,
"timestamp": "2023-11-20T12:57:51.267308Z"
}
+
Example of infraction_header.json
{
"signed_header": {
"header": {
"version": {
"block": 11,
"app": 2
},
"chain_id": "consumer",
"height": 22,
"time": "2023-11-20T12:57:40.479686Z",
"last_block_id": {
"hash": "L63hyLJ+y9+fpb7WYKdmmBhPHwbfEGQEuKmvGzyBPiY=",
"part_set_header": {
"total": 18,
"hash": "euzRQjN7MjGtM6skXM4B8wOgAldWGfZSJRA9JRlO42s="
}
},
"last_commit_hash": "qdDJwVziW3pPqmf8QDGZG+5HVd3OF7fCVh2Z8KQqNVU=",
"data_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"validators_hash": "pVc+gSYkGesaP3OkK4ig3DBi4o9/GCdXGtO/PQ6i/Ik=",
"next_validators_hash": "pVc+gSYkGesaP3OkK4ig3DBi4o9/GCdXGtO/PQ6i/Ik=",
"consensus_hash": "BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8=",
"app_hash": "Yu3HX62w7orbbY/pm2QEK7yIwR+AlNdjSSqiK1kmuJM=",
"last_results_hash": "Yu3HX62w7orbbY/pm2QEK7yIwR+AlNdjSSqiK1kmuJM=",
"evidence_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"proposer_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA="
},
"commit": {
"height": 22,
"round": 1,
"block_id": {
"hash": "PKrS32IEZoFY2q2S3iQ68HQL751ieBhf5Eu/Y5Z/QPg=",
"part_set_header": {
"total": 1,
"hash": "8UuA7Oqw5AH/KOacpmHVSMOIDe4l2eC8VmdH2mzcpiM="
}
},
"signatures": [
{
"block_id_flag": 2,
"validator_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",
"timestamp": "2023-11-20T12:57:44.076538Z",
"signature": "bSOH4+Vg2I37zeJphOguGOD0GK3JzM1ghSgJd0UlW/DHn1u9Hvv4EekHuCu6qwRLZcuS/ZxNlmr9qYNfxX3bDA=="
},
{
"block_id_flag": 2,
"validator_address": "i/A830FM7cfmA8yTn9n3xBg5XpU=",
"timestamp": "2020-01-02T00:07:00Z",
"signature": "7bXSDtlOwGK/gLEsFpTWOzm2TFoaARrWQUpbgWEwKtLlUs7iE06TOvJ3yPPfTfqqN/qYnvxxgjl0M0EhUWu5Bg=="
},
{
"block_id_flag": 2,
"validator_address": "lrQDkJ2fk7UAgNzRZfcwMKSYa2E=",
"timestamp": "2023-11-20T12:57:44.076519Z",
"signature": "Pb6G4bCg4wafmV89WNnzXxbSCknZUHnSQfSCE5QMFxPtSUIN4A7SK5m7yltqMJF5zkyenlFiEI4J3OZ4KCjCAw=="
},
{
"block_id_flag": 2,
"validator_address": "+R94nXSeM1Z49e/CXpyHT3M+h3k=",
"timestamp": "2023-11-20T12:57:44.057451Z",
"signature": "j3EasIHNYA6MxW/PiWyruzHsjVsBV9t11W6Qx800WMm/+P+CkfR+UZAp7MPTvKZEZFuh3GUsBtyfb/vA+jJWCw=="
}
]
}
},
"validator_set": {
"validators": [
{
"address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",
"pub_key": {
"ed25519": "dtn+SfD+4QLo0+t0hAoP6Q2sGjh0XEI3LWVG+doh3u0="
},
"voting_power": 100,
"proposer_priority": -200
},
{
"address": "lrQDkJ2fk7UAgNzRZfcwMKSYa2E=",
"pub_key": {
"ed25519": "UgN2JsjPy2WLh7dzJRBkUQtdgNoT4/uGj7kbIVqqHT8="
},
"voting_power": 100,
"proposer_priority": 100
},
{
"address": "+R94nXSeM1Z49e/CXpyHT3M+h3k=",
"pub_key": {
"ed25519": "5svW8261x+cZosp2xIhqzgt2tyuawrSDyHlpbgS3BC4="
},
"voting_power": 100,
"proposer_priority": 100
},
{
"address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",
"pub_key": {
"ed25519": "dtn+SfD+4QLo0+t0hAoP6Q2sGjh0XEI3LWVG+doh3u0="
},
"voting_power": 100,
"proposer_priority": -200
}
],
"proposer": {
"address": "VUz+QceJ8Nu7GbJuVItwsfVjybA=",
"pub_key": {
"ed25519": "0s8KDTgEcwmOBrHWvV7mtBlItJ3upgM1FJsciwREdy4="
},
"voting_power": 1,
"proposer_priority": -3
}
},
"trusted_height": {
"revision_height": 18
},
"trusted_validators": {
"validators": [
{
"address": "VUz+QceJ8Nu7GbJuVItwsfVjybA=",
"pub_key": {
"ed25519": "0s8KDTgEcwmOBrHWvV7mtBlItJ3upgM1FJsciwREdy4="
},
"voting_power": 1,
"proposer_priority": -3
},
{
"address": "i/A830FM7cfmA8yTn9n3xBg5XpU=",
"pub_key": {
"ed25519": "FCmIw7hSuiAoWk/2f4LuGQ+3zx5101xiqU8DoC5wGkg="
},
"voting_power": 1,
"proposer_priority": 1
},
{
"address": "2DrZF0roNnnvEy4NS2aY811ncKg=",
"pub_key": {
"ed25519": "MI9c6sphsWlx0RAHCYOjMRXMFkTUaEYwOiOKG/0tsMs="
},
"voting_power": 1,
"proposer_priority": 1
},
{
"address": "73aN0uOc5b/Zfq2Xcjl0kH2r+tw=",
"pub_key": {
"ed25519": "gWNcDup4mdnsuqET4QeFRzVb+FnSP4Vz3iNMj5wvWXk="
},
"voting_power": 1,
"proposer_priority": 1
}
],
"proposer": {
"address": "VUz+QceJ8Nu7GbJuVItwsfVjybA=",
"pub_key": {
"ed25519": "0s8KDTgEcwmOBrHWvV7mtBlItJ3upgM1FJsciwREdy4="
},
"voting_power": 1,
"proposer_priority": -3
}
}
}
+

Use the following command to submit evidence of light client attacks:

+
gaiad tx provider submit-consumer-misbehaviour [path/to/misbehaviour.json] --from node0 --home ../node0 --chain-id $CID
+
Example of misbehaviour.json
{
"client_id": "07-tendermint-0",
"header_1": {
"signed_header": {
"header": {
"version": {
"block": "11",
"app": "2"
},
"chain_id": "testchain2",
"height": "19",
"time": "2020-01-02T00:08:10Z",
"last_block_id": {
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"part_set_header": {
"total": 10000,
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
}
},
"last_commit_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",
"data_hash": "bW4ouLmLUycELqUKV91G5syFHHLlKL3qpu/e7v5moLg=",
"validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",
"next_validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",
"consensus_hash": "5eVmxB7Vfj/4zBDxhBeHiLj6pgKwfPH0JSF72BefHyQ=",
"app_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",
"last_results_hash": "CS4FhjAkftYAmGOhLu4RfSbNnQi1rcqrN/KrNdtHWjc=",
"evidence_hash": "c4ZdsI9J1YQokF04mrTKS5bkWjIGx6adQ6Xcc3LmBxQ=",
"proposer_address": "CbKqPquy50bcrY7JRdW7zXybSuA="
},
"commit": {
"height": "19",
"round": 1,
"block_id": {
"hash": "W2xVqzPw03ZQ1kAMpcpht9WohwMzsGnyKKNjPYKDF6U=",
"part_set_header": {
"total": 3,
"hash": "hwgKOc/jNqZj6lwNm97vSTq9wYt8Pj4MjmYTVMGDFDI="
}
},
"signatures": [
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"timestamp": "2020-01-02T00:08:10Z",
"signature": "PGTquCtnTNFFY5HfEFz9f9pA7PYqjtQfBwHq6cxF/Ux8OI6nVqyadD9a84Xm7fSm6mqdW+T6YVfqIKmIoRjJDQ=="
},
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",
"timestamp": "2020-01-02T00:08:10Z",
"signature": "0e39yoBorwORAH/K9qJ7D1N1Yr7CutMiQJ+oiIK39eMhuoK3UWzQyMGRLzDOIDupf8yD99mvGVVAlNIODlV3Dg=="
},
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",
"timestamp": "2020-01-02T00:08:10Z",
"signature": "lhc2tkwydag9D1iLQhdDCE8GgrHP94M1LbHFYMoL9tExaEq6RiFW/k71TQH5x96XQ9XYOznMIHKC2BDh4GlnAQ=="
},
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",
"timestamp": "2020-01-02T00:08:10Z",
"signature": "8xeSBf0nSFs/X/rQ9CZLzwkJJhQBLA2jKdPGP3MlULxm992XxrOsIYq47u1daxvSsn6ql5OVYjzBNU0qbPpvCA=="
}
]
}
},
"validator_set": {
"validators": [
{
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
{
"address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",
"pub_key": {
"ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",
"pub_key": {
"ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",
"pub_key": {
"ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="
},
"voting_power": "1",
"proposer_priority": "1"
}
],
"proposer": {
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
"total_voting_power": "0"
},
"trusted_height": {
"revision_number": "0",
"revision_height": "18"
},
"trusted_validators": {
"validators": [
{
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
{
"address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",
"pub_key": {
"ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",
"pub_key": {
"ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",
"pub_key": {
"ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="
},
"voting_power": "1",
"proposer_priority": "1"
}
],
"proposer": {
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
"total_voting_power": "0"
}
},
"header_2": {
"signed_header": {
"header": {
"version": {
"block": "11",
"app": "2"
},
"chain_id": "testchain2",
"height": "19",
"time": "2020-01-02T00:08:20Z",
"last_block_id": {
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"part_set_header": {
"total": 10000,
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
}
},
"last_commit_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",
"data_hash": "bW4ouLmLUycELqUKV91G5syFHHLlKL3qpu/e7v5moLg=",
"validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",
"next_validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",
"consensus_hash": "5eVmxB7Vfj/4zBDxhBeHiLj6pgKwfPH0JSF72BefHyQ=",
"app_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",
"last_results_hash": "CS4FhjAkftYAmGOhLu4RfSbNnQi1rcqrN/KrNdtHWjc=",
"evidence_hash": "c4ZdsI9J1YQokF04mrTKS5bkWjIGx6adQ6Xcc3LmBxQ=",
"proposer_address": "CbKqPquy50bcrY7JRdW7zXybSuA="
},
"commit": {
"height": "19",
"round": 1,
"block_id": {
"hash": "IZM8NKS+8FHB7CBmgB8Nz7BRVVXiiyqMQDvHFUvgzxo=",
"part_set_header": {
"total": 3,
"hash": "hwgKOc/jNqZj6lwNm97vSTq9wYt8Pj4MjmYTVMGDFDI="
}
},
"signatures": [
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"timestamp": "2020-01-02T00:08:20Z",
"signature": "pLIEZ4WSAtnMsgryujheHSq4+YG3RqTfMn2ZxgEymr0wyi+BNlQAKRtRfesm0vfYxvjzc/jhGqtUqHtSIaCwCQ=="
},
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",
"timestamp": "2020-01-02T00:08:20Z",
"signature": "XG7iTe/spWyTUkT7XDzfLMpYqrdyqizE4/X4wl/W+1eaQp0WsCHYnvPU3x9NAnYfZzaKdonZiDWs7wacbZTcDg=="
},
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",
"timestamp": "2020-01-02T00:08:20Z",
"signature": "TqegK7ORuICSy++wVdPHt8fL2WfPlYsMPv1XW79wUdcjnQkezOM50OSqYaP4ua5frIZsn+sWteDrlqFTdkl3BA=="
},
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",
"timestamp": "2020-01-02T00:08:20Z",
"signature": "dhvp3XlIaCxx5MFDs0TCkAPHSm0PS2EtJzYAx2c/7MWdLwUJFZrAUTeimQE2c9i9ro91cjZn/vI0/oFRXab6Aw=="
}
]
}
},
"validator_set": {
"validators": [
{
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
{
"address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",
"pub_key": {
"ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",
"pub_key": {
"ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",
"pub_key": {
"ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="
},
"voting_power": "1",
"proposer_priority": "1"
}
],
"proposer": {
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
"total_voting_power": "0"
},
"trusted_height": {
"revision_number": "0",
"revision_height": "18"
},
"trusted_validators": {
"validators": [
{
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
{
"address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",
"pub_key": {
"ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",
"pub_key": {
"ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",
"pub_key": {
"ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="
},
"voting_power": "1",
"proposer_priority": "1"
}
],
"proposer": {
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
"total_voting_power": "0"
}
}
}
+

Report equivocation infractions with Hermes

+

Ensure you have a well-configured Hermes v1.7.3+ relayer effectively relaying packets between a consumer chain and a provider chain. +The following command demonstrates how to run a Hermes instance in evidence mode to detect misbehaviors on a consumer chain and automatically submit the evidence to the provider chain.

+
hermes evidence --chain <CONSUMER-CHAIN-ID>
+
tip

hermes evidence takes a --check-past-blocks option giving the possibility to look for older evidence (default is 100).

+ + \ No newline at end of file diff --git a/features/slashing.html.html b/features/slashing.html.html new file mode 100644 index 0000000000..9987002e1f --- /dev/null +++ b/features/slashing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/fonts/inter/Inter-Black.woff b/fonts/inter/Inter-Black.woff new file mode 100644 index 0000000000..a18593a096 Binary files /dev/null and b/fonts/inter/Inter-Black.woff differ diff --git a/fonts/inter/Inter-Black.woff2 b/fonts/inter/Inter-Black.woff2 new file mode 100644 index 0000000000..68f64c9ed9 Binary files /dev/null and b/fonts/inter/Inter-Black.woff2 differ diff --git a/fonts/inter/Inter-BlackItalic.woff b/fonts/inter/Inter-BlackItalic.woff new file mode 100644 index 0000000000..b6b01943d9 Binary files /dev/null and b/fonts/inter/Inter-BlackItalic.woff differ diff --git a/fonts/inter/Inter-BlackItalic.woff2 b/fonts/inter/Inter-BlackItalic.woff2 new file mode 100644 index 0000000000..1c9c7ca8b0 Binary files /dev/null and b/fonts/inter/Inter-BlackItalic.woff2 differ diff --git a/fonts/inter/Inter-Bold.woff b/fonts/inter/Inter-Bold.woff new file mode 100644 index 0000000000..eaf3d4bfd7 Binary files /dev/null and b/fonts/inter/Inter-Bold.woff differ diff --git a/fonts/inter/Inter-Bold.woff2 b/fonts/inter/Inter-Bold.woff2 new file mode 100644 index 0000000000..2846f29cc8 Binary files /dev/null and b/fonts/inter/Inter-Bold.woff2 differ diff --git a/fonts/inter/Inter-BoldItalic.woff b/fonts/inter/Inter-BoldItalic.woff new file mode 100644 index 0000000000..3275076164 Binary files /dev/null and b/fonts/inter/Inter-BoldItalic.woff differ diff --git a/fonts/inter/Inter-BoldItalic.woff2 b/fonts/inter/Inter-BoldItalic.woff2 new file mode 100644 index 0000000000..0b1fe8e125 Binary files /dev/null and b/fonts/inter/Inter-BoldItalic.woff2 differ diff --git a/fonts/inter/Inter-ExtraBold.woff b/fonts/inter/Inter-ExtraBold.woff new file mode 100644 index 0000000000..c2c17edead Binary files /dev/null and b/fonts/inter/Inter-ExtraBold.woff differ diff --git a/fonts/inter/Inter-ExtraBold.woff2 b/fonts/inter/Inter-ExtraBold.woff2 new file mode 100644 index 0000000000..c24c2bdc2f Binary files /dev/null and b/fonts/inter/Inter-ExtraBold.woff2 differ diff --git a/fonts/inter/Inter-ExtraBoldItalic.woff b/fonts/inter/Inter-ExtraBoldItalic.woff new file mode 100644 index 0000000000..c42f70526c Binary files /dev/null and b/fonts/inter/Inter-ExtraBoldItalic.woff differ diff --git a/fonts/inter/Inter-ExtraBoldItalic.woff2 b/fonts/inter/Inter-ExtraBoldItalic.woff2 new file mode 100644 index 0000000000..4a81dc7982 Binary files /dev/null and b/fonts/inter/Inter-ExtraBoldItalic.woff2 differ diff --git a/fonts/inter/Inter-ExtraLight.woff b/fonts/inter/Inter-ExtraLight.woff new file mode 100644 index 0000000000..d0de5f3973 Binary files /dev/null and b/fonts/inter/Inter-ExtraLight.woff differ diff --git a/fonts/inter/Inter-ExtraLight.woff2 b/fonts/inter/Inter-ExtraLight.woff2 new file mode 100644 index 0000000000..f2ea706faf Binary files /dev/null and b/fonts/inter/Inter-ExtraLight.woff2 differ diff --git a/fonts/inter/Inter-ExtraLightItalic.woff b/fonts/inter/Inter-ExtraLightItalic.woff new file mode 100644 index 0000000000..81f1a28ef5 Binary files /dev/null and b/fonts/inter/Inter-ExtraLightItalic.woff differ diff --git a/fonts/inter/Inter-ExtraLightItalic.woff2 b/fonts/inter/Inter-ExtraLightItalic.woff2 new file mode 100644 index 0000000000..9af717ba91 Binary files /dev/null and b/fonts/inter/Inter-ExtraLightItalic.woff2 differ diff --git a/fonts/inter/Inter-Italic.woff b/fonts/inter/Inter-Italic.woff new file mode 100644 index 0000000000..a806b38201 Binary files /dev/null and b/fonts/inter/Inter-Italic.woff differ diff --git a/fonts/inter/Inter-Italic.woff2 b/fonts/inter/Inter-Italic.woff2 new file mode 100644 index 0000000000..a619fc5486 Binary files /dev/null and b/fonts/inter/Inter-Italic.woff2 differ diff --git a/fonts/inter/Inter-Light.woff b/fonts/inter/Inter-Light.woff new file mode 100644 index 0000000000..c496464d02 Binary files /dev/null and b/fonts/inter/Inter-Light.woff differ diff --git a/fonts/inter/Inter-Light.woff2 b/fonts/inter/Inter-Light.woff2 new file mode 100644 index 0000000000..bc4be6658b Binary files /dev/null and b/fonts/inter/Inter-Light.woff2 differ diff --git a/fonts/inter/Inter-LightItalic.woff b/fonts/inter/Inter-LightItalic.woff new file mode 100644 index 0000000000..f84a9de35e Binary files /dev/null and b/fonts/inter/Inter-LightItalic.woff differ diff --git a/fonts/inter/Inter-LightItalic.woff2 b/fonts/inter/Inter-LightItalic.woff2 new file mode 100644 index 0000000000..842b2dfcb7 Binary files /dev/null and b/fonts/inter/Inter-LightItalic.woff2 differ diff --git a/fonts/inter/Inter-Medium.woff b/fonts/inter/Inter-Medium.woff new file mode 100644 index 0000000000..d546843f28 Binary files /dev/null and b/fonts/inter/Inter-Medium.woff differ diff --git a/fonts/inter/Inter-Medium.woff2 b/fonts/inter/Inter-Medium.woff2 new file mode 100644 index 0000000000..f92498a2ec Binary files /dev/null and b/fonts/inter/Inter-Medium.woff2 differ diff --git a/fonts/inter/Inter-MediumItalic.woff b/fonts/inter/Inter-MediumItalic.woff new file mode 100644 index 0000000000..459a656889 Binary files /dev/null and b/fonts/inter/Inter-MediumItalic.woff differ diff --git a/fonts/inter/Inter-MediumItalic.woff2 b/fonts/inter/Inter-MediumItalic.woff2 new file mode 100644 index 0000000000..0e3019f4ae Binary files /dev/null and b/fonts/inter/Inter-MediumItalic.woff2 differ diff --git a/fonts/inter/Inter-Regular.woff b/fonts/inter/Inter-Regular.woff new file mode 100644 index 0000000000..62d3a61871 Binary files /dev/null and b/fonts/inter/Inter-Regular.woff differ diff --git a/fonts/inter/Inter-Regular.woff2 b/fonts/inter/Inter-Regular.woff2 new file mode 100644 index 0000000000..6c2b6893d5 Binary files /dev/null and b/fonts/inter/Inter-Regular.woff2 differ diff --git a/fonts/inter/Inter-SemiBold.woff b/fonts/inter/Inter-SemiBold.woff new file mode 100644 index 0000000000..a815f43a91 Binary files /dev/null and b/fonts/inter/Inter-SemiBold.woff differ diff --git a/fonts/inter/Inter-SemiBold.woff2 b/fonts/inter/Inter-SemiBold.woff2 new file mode 100644 index 0000000000..611e90c958 Binary files /dev/null and b/fonts/inter/Inter-SemiBold.woff2 differ diff --git a/fonts/inter/Inter-SemiBoldItalic.woff b/fonts/inter/Inter-SemiBoldItalic.woff new file mode 100644 index 0000000000..909e43a97d Binary files /dev/null and b/fonts/inter/Inter-SemiBoldItalic.woff differ diff --git a/fonts/inter/Inter-SemiBoldItalic.woff2 b/fonts/inter/Inter-SemiBoldItalic.woff2 new file mode 100644 index 0000000000..545685bd2c Binary files /dev/null and b/fonts/inter/Inter-SemiBoldItalic.woff2 differ diff --git a/fonts/inter/Inter-Thin.woff b/fonts/inter/Inter-Thin.woff new file mode 100644 index 0000000000..62bc58cd14 Binary files /dev/null and b/fonts/inter/Inter-Thin.woff differ diff --git a/fonts/inter/Inter-Thin.woff2 b/fonts/inter/Inter-Thin.woff2 new file mode 100644 index 0000000000..abbc3a5c96 Binary files /dev/null and b/fonts/inter/Inter-Thin.woff2 differ diff --git a/fonts/inter/Inter-ThinItalic.woff b/fonts/inter/Inter-ThinItalic.woff new file mode 100644 index 0000000000..700a7f069b Binary files /dev/null and b/fonts/inter/Inter-ThinItalic.woff differ diff --git a/fonts/inter/Inter-ThinItalic.woff2 b/fonts/inter/Inter-ThinItalic.woff2 new file mode 100644 index 0000000000..ab0b2002a3 Binary files /dev/null and b/fonts/inter/Inter-ThinItalic.woff2 differ diff --git a/fonts/inter/Inter-italic.var.woff2 b/fonts/inter/Inter-italic.var.woff2 new file mode 100644 index 0000000000..b826d5af84 Binary files /dev/null and b/fonts/inter/Inter-italic.var.woff2 differ diff --git a/fonts/inter/Inter-roman.var.woff2 b/fonts/inter/Inter-roman.var.woff2 new file mode 100644 index 0000000000..6a256a068f Binary files /dev/null and b/fonts/inter/Inter-roman.var.woff2 differ diff --git a/fonts/intervar/Inter.var.woff2 b/fonts/intervar/Inter.var.woff2 new file mode 100644 index 0000000000..365eedc50c Binary files /dev/null and b/fonts/intervar/Inter.var.woff2 differ diff --git a/fonts/jetbrainsmono/JetBrainsMono-Bold.woff2 b/fonts/jetbrainsmono/JetBrainsMono-Bold.woff2 new file mode 100644 index 0000000000..023512c051 Binary files /dev/null and b/fonts/jetbrainsmono/JetBrainsMono-Bold.woff2 differ diff --git a/fonts/jetbrainsmono/JetBrainsMono-BoldItalic.woff2 b/fonts/jetbrainsmono/JetBrainsMono-BoldItalic.woff2 new file mode 100644 index 0000000000..f3e87a35ab Binary files /dev/null and b/fonts/jetbrainsmono/JetBrainsMono-BoldItalic.woff2 differ diff --git a/fonts/jetbrainsmono/JetBrainsMono-ExtraBold.woff2 b/fonts/jetbrainsmono/JetBrainsMono-ExtraBold.woff2 new file mode 100644 index 0000000000..a8b78a9c17 Binary files /dev/null and b/fonts/jetbrainsmono/JetBrainsMono-ExtraBold.woff2 differ diff --git a/fonts/jetbrainsmono/JetBrainsMono-ExtraBoldItalic.woff2 b/fonts/jetbrainsmono/JetBrainsMono-ExtraBoldItalic.woff2 new file mode 100644 index 0000000000..b54a2d5beb Binary files /dev/null and b/fonts/jetbrainsmono/JetBrainsMono-ExtraBoldItalic.woff2 differ diff --git a/fonts/jetbrainsmono/JetBrainsMono-ExtraLight.woff2 b/fonts/jetbrainsmono/JetBrainsMono-ExtraLight.woff2 new file mode 100644 index 0000000000..edd6a68c06 Binary files /dev/null and b/fonts/jetbrainsmono/JetBrainsMono-ExtraLight.woff2 differ diff --git a/fonts/jetbrainsmono/JetBrainsMono-ExtraLightItalic.woff2 b/fonts/jetbrainsmono/JetBrainsMono-ExtraLightItalic.woff2 new file mode 100644 index 0000000000..2a02a18e64 Binary files /dev/null and b/fonts/jetbrainsmono/JetBrainsMono-ExtraLightItalic.woff2 differ diff --git a/fonts/jetbrainsmono/JetBrainsMono-Italic.woff2 b/fonts/jetbrainsmono/JetBrainsMono-Italic.woff2 new file mode 100644 index 0000000000..e8eeb4b8e8 Binary files /dev/null and b/fonts/jetbrainsmono/JetBrainsMono-Italic.woff2 differ diff --git a/fonts/jetbrainsmono/JetBrainsMono-Light.woff2 b/fonts/jetbrainsmono/JetBrainsMono-Light.woff2 new file mode 100644 index 0000000000..459bacf498 Binary files /dev/null and b/fonts/jetbrainsmono/JetBrainsMono-Light.woff2 differ diff --git a/fonts/jetbrainsmono/JetBrainsMono-LightItalic.woff2 b/fonts/jetbrainsmono/JetBrainsMono-LightItalic.woff2 new file mode 100644 index 0000000000..352f5d95a6 Binary files /dev/null and b/fonts/jetbrainsmono/JetBrainsMono-LightItalic.woff2 differ diff --git a/fonts/jetbrainsmono/JetBrainsMono-Medium.woff2 b/fonts/jetbrainsmono/JetBrainsMono-Medium.woff2 new file mode 100644 index 0000000000..484c9e6415 Binary files /dev/null and b/fonts/jetbrainsmono/JetBrainsMono-Medium.woff2 differ diff --git a/fonts/jetbrainsmono/JetBrainsMono-MediumItalic.woff2 b/fonts/jetbrainsmono/JetBrainsMono-MediumItalic.woff2 new file mode 100644 index 0000000000..e1279949e0 Binary files /dev/null and b/fonts/jetbrainsmono/JetBrainsMono-MediumItalic.woff2 differ diff --git a/fonts/jetbrainsmono/JetBrainsMono-Regular.woff2 b/fonts/jetbrainsmono/JetBrainsMono-Regular.woff2 new file mode 100644 index 0000000000..8c862e334d Binary files /dev/null and b/fonts/jetbrainsmono/JetBrainsMono-Regular.woff2 differ diff --git a/fonts/jetbrainsmono/JetBrainsMono-SemiBold.woff2 b/fonts/jetbrainsmono/JetBrainsMono-SemiBold.woff2 new file mode 100644 index 0000000000..fce8cd8053 Binary files /dev/null and b/fonts/jetbrainsmono/JetBrainsMono-SemiBold.woff2 differ diff --git a/fonts/jetbrainsmono/JetBrainsMono-SemiBoldItalic.woff2 b/fonts/jetbrainsmono/JetBrainsMono-SemiBoldItalic.woff2 new file mode 100644 index 0000000000..a14851f6bb Binary files /dev/null and b/fonts/jetbrainsmono/JetBrainsMono-SemiBoldItalic.woff2 differ diff --git a/fonts/jetbrainsmono/JetBrainsMono-Thin.woff2 b/fonts/jetbrainsmono/JetBrainsMono-Thin.woff2 new file mode 100644 index 0000000000..7c6127875f Binary files /dev/null and b/fonts/jetbrainsmono/JetBrainsMono-Thin.woff2 differ diff --git a/fonts/jetbrainsmono/JetBrainsMono-ThinItalic.woff2 b/fonts/jetbrainsmono/JetBrainsMono-ThinItalic.woff2 new file mode 100644 index 0000000000..0676ba8a56 Binary files /dev/null and b/fonts/jetbrainsmono/JetBrainsMono-ThinItalic.woff2 differ diff --git a/img/acceptance-tests.png b/img/acceptance-tests.png new file mode 100644 index 0000000000..b85d7da7d0 Binary files /dev/null and b/img/acceptance-tests.png differ diff --git a/img/android-chrome-192x192.png b/img/android-chrome-192x192.png new file mode 100644 index 0000000000..6d04cf4c08 Binary files /dev/null and b/img/android-chrome-192x192.png differ diff --git a/img/android-chrome-256x256.png b/img/android-chrome-256x256.png new file mode 100644 index 0000000000..1c30cc0267 Binary files /dev/null and b/img/android-chrome-256x256.png differ diff --git a/img/apple-touch-icon.png b/img/apple-touch-icon.png new file mode 100644 index 0000000000..397e21af2a Binary files /dev/null and b/img/apple-touch-icon.png differ diff --git a/img/banner.png b/img/banner.png new file mode 100644 index 0000000000..018b2886e7 Binary files /dev/null and b/img/banner.png differ diff --git a/img/docusaurus-social-card.jpg b/img/docusaurus-social-card.jpg new file mode 100644 index 0000000000..ffcb448210 Binary files /dev/null and b/img/docusaurus-social-card.jpg differ diff --git a/img/docusaurus.png b/img/docusaurus.png new file mode 100644 index 0000000000..f458149e3c Binary files /dev/null and b/img/docusaurus.png differ diff --git a/img/favicon-16x16.png b/img/favicon-16x16.png new file mode 100644 index 0000000000..5f15c3b0af Binary files /dev/null and b/img/favicon-16x16.png differ diff --git a/img/favicon-32x32.png b/img/favicon-32x32.png new file mode 100644 index 0000000000..9433c807fd Binary files /dev/null and b/img/favicon-32x32.png differ diff --git a/img/favicon-dark.svg b/img/favicon-dark.svg new file mode 100644 index 0000000000..a4f0fac959 --- /dev/null +++ b/img/favicon-dark.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/img/favicon.ico b/img/favicon.ico new file mode 100644 index 0000000000..c01d54bcd3 Binary files /dev/null and b/img/favicon.ico differ diff --git a/img/favicon.svg b/img/favicon.svg new file mode 100644 index 0000000000..dbefbad9f4 --- /dev/null +++ b/img/favicon.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/img/hub.svg b/img/hub.svg new file mode 100644 index 0000000000..46ace9e4ab --- /dev/null +++ b/img/hub.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/ico-chevron.svg b/img/ico-chevron.svg new file mode 100644 index 0000000000..3f8e8fac11 --- /dev/null +++ b/img/ico-chevron.svg @@ -0,0 +1,3 @@ + + + diff --git a/img/ico-github.svg b/img/ico-github.svg new file mode 100644 index 0000000000..a74bee5aed --- /dev/null +++ b/img/ico-github.svg @@ -0,0 +1,3 @@ + + + diff --git a/img/logo copy.svg b/img/logo copy.svg new file mode 100644 index 0000000000..95ca6d30da --- /dev/null +++ b/img/logo copy.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/img/logo-bw.svg b/img/logo-bw.svg new file mode 100644 index 0000000000..f2575260a7 --- /dev/null +++ b/img/logo-bw.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/img/logo-sdk.svg b/img/logo-sdk.svg new file mode 100644 index 0000000000..444eff2ab3 --- /dev/null +++ b/img/logo-sdk.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/img/logo.svg b/img/logo.svg new file mode 100644 index 0000000000..9db6d0d066 --- /dev/null +++ b/img/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/undraw_docusaurus_mountain.svg b/img/undraw_docusaurus_mountain.svg new file mode 100644 index 0000000000..af961c49a8 --- /dev/null +++ b/img/undraw_docusaurus_mountain.svg @@ -0,0 +1,171 @@ + + Easy to Use + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/undraw_docusaurus_react.svg b/img/undraw_docusaurus_react.svg new file mode 100644 index 0000000000..94b5cf08f8 --- /dev/null +++ b/img/undraw_docusaurus_react.svg @@ -0,0 +1,170 @@ + + Powered by React + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/undraw_docusaurus_tree.svg b/img/undraw_docusaurus_tree.svg new file mode 100644 index 0000000000..d9161d3392 --- /dev/null +++ b/img/undraw_docusaurus_tree.svg @@ -0,0 +1,40 @@ + + Focus on What Matters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/index.html b/index.html new file mode 100644 index 0000000000..088eef1de5 --- /dev/null +++ b/index.html @@ -0,0 +1,19 @@ + + + + + +Interchain Security Docs | Interchain Security + + + + +
+ + \ No newline at end of file diff --git a/introduction/overview.html b/introduction/overview.html new file mode 100644 index 0000000000..5856bee61a --- /dev/null +++ b/introduction/overview.html @@ -0,0 +1,33 @@ + + + + + +Overview | Interchain Security + + + + +
Version: main

Overview

+
info

Interchain Security is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.


Interchain Security allows anyone to launch a "consumer" blockchain using a subset, or even the entire, validator set from the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit security and decentralization from the provider.

+

Why Interchain Security?

+
    +
  • The right amount of security for each application. Consumer chains can choose to inherit the whole validator set from the provider, or they can launch as an opt in chain where only a subset of the provider validators validate the consumer chain. This allows for a wide range of security tradeoffs.
  • +
  • Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum.
  • +
  • Projects keep majority of gas fees. Depending on configuration, these fees either go to the project’s community DAO, or can be used in the protocol in other ways.
  • +
  • No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. Validators from the provider chain validate on the consumer chain with their stake on the provider chain, earning additional rewards. For the consumer chain, this comes with the benefit of exposing their chain to the wider audience of the provider chain.
  • +
  • Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set.
  • +
+

Core protocol

+
info

Protocol specification is available as ICS-028 in the IBC repository.

+

Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer.

+

To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider.

+

Downtime Slashing

+

If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period.

+

Tokenomics and Rewards

+

Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance.

+ + \ No newline at end of file diff --git a/introduction/overview.html.html b/introduction/overview.html.html new file mode 100644 index 0000000000..deb52828ef --- /dev/null +++ b/introduction/overview.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/introduction/params.html b/introduction/params.html new file mode 100644 index 0000000000..0e1567cd24 --- /dev/null +++ b/introduction/params.html @@ -0,0 +1,100 @@ + + + + + +Interchain Security Parameters | Interchain Security + + + + +
Version: main

Interchain Security Parameters

+

The parameters necessary for Interchain Security (ICS) are defined in

+
    +
  • the Params structure in proto/interchain_security/ccv/provider/v1/provider.proto for the provider;
  • +
  • the Params structure in proto/interchain_security/ccv/consumer/v1/consumer.proto for the consumer.
  • +
+

Time-Based Parameters

+

ICS relies on the following time-based parameters.

+

ProviderUnbondingPeriod

+

ProviderUnbondingPeriod is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance.

+

ConsumerUnbondingPeriod

+

ConsumerUnbondingPeriod is the unbonding period on the consumer chain.

+
info

ConsumerUnbondingPeriod is set via the ConsumerAdditionProposal governance proposal to add a new consumer chain. +It is recommended that every consumer chain set and unbonding period shorter than ProviderUnbondingPeriod


Example:

ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day
+

Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer.

+

TrustingPeriodFraction

+

TrustingPeriodFraction is used to calculate the TrustingPeriod of created IBC clients on both provider and consumer chains.

+

Setting TrustingPeriodFraction to 0.5 would result in the following:

+
TrustingPeriodFraction = 0.5
ProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5
ConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5
+

Note that a light clients must be updated within the TrustingPeriod in order to avoid being frozen.

+

For more details, see the IBC specification of Tendermint clients.

+

CCVTimeoutPeriod

+

CCVTimeoutPeriod is the period used to compute the timeout timestamp when sending IBC packets.

+

For more details, see the IBC specification of Channel & Packet Semantics.

+
warning

If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed.

+

CCVTimeoutPeriod may have different values on the provider and consumer chains.

+
    +
  • CCVTimeoutPeriod on the provider must be larger than ConsumerUnbondingPeriod
  • +
  • CCVTimeoutPeriod on the consumer is initial set via the ConsumerAdditionProposal
  • +
+

InitTimeoutPeriod

+

InitTimeoutPeriod is the maximum allowed duration for CCV channel initialization to execute.

+

For any consumer chain, if the CCV channel is not established within InitTimeoutPeriod then the consumer chain will be removed and therefore will not be secured by the provider chain.

+

The countdown starts when the spawn_time specified in the ConsumerAdditionProposal is reached.

+

VscTimeoutPeriod

+

VscTimeoutPeriod is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live. +If the VscTimeoutPeriod is ever reached for a consumer chain that chain will be considered not live and removed from interchain security.

+
tip

VscTimeoutPeriod MUST be larger than the ConsumerUnbondingPeriod.

+

BlocksPerDistributionTransmission

+

BlocksPerDistributionTransmission is the number of blocks between rewards transfers from the consumer to the provider.

+

TransferPeriodTimeout

+

TransferPeriodTimeout is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider.

+

If this timeout expires, then the transfer is attempted again after BlocksPerDistributionTransmission blocks.

+
    +
  • TransferPeriodTimeout on the consumer is initial set via the ConsumerAdditionProposal gov proposal to add the consumer
  • +
  • TransferPeriodTimeout should be smaller than BlocksPerDistributionTransmission x avg_block_time
  • +
+

Reward Distribution Parameters

+
tip

The following chain parameters dictate consumer chain distribution amount and frequency. +They are set at consumer genesis and BlocksPerDistributionTransmission, ConsumerRedistributionFraction +TransferTimeoutPeriod must be provided in every ConsumerChainAddition proposal.

+

ConsumerRedistributionFraction

+

ConsumerRedistributionFraction is the fraction of tokens allocated to the consumer redistribution address during distribution events. The fraction is a string representing a decimal number. For example "0.75" would represent 75%.

+
tip

Example:

With ConsumerRedistributionFraction set to "0.75" the consumer chain would send 75% of its block rewards and accumulated fees to the consumer redistribution address, and the remaining 25% to the provider chain every BlocksPerDistributionTransmission blocks.

+

BlocksPerDistributionTransmission

+

BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.

+

TransferTimeoutPeriod

+

TransferTimeoutPeriod is the timeout period for consumer chain reward distribution IBC packets.

+

DistributionTransmissionChannel

+

DistributionTransmissionChannel is the provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.

+

ProviderFeePoolAddrStr

+

ProviderFeePoolAddrStr is the provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.

+

Slash Throttle Parameters

+

SlashMeterReplenishPeriod

+

SlashMeterReplenishPeriod exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed.

+

The meter is replenished to an amount equal to the slash meter allowance for that block, or SlashMeterReplenishFraction * CurrentTotalVotingPower.

+

SlashMeterReplenishFraction

+

SlashMeterReplenishFraction exists on the provider as the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs.

+

This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a sdk.Dec when used.

+

MaxThrottledPackets

+

MaxThrottledPackets exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value.

+

This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness.

+
info

MaxThrottledPackets was deprecated in ICS versions >= v3.2.0 due to the implementation of ADR-008.

+

RetryDelayPeriod

+

RetryDelayPeriod exists on the consumer for ICS versions >= v3.2.0 (introduced by the implementation of ADR-008) and is the period at which the consumer retries to send a SlashPacket that was rejected by the provider.

+

Epoch Parameters

+

BlocksPerEpoch

+

BlocksPerEpoch exists on the provider for ICS versions >= 3.3.0 (introduced by the implementation of ADR-014) +and corresponds to the number of blocks that constitute an epoch. This param is set to 600 by default. Assuming we need 6 seconds to +commit a block, the duration of an epoch corresponds to 1 hour. This means that a VSCPacket would be sent to a consumer +chain once at the end of every epoch, so once every 600 blocks. This parameter can be adjusted via a governance proposal, +however careful consideration is needed so that BlocksPerEpoch is not too large. A large BlocksPerEpoch could lead to a delay +of VSCPackets and hence potentially lead to unbonding pausing. +For setting BlocksPerEpoch, we also need to consider potential slow chain upgrades that could delay the sending of a +VSCPacket, as well as potential increases in the time it takes to commit a block (e.g., from 6 seconds to 30 seconds).

+ + \ No newline at end of file diff --git a/introduction/params.html.html b/introduction/params.html.html new file mode 100644 index 0000000000..0b9ffecbbc --- /dev/null +++ b/introduction/params.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/introduction/technical-specification.html b/introduction/technical-specification.html new file mode 100644 index 0000000000..646866e11c --- /dev/null +++ b/introduction/technical-specification.html @@ -0,0 +1,17 @@ + + + + + +Technical Specification | Interchain Security + + + + +
Version: main

Technical Specification

+

For a technical deep dive into the replicated security protocol, see the specification.

+ + \ No newline at end of file diff --git a/introduction/technical-specification.html.html b/introduction/technical-specification.html.html new file mode 100644 index 0000000000..93bfa79d74 --- /dev/null +++ b/introduction/technical-specification.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/introduction/terminology.html b/introduction/terminology.html new file mode 100644 index 0000000000..ae0fde7553 --- /dev/null +++ b/introduction/terminology.html @@ -0,0 +1,35 @@ + + + + + +Terminology | Interchain Security + + + + +
Version: main

Terminology

+

You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.

+

Shared Security

+

Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share its proof-of-stake security with another blockchain or off-chain process.

+

Interchain Security

+

Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC.

+

Replicated Security

+

A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC.

+

Partial Set Security

+

A major iteration of Interchain Security, also known as "Interchain Security V2". Partial Set Security allows a provider chain to share only a subset of its validator set with a consumer chain. This subset can be determined by the top N% validators by voting power, or by validators opting in to validate the consumer chain. Partial Set Security allows for more flexible security tradeoffs than Replicated Security.

+

Mesh security

+

A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see Replicated vs. Mesh Security on the Informal Blog.

+

Consumer Chain

+

Chain that is secured by the validator set of the provider, instead of its own. +Interchain Security allows a subset of the provider chain's validator set to validate blocks on the consumer chain.

+

Standalone Chain

+

Chain that is secured by its own validator set. This chain does not participate in Interchain Security.

+

Standalone chains may sometimes be called "sovereign" - the terms are synonymous.

+

Changeover Procedure

+

Chains that were not initially launched as consumers of Interchain Security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.

+ + \ No newline at end of file diff --git a/introduction/terminology.html.html b/introduction/terminology.html.html new file mode 100644 index 0000000000..425787c58c --- /dev/null +++ b/introduction/terminology.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/.nojekyll b/legacy/.nojekyll new file mode 100644 index 0000000000..e69de29bb2 diff --git a/legacy/404.html b/legacy/404.html new file mode 100644 index 0000000000..820d8e71cb --- /dev/null +++ b/legacy/404.html @@ -0,0 +1,19 @@ + + + + + +Page Not Found | Interchain Security + + + + +
+

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

+ + + + \ No newline at end of file diff --git a/legacy/404/index.html b/legacy/404/index.html new file mode 100644 index 0000000000..71d591abb0 --- /dev/null +++ b/legacy/404/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/adrs/adr-001-key-assignment.html b/legacy/adrs/adr-001-key-assignment.html new file mode 100644 index 0000000000..50a7ebd469 --- /dev/null +++ b/legacy/adrs/adr-001-key-assignment.html @@ -0,0 +1,19 @@ + + + + + +Key Assignment | Interchain Security + + + + +
+
Version: Next

ADR 001: Key Assignment

Changelog

  • 2022-12-01: Initial Draft

Status

Accepted

Context

KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate.

Decision

It is possible to change the keys at any time by submitting a transaction (i.e., MsgAssignConsumerKey).

State required

  • ValidatorConsumerPubKey - Stores the validator assigned keys for every consumer chain.
ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey
  • ValidatorByConsumerAddr - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol.
ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress
  • KeyAssignmentReplacements - Stores the key assignments that need to be replaced in the current block. Needed to apply the key assignments received in a block to the validator updates sent to the consumer chains.
KeyAssignmentReplacementsBytePrefix | len(chainID) | chainID | providerConsAddress -> abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower},
  • ConsumerAddrsToPrune - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ValidatorByConsumerAddr.
ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses

Protocol overview

On receiving a MsgAssignConsumerKey(chainID, providerAddr, consumerKey) message:

// get validator from staking module  
validator, found := stakingKeeper.GetValidator(providerAddr)
if !found {
return ErrNoValidatorFound
}
providerConsAddr := validator.GetConsAddr()

// make sure consumer key is not in use
consumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)
if _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {
return ErrInvalidConsumerConsensusPubKey
}

// check whether the consumer chain is already registered
// i.e., a client to the consumer was already created
if _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {
// get the previous key assigned for this validator on this consumer chain
oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)
if found {
// mark this old consumer key as prunable once the VSCMaturedPacket
// for the current VSC ID is received
oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)
vscID := GetValidatorSetUpdateId()
AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)
} else {
// the validator had no key assigned on this consumer chain
oldConsumerKey := validator.TmConsPublicKey()
}

// check whether the validator is valid, i.e., its power is positive
if currentPower := stakingKeeper.GetLastValidatorPower(providerAddr); currentPower > 0 {
// to enable multiple calls of AssignConsumerKey in the same block by the same validator
// the key assignment replacement should not be overwritten
if _, found := GetKeyAssignmentReplacement(chainID, providerConsAddr); !found {
// store old key and power for modifying the valset update in EndBlock
oldKeyAssignment := abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower}
SetKeyAssignmentReplacement(chainID, providerConsAddr, oldKeyAssignment)
}
}
} else {
// if the consumer chain is not registered, then remove the previous reverse mapping
if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {
oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)
DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)
}
}


// set the mapping from this validator's provider address to the new consumer key
SetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)

// set the reverse mapping: from this validator's new consensus address
// on the consumer to its consensus address on the provider
SetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)

When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see MakeConsumerGenesis).

func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {
// ...
// get initial valset from the staking module
var updates []abci.ValidatorUpdate{}
stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {
validator := stakingKeeper.GetValidator(providerAddr)
providerKey := validator.TmConsPublicKey()
updates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})
return false
})

// applies the key assignment to the initial validator
for i, update := range updates {
providerAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)
if consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {
updates[i].PubKey = consumerKey
}
}
gen.InitialValSet = updates

// get a hash of the consumer validator set from the update
updatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)
hash := tendermint.NewValidatorSet(updatesAsValSet).Hash()

return gen, hash, nil
}

On EndBlock while queueing VSCPackets to send to registered consumer chains:

func QueueVSCPackets() {
valUpdateID := GetValidatorSetUpdateId()
// get the validator updates from the staking module
valUpdates := stakingKeeper.GetValidatorUpdates()

IterateConsumerChains(func(chainID, clientID string) (stop bool) {
// apply the key assignment to the validator updates
valUpdates := ApplyKeyAssignmentToValUpdates(chainID, valUpdates)
// ..
})
// ...
}

func ApplyKeyAssignmentToValUpdates(
chainID string,
valUpdates []abci.ValidatorUpdate,
) (newUpdates []abci.ValidatorUpdate) {
for _, valUpdate := range valUpdates {
providerAddr := utils.TMCryptoPublicKeyToConsAddr(valUpdate.PubKey)

// if a key assignment replacement is found, then
// remove the valupdate with the old consumer key
// and create two new valupdates
prevConsumerKey, _, found := GetKeyAssignmentReplacement(chainID, providerAddr)
if found {
// set the old consumer key's power to 0
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: prevConsumerKey,
Power: 0,
})
// set the new consumer key's power to the power in the update
newConsumerKey := GetValidatorConsumerPubKey(chainID, providerAddr)
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: newConsumerKey,
Power: valUpdate.Power,
})
// delete key assignment replacement
DeleteKeyAssignmentReplacement(chainID, providerAddr)
} else {
// there is no key assignment replacement;
// check if the validator's key is assigned
consumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr)
if found {
// replace the update containing the provider key
// with an update containing the consumer key
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: consumerKey,
Power: valUpdate.Power,
})
} else {
// keep the same update
newUpdates = append(newUpdates, valUpdate)
}
}
}

// iterate over the remaining key assignment replacements
IterateKeyAssignmentReplacements(chainID, func(
pAddr sdk.ConsAddress,
prevCKey tmprotocrypto.PublicKey,
power int64,
) (stop bool) {
// set the old consumer key's power to 0
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: prevCKey,
Power: 0,
})
// set the new consumer key's power to the power in key assignment replacement
newConsumerKey := GetValidatorConsumerPubKey(chainID, pAddr)
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: newConsumerKey,
Power: power,
})
return false
})

// remove all the key assignment replacements

return newUpdates
}

On receiving a SlashPacket from a consumer chain with id chainID for a infraction of a validator data.Validator:

func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {
// ...
// the slash packet validator address may be known only on the consumer chain;
// in this case, it must be mapped back to the consensus address on the provider chain
consumerAddr := sdk.ConsAddress(data.Validator.Address)
providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)
if !found {
// the validator has the same key on the consumer as on the provider
providerAddr = consumer
}
// ...
}

On receiving a VSCMatured:

func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {
// ...
// prune previous consumer validator address that are no longer needed
consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)
for _, addr := range consumerAddrs {
DeleteValidatorByConsumerAddr(chainID, addr)
}
DeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)
// ...
}

On stopping a consumer chain:

func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {
// ...
// deletes all the state needed for key assignments on this consumer chain
// ...
}

Consequences

Positive

  • Validators can use different consensus keys on the consumer chains.

Negative

  • None

Neutral

  • The consensus state necessary to create a client to the consumer chain must use the hash returned by the MakeConsumerGenesis method as the nextValsHash.
  • The consumer chain can no longer check the initial validator set against the consensus state on InitGenesis.

References

+ + + + \ No newline at end of file diff --git a/legacy/adrs/adr-001-key-assignment.html.html b/legacy/adrs/adr-001-key-assignment.html.html new file mode 100644 index 0000000000..cb11627c66 --- /dev/null +++ b/legacy/adrs/adr-001-key-assignment.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/adrs/adr-002-throttle.html b/legacy/adrs/adr-002-throttle.html new file mode 100644 index 0000000000..790848e1b7 --- /dev/null +++ b/legacy/adrs/adr-002-throttle.html @@ -0,0 +1,19 @@ + + + + + +Jail Throttling | Interchain Security + + + + +
+
Version: Next

ADR 002: Jail Throttling

Changelog

  • 2023-01-26: Initial Draft
  • 2023-02-07: Property refined, ADR ready to review/merge

Status

Accepted

Context

The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols. In practice, this assumption may not hold. A malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider.

Before the throttling feature was implemented, the following attack was possible. Attacker(s) would create provider validators just below the provider's active set. Using a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once. Control of the provider would then pass over to the attackers' validators. This enables the attacker(s) to halt the provider. Or even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC.

Decision

The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack. Ie. this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time.

State Required - Slash Meter

There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time. This meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params.

State Required - Global entry queue

There exists a single queue which stores "global slash entries". These entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering. This queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.

State Required - Per-chain data queue

For each established consumer, there exists a queue which stores "throttled packet data". Ie. pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering. Order is enforced by IBC sequence number. These "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.

Reasoning - Multiple queues

For reasoning on why this feature was implemented with multiple queues, see spec. Specifically the section on VSC Maturity and Slashing Order. There are other ways to ensure such a property (like a queue of linked lists, etc.), but the implemented protocol seemed to be the most understandable and easiest to implement with a KV store.

Protocol Overview - OnRecvSlashPacket

Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:

  1. A global slash entry is queued.
  2. The data of such a packet is added to the per-chain queue.

Protocol Overview - OnRecvVSCMaturedPacket

Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue.

Endblocker Step 1 - Slash Meter Replenishment

Once the slash meter becomes not full, it'll be replenished after SlashMeterReplenishPeriod (param) by incrementing the meter with its allowance for the replenishment block, where allowance = SlashMeterReplenishFraction (param) * currentTotalVotingPower. The slash meter will never exceed its current allowance (fn of the total voting power for the block) in value. Note a few things:

  1. The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power. In such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods.
  2. Total voting power of a chain changes over time, especially as validators are jailed. As validators are jailed, total voting power decreases, and so does the jailing allowance. See below for more detailed throttling property discussion.
  3. The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1. If the SlashMeterReplenishFraction (param) is set too low, integer rounding will put this minimum value into effect. That is, if SlashMeterReplenishFraction * currentTotalVotingPower < 1, then the effective allowance would be 1. This min value of allowance ensures that there's some packets handled over time, even if that is a very long time. It's a crude solution to an edge case caused by too small of a replenishment fraction.

The behavior described above is achieved by executing CheckForSlashMeterReplenishment() every endblock, BEFORE HandleThrottleQueues() is executed.

Endblocker Step 2 - HandleLeadingVSCMaturedPackets

Every block it is possible that VSCMatured packet data was queued before any slash packet data. Since this "leading" VSCMatured packet data does not have to be throttled (see VSC Maturity and Slashing Order), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes.

Endblocker Step 3 - HandleThrottleQueues

Every endblocker the following pseudo-code is executed to handle data from the throttle queues.

meter := getSlashMeter()

// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist
while meter.IsPositiveOrZero() && entriesExist() {
// Get next entry in queue
entry := getNextGlobalSlashEntry()
// Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet
valPower := entry.getValPower()
meter = meter - valPower
// Using the per-chain queue, handle the single slash packet using its queued data,
// then handle all trailing VSCMatured packets for this consumer
handleSlashPacketAndTrailingVSCMaturedPackets(entry)
// Delete entry in global queue, delete handled data
entry.Delete()
deleteThrottledSlashPacketData()
deleteTrailingVSCMaturedPacketData()
}

System Properties

All CCV system properties should be maintained by implementing this feature, see: CCV spec - Consumer Initiated Slashing.

One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than MaxThrottledPackets (param), then the provider binary will panic, and the provider chain will halt. Therefore this param should be set carefully. See SetThrottledPacketDataSize. This behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators.

Main Throttling Property

Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions.

First, we define the following:

  • A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.
  • The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.
  • There is a list of honest validators s.t if they are jailed, X% of the initial validator set will be jailed.

For the following property to hold, these assumptions must be true:

  1. We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack.
  2. No validator has more than SlashMeterReplenishFraction of total voting power on the provider.
  3. SlashMeterReplenishFraction is large enough that SlashMeterReplenishFraction * currentTotalVotingPower > 1. Ie. the replenish fraction is set high enough that we can ignore the effects of rounding.
  4. SlashMeterReplenishPeriod is sufficiently longer than the time it takes to produce a block.

Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined.

Property:

The time it takes to jail/tombstone X% of the initial validator set will be greater than or equal to (X * SlashMeterReplenishPeriod / SlashMeterReplenishFraction) - 2 * SlashMeterReplenishPeriod

Intuition:

Let's use the following notation:

  • $C$: Number of replenishment cycles
  • $P$: $\text{SlashMeterReplenishPeriod}$
  • $F$: $\text{SlashMeterReplenishFraction}$
  • $V_{\mathit{max}}$: Max power of a validator as a fraction of total voting power

In $C$ number of replenishment cycles, the fraction of total voting power that can be removed, $a$, is $a \leq F \cdot C + V{\mathit{max}}$ (where $V{\mathit{max}}$ is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value).

So, we need at least $C \geq \frac{a - V_{\mathit{max}}}{F}$ cycles to remove $a$ fraction of the total voting power.

Since we defined the start of the attack to be the moment when the first slash request arrives, then $F$ fraction of the initial validator set can be jailed immediately. For the remaining $X - F$ fraction of the initial validator set to be jailed, it takes at least $C \geq \frac{(X - F) - V{\mathit{max}}}{F}$ cycles. Using the assumption that $V{\mathit{max}} \leq F$ (assumption 2), we get $C \geq \frac{X - 2F}{F}$ cycles.

In order to execute $C$ cycles, we need $C \cdot P$ time.

Thus, jailing the remaining $X - F$ fraction of the initial validator set corresponds to $\frac{P \cdot (X - 2F)}{F}$ time.

In other words, the attack must take at least $\frac{P \cdot X}{F} - 2P$ time (in the units of replenish period $P$).

This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests. For example, if SlashMeterReplenishFraction is set to 0.06, then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub. Note that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power.

Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings.

How Unjailing Affects the Main Throttling Property

Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained.

If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider.

In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack.

Consequences

Positive

  • The described attack is slowed down in seemingly all cases.
  • If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded.

Negative

  • Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below. However, this is sacrificing liveness in a edge case scenario for the sake of security. As an improvement, using retries would fully prevent this attack vector.

Neutral

  • Additional state is introduced to the provider chain.
  • VSCMatured and slash packet data is not always handled in the same block that it is received.

References

+ + + + \ No newline at end of file diff --git a/legacy/adrs/adr-002-throttle.html.html b/legacy/adrs/adr-002-throttle.html.html new file mode 100644 index 0000000000..0451fb1519 --- /dev/null +++ b/legacy/adrs/adr-002-throttle.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/adrs/adr-003-equivocation-gov-proposal.html b/legacy/adrs/adr-003-equivocation-gov-proposal.html new file mode 100644 index 0000000000..ff5fc737b8 --- /dev/null +++ b/legacy/adrs/adr-003-equivocation-gov-proposal.html @@ -0,0 +1,19 @@ + + + + + +Equivocation governance proposal | Interchain Security + + + + +
+
Version: Next

ADR 003: Equivocation governance proposal

Changelog

  • 2023-02-06: Initial draft

Status

Accepted

Context

We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain.

For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence.

Decision

To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain.

A new kind of governance proposal is added to the provider module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain.

If such proposal passes, the proposal handler delegates to the evidence module to process the equivocation. This module ensures the evidence isn’t too old, or else ignores it (see code). Too old is determined by 2 consensus params :

  • evidence.max_age_duration number of nanoseconds before an evidence is considered too old
  • evidence.max_age_numblocks number of blocks before an evidence is considered too old.

On the hub, those parameters are equals to

// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682
(...)
"evidence": {
"max_age_num_blocks": "1000000",
"max_age_duration": "172800000000000",
(...)
},
(...)

A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the evidence module when the proposal passes and is handled by the hub.

For max_age_num_blocks=1M, the parameter is big enough if we consider the hub produces 12k blocks per day (blocks_per_year/365 = 436,0000/365). The evidence can be up to 83 days old (1,000,000/12,000) and not be ignored.

For max_age_duration=172,800,000,000,000, the parameter is too low, because the value is in nanoseconds so it’s 2 days. Fortunately the condition that checks those 2 parameters uses a AND, so if max_age_num_blocks condition passes, the evidence won’t be ignored.

Consequences

Positive

  • Remove the possibility from a malicious consumer chain to “attack” the provider chain by slashing/jailing validators.
  • Provide a more acceptable implementation for the validator community.

Negative

  • Punishment action of double-signing isn’t “automated”, a governance proposal is required which takes more time.
  • You need to pay 250ATOM to submit an equivocation evidence.

Neutral

References

+ + + + \ No newline at end of file diff --git a/legacy/adrs/adr-003-equivocation-gov-proposal.html.html b/legacy/adrs/adr-003-equivocation-gov-proposal.html.html new file mode 100644 index 0000000000..3002e7d6ef --- /dev/null +++ b/legacy/adrs/adr-003-equivocation-gov-proposal.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/adrs/adr-005-cryptographic-equivocation-verification.html b/legacy/adrs/adr-005-cryptographic-equivocation-verification.html new file mode 100644 index 0000000000..c41b4bc83e --- /dev/null +++ b/legacy/adrs/adr-005-cryptographic-equivocation-verification.html @@ -0,0 +1,85 @@ + + + + + +Cryptographic verification of equivocation evidence | Interchain Security + + + + +
+
Version: Next

ADR 005: Cryptographic verification of equivocation evidence

Changelog

  • 5/1/2023: First draft
  • 7/23/2023: Add light client attacks handling
  • 9/6/2023: Add double signing attacks handling

Status

Accepted

Context

Currently, we use a governance proposal to slash validators for equivocation (double signing and light client attacks). +Every proposal needs to go through a (two weeks) voting period before it can be approved. +Given a three-week unbonding period, this means that an equivocation proposal needs to be submitted within one week since the infraction occurred.

This ADR proposes a system to slash validators automatically for equivocation, immediately upon the provider chain's receipt of the evidence. Another thing to note is that we intend to introduce this system in stages, since even the partial ability to slash and/or tombstone is a strict improvement in security. +The feature is implemented in two parts, each with its dedicated endpoint. One endpoint handles light client attacks, while the other handles double signing attacks.

Light Client Attack

In a nutshell, the light client is a process that solely verifies a specific state machine's +consensus without executing the transactions. The light clients get new headers by querying +multiple nodes, called primary and witness nodes.

Light clients download new headers committed on chain from a primary. Headers can be verified in two ways: sequentially, +where the block height of headers is serial, or using skipping. This second verification method allows light clients to download headers +with nonconsecutive block height, where some intermediate headers are skipped (see Tendermint Light Client, Figure 1 and Figure 3). +Additionally, light clients are cross-checking new headers obtained from a primary with witnesses to ensure all nodes share the same state.

A light client attack occurs when a Byzantine validator sends invalid headers to a light client. +As the light client doesn't execute transactions, it can be deceived into trusting corrupted application state transitions. +For instance, if a light client receives header A from the primary and header B from a witness for the same block height H, +and both headers are successfully verified, it indicates a light client attack. +Note that in this case, either the primary or the witness or both are malicious.

The types of light client attacks are defined by analyzing the differences between the conflicting headers. +There are three types of light client attacks: lunatic attack, equivocation attack, and amnesia attack. +For details, see the CometBFT specification.

When a light client agent detects two conflicting headers, it will initially verify their traces (see cometBFT detector) using its primary and witness nodes. +If these headers pass successful verification, the Byzantine validators will be identified based on the header's commit signatures +and the type of light client attack. The agent will then transmit this information to its nodes using a LightClientAttackEvidence evidence to be eventually voted on and added to a block. +Note that from a light client agent perspective, it is not possible to establish whether a primary or a witness node, or both, are malicious. +Therefore, it will create and send two evidences: one against the primary (sent to the witness), and one against the witness (sent to the primary). +Both nodes will then verify it before broadcasting it and adding it to the evidence pool. +If an evidence is finally committed to a block, the chain's evidence module will execute it, resulting in the jailing and the slashing of the validators responsible for the light client attack.

Light clients are a core component of IBC. In the event of a light client attack, IBC relayers notify the affected chains by submitting an IBC misbehavior message. +A misbehavior message includes the conflicting headers that constitute a light client attack evidence. Upon receiving such a message, +a chain will first verify whether these headers would have convinced its light client. This verification is achieved by checking +the header states against the light client consensus states (see IBC misbehaviour handler). If the misbehaviour is successfully verified, the chain will then "freeze" the +light client, halting any further trust in or updating of its states.

Double Signing Attack

A double signing attack, also known as equivocation, +occurs when a validator votes for two different blocks in the same round of the CometBFT consensus. +This consensus mechanism operates with multiple voting rounds at each block height, +and it strictly prohibits sending two votes of the same type during a round +(see CometBFT State Machine Overview).

When a node observes two votes from the same peer, it will use these two votes to create +a DuplicateVoteEvidence +evidence and gossip it to the other nodes in the network +(see CometBFT equivocation detection). +Each node will then verify the evidence according to the CometBFT rules that define a valid double signing infraction, and based on this verification, they will decide whether to add the evidence to a block. +During the evidence verification process, the signatures of the conflicting votes must be verified successfully. +Note that this is achieved using the public key of the misbehaving validator, along with the chain ID of the chain where the infraction occurred (see CometBFT equivocation verification).

Once a double signing evidence is committed to a block, the consensus layer will report the equivocation to the evidence module of the Cosmos SDK application layer. +The application will, in turn, punish the malicious validator through jailing, tombstoning and slashing +(see handleEquivocationEvidence).

Decision

Light Client Attack

In the first part of the feature, we introduce a new endpoint: HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour). +The main idea is to leverage the current IBC misbehaviour handling and update it to solely jail and slash the validators that +performed a light client attack. Note that in this context, we assume that chains connected via a light client +share the same validator set, as is the case with Replicated Security.

This endpoint reuses the IBC client libraries to verify that the misbehaviour headers would have fooled the light client. +Additionally, it’s crucial that the endpoint logic results in the slashing and jailing of validators under the same conditions +as a light client agent detector. Therefore, the endpoint ensures that the two conditions are met: +the headers in the misbehaviour message have the same block height, and +the light client isn’t expired.

After having successfully verified a misbehaviour, the endpoint executes the jailing and slashing of the malicious validators similarly as in the evidence module.

Double Signing Attack

In the second part of the feature, we introduce a new endpoint HandleConsumerDoubleVoting( +ctx sdk.Context, evidence *tmtypes.DuplicateVoteEvidence, chainID string, pubkey cryptotypes.PubKey). +Simply put, the handling logic verifies a double signing evidence against a provided +public key and chain ID and, if successful, executes the jailing of the malicious validator who double voted.

We define a new +MsgSubmitConsumerDoubleVoting message to report a double voting evidence observed +on a consumer chain to the endpoint of the provider chain. This message contains two fields: +a double signing evidence +duplicate_vote_evidence and a light client header for the infraction block height, +referred to as infraction_block_header. +The latter provides the malicious validator's public key and the chain ID required to verify the signature of the votes contained in the evidence.

Note that double signing evidence is not verified using the same conditions as in the implementation CometBFT (see +verify(evidence types.Evidence) method). Specifically, we do not check that the evidence hasn't expired. +More details can be found in the "Current limitations" section below.

Upon a successful equivocation verification, the misbehaving validator is jailed for the maximum time +(see DoubleSignJailEndTime +in the SDK evidence module).

Current limitations:

  • We cannot derive an infraction height from the evidence, so it is only possible to jail validators, not actually slash them. +To explain the technical reasons behind this limitation, let's recap the initial consumer initiated slashing logic. +In a nutshell, consumer heights are mapped to provider heights through VSCPackets, namely through the so called vscIDs. +When an infraction occurs on the consumer, a SlashPacket containing the vscID obtained from mapping the consumer infraction height +is sent to the provider. Upon receiving the packet, the provider maps the consumer infraction height to a local infraction height, +which is used to slash the misbehaving validator. In the context of untrusted consumer chains, all their states, including vscIDs, +could be corrupted and therefore cannot be used for slashing purposes.

  • For the same reasons explained above, the age of a consumer double signing evidence can't be verified, +either using its infraction height or its unsigned timestamp. Note that changes the jailing behaviour, potentially leading to a validator's jailing based on some "old" evidence from a consumer, which wouldn't occur if the consumer were a standalone chain.

  • In the first stage of this feature, validators are jailed indefinitely without being tombstoned. +The underlying reason is that a malicious validator could take advantage of getting tombstoned +to avoid being slashed on the provider (see comment).

  • Currently, the endpoint can only handle "equivocation" light client attacks. This is because the "lunatic" attacks require the endpoint to possess the ability to dissociate which header is conflicted or trusted upon receiving a misbehavior message. Without this information, it's not possible to define the Byzantine validators from the conflicting headers (see comment).

Consequences

Positive

  • It is now possible for the provider chain to jail validators who committed +light client or double signing attacks on a consumer chain.

Negative

  • N/A

References

+ + + + \ No newline at end of file diff --git a/legacy/adrs/adr-005-cryptographic-equivocation-verification.html.html b/legacy/adrs/adr-005-cryptographic-equivocation-verification.html.html new file mode 100644 index 0000000000..101b5b7ddc --- /dev/null +++ b/legacy/adrs/adr-005-cryptographic-equivocation-verification.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop.html b/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop.html new file mode 100644 index 0000000000..5d92d26528 --- /dev/null +++ b/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop.html @@ -0,0 +1,51 @@ + + + + + +ADR Template | Interchain Security + + + + +
+
Version: Next

ADR 007: Pause validator unbonding during equivocation proposal

Changelog

  • 2023-05-16: Initial Draft

Status

Proposed

Context

Currently, if an equivocation slashing proposal is created after more than one +week has passed since the equivocation, it is possible that the validator in +question could unbond and get away without being slashed, since the unbonding +period is 3 weeks, and the voting period is 2 weeks. For this reason, it might +be good to pause unbondings for validators named in an equivocation slashing +proposal until the proposal's voting period is over.

Decision

How

Pausing the unbonding period is already possible thanks to the changes in the +staking module of the cosmos-sdk:

  • stakingKeeper.PutUnbondingOnHold pauses an unbonding period
  • stakingKeeper.UnbondingCanComplete unpauses an unbonding period

These methods use a reference counter under the hood, that gets incremented +every time PutUnbondingOnHold is called, and decreased when +UnbondingCanComplete is called instead. A specific unbonding is considered +fully unpaused when its underlying reference counter reaches 0. Therefore, as +long as we safeguard consistency - i.e. we make sure we eventually decrement +the reference counter for each time we have incremented it - we can safely use +this existing mechanism without conflicts with the Completion of Unbonding +Operations system.

When pause

The unbonding period (if there is any unbonding) should be paused once an +equivocation proposal enters the voting period. For that, the gov module's +hook AfterProposalDeposit can be used.

If the hook is triggered with a an equivocation proposal in voting period, then +for each equivocation of the proposal, the unbonding operations of the related +validator that were initiated after the equivocation block time must be paused

  • i.e. the underlying reference counter has to be increased.

Note that even after the voting period has started, a proposal can receive +additional deposits. The hook is triggered however at arrival of a deposit, so +a check to verify that the proposal is not already in voting period is +required.

When unpause

We can use a gov module's hook also here and it is +AfterProposalVotingPeriodEnded.

If the hook is triggered with an equivocation proposal, then for each +associated equivocation, the unbonding operations of the related validator that +were initiated between the equivocation block time and the start of the +proposal voting period must be unpaused - i.e. decrease the underlying +reference counter - regardless of the proposal outcome.

Consequences

Positive

  • Validators subject to an equivocation proposal cannot finish unbonding +their tokens before the end of the voting period.

Negative

  • A malicious consumer chain could forge slash packets enabling submission of +an equivocation proposal on the provider chain, resulting in the freezing of +validator's unbondings for an undeterminated amount of time.
  • Misbehavior on a consumer chain can potentially go unpunished, if no one +submits an equivocation proposal in time, or if the proposal doesn't pass.

Neutral

  • This feature can't be used for social slashing, because an equivocation +proposal is only accepted if there's a slash log for the related +validator(s), meaning the consumer chain has reported the equivocation to +the provider chain.

References

+ + + + \ No newline at end of file diff --git a/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html b/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html new file mode 100644 index 0000000000..8323c89f53 --- /dev/null +++ b/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/adrs/adr-008-throttle-retries.html b/legacy/adrs/adr-008-throttle-retries.html new file mode 100644 index 0000000000..489512916e --- /dev/null +++ b/legacy/adrs/adr-008-throttle-retries.html @@ -0,0 +1,19 @@ + + + + + +Throttle with retries | Interchain Security + + + + +
+
Version: Next

Throttle with retries

ADR 008: Throttle with retries

Changelog

  • 6/9/23: Initial draft
  • 6/22/23: added note on consumer pending packets storage optimization
  • 7/14/23: Added note on upgrade order

Status

Accepted

Context

For context on why the throttling mechanism exists, see ADR 002.

Note the terms slash throttling and jail throttling are synonymous, since in replicated security a SlashPacket simply jails a validator for downtime infractions.

Currently the throttling mechanism is designed so that provider logic (slash meter, etc.) dictates how many slash packets can be handled over time. Throttled slash packets are persisted on the provider, leading to multiple possible issues. Namely:

  • If slash or vsc matured packets are actually throttled/queued on the provider, state can grow and potentially lead to a DoS attack. We have short term solutions around this, but overall they come with their own weaknesses. See #594.
  • If a jailing attack described in ADR 002 were actually to be carried out with the current throttling design, we'd likely have to halt the provider, and perform an emergency upgrade and/or migration to clear the queues of slash packets that were deemed to be malicious. Alternatively, validators would just have to tough it out and wait for the queues to clear, during which all/most validators would be jailed. Right after being jailed, vals would have to unjail themselves promptly to ensure safety. The synchronous coordination required to maintain safety in such a scenario is not ideal.

So what's the solution? We can improve the throttling mechanism to instead queue/persist relevant data on each consumer, and have consumers retry slash requests as needed.

Decision

Consumer changes

Note the consumer already queues up both slash and vsc matured packets via AppendPendingPacket. Those packets are dequeued every endblock in SendPackets and sent to the provider.

Instead, we will now introduce the following logic on endblock:

  • Slash packets will always be sent to the provider once they're at the head of the queue. However, once sent, the consumer will not send any trailing vsc matured packets from the queue until the provider responds with an ack that the slash packet has been handled (ie. val was jailed). That is, slash packets block the sending of trailing vsc matured packets in the consumer queue.
  • If two slash packets are at the head of the queue, the consumer will send the first slash packet, and then wait for a success ack from the provider before sending the second slash packet. This seems like it'd simplify implementation.
  • VSC matured packets at the head of the queue (ie. NOT trailing a slash packet) can be sent immediately, and do not block any other packets in the queue, since the provider always handles them immediately.

To prevent the provider from having to keep track of what slash packets have been rejected, the consumer will have to retry the sending of slash packets over some period of time. This can be achieved with an on-chain consumer param. The suggested param value would probably be 1/2 of the provider's SlashMeterReplenishmentPeriod, although it doesn't matter too much as long as the param value is sane.

Note to prevent weird edge case behavior, a retry would not be attempted until either a success ack or failure ack has been recv from the provider.

With the behavior described, we maintain very similar behavior to the current throttling mechanism regarding the timing that slash and vsc matured packets are handled on the provider. Obviously the queueing and blocking logic is moved, and the two chains would have to send more messages between one another (only in the case the throttling mechanism is triggered).

In the normal case, when no or a few slash packets are being sent, the VSCMaturedPackets will not be delayed, and hence unbonding will not be delayed.

For implementation of this design, see throttle_retry.go.

Consumer pending packets storage optimization

In addition to the mentioned consumer changes above. An optimization will need to be made to the consumer's pending packets storage to properly implement the feature from this ADR.

The consumer ccv module previously queued "pending packets" to be sent on each endblocker in SendPackets. These packets are queued in state with a protobuf list of ConsumerPacketData. For a single append operation, the entire list is deserialized, then a packet is appended to that list, and the list is serialized again. See older version of AppendPendingPacket. That is, a single append operation has O(N) complexity, where N is the size of the list.

This poor append performance isn't a problem when the pending packets list is small. But with this ADR being implemented, the pending packets list could potentially grow to the order of thousands of entries, in the scenario that a slash packet is bouncing.

We can improve the append time for this queue by converting it from a protobuf-esq list, to a queue implemented with sdk-esq code. The idea is to persist an uint64 index that will be incremented each time you queue up a packet. You can think of this as storing the tail of the queue. Then, packet data will be keyed by that index, making the data naturally ordered byte-wise for sdk's iterator. The index will also be stored in the packet data value bytes, so that the index can later be used to delete certain packets from the queue.

Two things are achieved with this approach:

  • More efficient packet append/enqueue times
  • The ability to delete select packets from the queue (previously all packets were deleted at once)

Provider changes

The main change needed for the provider is the removal of queuing logic for slash and vsc matured packets upon being received.

Instead, the provider will consult the slash meter to determine if a slash packet can be handled immediately. If not, the provider will return an ack message to the consumer communicating that the slash packet could not be handled, and needs to be sent again in the future (retried).

VSCMatured packets will always be handled immediately upon being received by the provider.

Note spec. Specifically the section on VSC Maturity and Slashing Order. Previously the onus was on the provider to maintain this property via queuing packets and handling them FIFO.

Now this property will be maintained by the consumer sending packets in the correct order, and blocking the sending of VSCMatured packets as needed. Then, the ordered IBC channel will ensure that Slash/VSCMatured packets are received in the correct order on the provider.

The provider's main responsibility regarding throttling will now be to determine if a recv slash packet can be handled via slash meter etc., and appropriately ack to the sending consumer.

Why the provider can handle VSCMatured packets immediately

First we answer, what does a VSCMatured packet communicate to the provider? A VSCMatured packet communicates that a VSC has been applied to a consumer long enough that infractions committed on the consumer could have been submitted.

If the consumer is following the queuing/blocking protocol described. No bad behavior occurs, VSC Maturity and Slashing Order property is maintained.

If a consumer sends VSCMatured packets too leniently: The consumer is malicious and sending duplicate vsc matured packets, or sending the packets sooner than the ccv protocol specifies. In this scenario, the provider needs to handle vsc matured packets immediately to prevent DOS, state bloat, or other issues. The only possible negative outcome is that the malicious consumer may not be able to jail a validator who should have been jailed. The malicious behavior only creates a negative outcome for the chain that is being malicious.

If a consumer blocks the sending of VSCMatured packets: The consumer is malicious and blocking vsc matured packets that should have been sent. This will block unbonding only up until the VSC timeout period has elapsed. At that time, the consumer is removed. Again the malicious behavior only creates a negative outcome for the chain that is being malicious.

Splitting of PRs and Upgrade Order

This feature will implement consumer changes in #1024. Note these changes should be deployed to prod for all consumers before the provider changes are deployed to prod. That is the consumer changes in #1024 are compatible with the current ("v1") provider implementation of throttling that's running on the Cosmos Hub as of July 2023.

Once all consumers have deployed the changes in #1024, the provider changes from (TBD) can be deployed to prod, fully enabling v2 throttling.

Consequences

  • Consumers will now have to manage their own queues, and retry logic.
  • Consumers still aren't trustless, but the provider is now less susceptible to mismanaged or malicious consumers.
  • Recovering from the "jailing attack" is more elegant.
  • Some issues like #1001 will now be handled implicitly by the improved throttling mechanism.
  • Slash and vsc matured packets can be handled immediately once recv by the provider if the slash meter allows.
  • In general, we reduce the amount of computation that happens in the provider end-blocker.

Positive

  • We no longer have to reason about a "global queue" and a "chain specific queue", and keeping those all in-sync. Now slash and vsc matured packet queuing is handled on each consumer individually.
  • Due to the above, the throttling protocol becomes less complex overall.
  • We no longer have to worry about throttle related DoS attack on the provider, since no queuing exists on the provider.

Negative

  • Increased number of IBC packets being relayed anytime throttling logic is triggered.
  • Consumer complexity increases, since consumers now have manage queuing themselves, and implement packet retry logic.

Neutral

  • Core throttling logic on the provider remains unchanged, ie. slash meter, replenishment cycles, etc.

References

+ + + + \ No newline at end of file diff --git a/legacy/adrs/adr-008-throttle-retries.html.html b/legacy/adrs/adr-008-throttle-retries.html.html new file mode 100644 index 0000000000..f0a0499466 --- /dev/null +++ b/legacy/adrs/adr-008-throttle-retries.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/adrs/adr-009-soft-opt-out.html b/legacy/adrs/adr-009-soft-opt-out.html new file mode 100644 index 0000000000..3adee456b2 --- /dev/null +++ b/legacy/adrs/adr-009-soft-opt-out.html @@ -0,0 +1,19 @@ + + + + + +Soft Opt-Out | Interchain Security + + + + +
+
Version: Next

Soft Opt-Out

ADR 009: Soft Opt-Out

Changelog

  • 6/13/23: Initial draft of ADR. Feature already implemented and in production.

Status

Accepted

Context

Some small validators may not have the resources needed to validate all consumer chains. Therefore a need exists to allow the bottom x% of validators to opt-out of validating a consumer chain. Meaning downtime infractions for these validators are dropped without ever reaching the provider.

This document specifies a modification to the ccv protocol which allows the bottom x% of the validator set by power to opt out of validating consumer chains without being jailed or otherwise punished for it. The feature is implemented with entirely consumer-side code.

Decision

A consumer param exists, known as SoftOptOutThreshold, which is a string decimal in the range of [0, 0.2], that determines the portion of validators which are allowed to opt out of validating that specific consumer.

In every consumer beginblocker, a function is ran which determines the so called smallest non opt-out voting power. Validators with voting power greater than or equal to this value must validate the consumer chain, while validators below this value may opt out of validating the consumer chain.

The smallest non opt-out voting power is recomputed every beginblocker in UpdateSmallestNonOptOutPower(). In a nutshell, the method obtains the total voting power of the consumer, iterates through the full valset (ordered power ascending) keeping track of a power sum, and when powerSum / totalPower > SoftOptOutThreshold, the SmallestNonOptOutPower is found and persisted.

Then, whenever the Slash() interface is executed on the consumer, if the voting power of the relevant validator being slashed is less than SmallestNonOptOutPower for that block, the slash request is dropped and never sent to the provider.

Consequences

Positive

  • Small validators can opt out of validating specific consumers without being punished for it.

Negative

  • The bottom x% is still part of the total voting power of the consumer chain. This means that if the soft opt-out threshold is set to 10% for example, and every validator in the bottom 10% opts out from validating the consumer, then a 24% downtime of the remaining voting power would halt the chain. This may be especially problematic during consumer upgrades.
  • In nominal scenarios, consumers with soft opt out enabled will be constructing slash packets for small vals, which may be dropped. This is wasted computation, but necessary to keep implementation simple. Note that the sdk's full downtime logic is always executed on the consumer, which can be computationally expensive and slow down certain blocks.

Neutral

  • Validators in the bottom of the valset who don't have to validate, may receive large delegation(s) which suddenly boost the validator to the subset that has to validate. This may catch the validator off guard.

References

  • Original issue with some napkin math #784
+ + + + \ No newline at end of file diff --git a/legacy/adrs/adr-009-soft-opt-out.html.html b/legacy/adrs/adr-009-soft-opt-out.html.html new file mode 100644 index 0000000000..ffe8bb7f72 --- /dev/null +++ b/legacy/adrs/adr-009-soft-opt-out.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/adrs/adr-010-standalone-changeover.html b/legacy/adrs/adr-010-standalone-changeover.html new file mode 100644 index 0000000000..ac5db505e9 --- /dev/null +++ b/legacy/adrs/adr-010-standalone-changeover.html @@ -0,0 +1,19 @@ + + + + + +Standalone to Consumer Changeover | Interchain Security + + + + +
+
Version: Next

Standalone to Consumer Changeover

ADR 010: Standalone to Consumer Changeover

Changelog

  • 6/30/23: Feature completed, first draft of ADR.

Status

Implemented

Context

Stride will be the first consumer to "changeover" from a standalone cosmos blockchain, to a consumer chain secured by the Cosmos Hub. This document will outline the changes made to the replicated security protocol to support this changeover process.

Decision

Process

Prior to the changeover, the consumer chain will have an existing staking keeper and validator set, these may be referred to as the "standalone staking keeper" and "standalone validator set" respectively.

The first step in the changeover process is to submit a ConsumerAdditionProposal. If the proposal passes, the provider will create a new IBC client for the consumer at spawn time, with the provider's validator set. A consumer genesis will also be constructed by the provider for validators to query. Within this consumer genesis contains the initial validator set for the consumer to apply after the changeover.

Next, the standalone consumer chain runs an upgrade which adds the CCV module, and is properly setup to execute changeover logic.

The consumer upgrade height must be reached after the provider has created the new IBC client. Any replicated security validators who will run the consumer, but are not a part of the sovereign validator set, must sync up a full node before the consumer upgrade height is reached. The disc state of said full node will be used to run the consumer chain after the changeover has completed.

The meat of the changeover logic is that the consumer chain validator set is updated to that which was specified by the provider via the queried consumer genesis. Validators which were a part of the old set, but not the new set, are given zero voting power. Once these validator updates are given to Comet, the set is committed, and in effect 2 blocks later (see FirstConsumerHeight).

A relayer then establishes the new IBC connection between the provider and consumer. The CCV channel handshake is started on top of this connection. Once the CCV channel is established and VSC packets are being relayed, the consumer chain is secured by the provider.

Changes to CCV Protocol

  • Consumer Genesis state is updated to include a PreCCV boolean. When this boolean is set true in the consumer genesis JSON, special logic is executed on InitGenesis to trigger the changeover process on the consumer's first endblocker after the upgrade which adds the CCV module. Note that InitGenesis is not automatically called during chain upgrades, so the consumer must manually call the consumer's InitGenesis method in an upgrade handler.
  • The ConsumerAdditionProposal type is updated to include a DistributionTransmissionChannel field. This field allows the consumer to use an existing IBC transfer channel to send rewards as a part of the CCV protocol. Consumers that're not changing over from a standalone chain will leave this field blank, indicating that a new transfer channel should be created on top of the same connection as the CCV channel.
  • The CCV consumer keeper is updated to contain an optional reference to the standalone staking keeper. The standalone staking keeper is used to slash for infractions that happened before the changeover was completed. Ie. any infraction from a block height before the changeover, that is submitted after the changeover, will call the standalone staking keeper's slash method. Note that a changeover consumer's standalone staking keeper becomes a democracy module keeper, so it is possible for a governance token to be slashed.

Consequences

Positive

  • Existing cosmos chains are now able to onboard over to a consumer chain secured by a provider.
  • The previous staking keepers for such chains can be transitioned to democracy staking module keepers.

Negative

  • The delineation between different types of consumers in this repo becomes less clear. Ie. there is code in the democracy consumer's app.go that only applies to a previously standalone chain, but that file also serves as the base for a normal democracy consumer launched with RS from genesis.

References

+ + + + \ No newline at end of file diff --git a/legacy/adrs/adr-010-standalone-changeover.html.html b/legacy/adrs/adr-010-standalone-changeover.html.html new file mode 100644 index 0000000000..7670e7cc04 --- /dev/null +++ b/legacy/adrs/adr-010-standalone-changeover.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/adrs/adr-011-improving-test-confidence.html b/legacy/adrs/adr-011-improving-test-confidence.html new file mode 100644 index 0000000000..7db527e1ab --- /dev/null +++ b/legacy/adrs/adr-011-improving-test-confidence.html @@ -0,0 +1,29 @@ + + + + + +Improving testing and increasing confidence | Interchain Security + + + + +
+
Version: Next

ADR 11: Improving testing and increasing confidence

Changelog

  • 2023-08-11: Proposed, first draft of ADR.

Status

Proposed

Context

Testing, QA, and maintenance of interchain-security libraries is an ever-evolving area of software engineering we have to keep incrementally improving. The purpose of the QA process is to catch bugs as early as possible. In an ideal development workflow a bug should never reach production. A bug found in the specification stage is a lot cheaper to resolve than a bug discovered in production (or even in testnet). Ideally, all bugs should be found during the CI execution, and we hope that no bugs will ever even reach the testnet (although nothing can replace actual system stress test under load interacting with users).

During development and testnet operation the following types of bugs were the most commonly found:

  • improper iterator usage
  • unbounded array access/iteration
  • improper input handling and validation
  • improper cached context usage
  • non-determinism check (improper use of maps in go, relying on random values)
  • KV store management and/or how keys are defined
  • deserialization issues arising from consumer/provider versioning mismatch

Such bugs can be discovered earlier with better tooling. Some of these bugs can induce increases in block times, chain halts, state corruption, or introduce an attack surface which is difficult to remove if other systems have started depending on that behavior.

Current state of testing

Our testing suites consist of multiple parts, each with their own trade-offs and benefits with regards to code coverage, complexity and confidence they provide.

Unit testing

Unit testing is employed mostly for testing single-module functionality. It is the first step in testing and often the most practical. While highly important, unit tests often test a single piece of code and don't test relationships between different moving parts, this makes them less valuable when dealing with multi-module interactions.

Unit tests often employ mocks to abstract parts of the system that are not under test. Mocks are not equivalent to actual models and should not be treated as such.

Out of all the approaches used, unit testing has the most tools available and the coverage can simply be displayed as % of code lines tested. Although this is a very nice and very easy to understand metric, it does not speak about the quality of the test coverage.

Since distributed systems testing is a lot more involved, unit tests are oftentimes not sufficient to cover complex interactions. Unit tests are still necessary and helpful, but in cases where unit tests are not helpful e2e or integration tests should be favored.

Integration testing

With integration testing we test the multi-module interactions while isolating them from the remainder of the system. +Integration tests can uncover bugs that are often missed by unit tests.

It is very difficult to gauge the actual test coverage imparted by integration tests and the available tooling is limited. +In interchain-security we employ the ibc-go/testing framework to test interactions in-memory.

At present, integration testing does not involve the consensus layer - it is only concerned with application level state and logic.

End-to-end testing

In our context end-to-end testing comprises of tests that use the actual application binaries in an isolated environment (e.g. docker container). During test execution the inputs are meant to simulate actual user interaction, either by submitting transactions/queries using the command line or using gRPC/REST APIs and checking for state changes after an action has been performed. With this testing strategy we also include the consensus layer in all of our runs. This is the closest we can get to testing user interactions without starting a full testnet.

End-to-end testing strategies vary between different teams and projects and we strive to unify our approach to the best of our ability (at least for ICS and gaia).

The available tooling does not give us significant (or relevant) line of code coverage information since most of the tools are geared towards analyzing unit tests and simple code branch evaluation.

We aim to adapt our best practices by learning from other similar systems and projects such as cosmos-sdk, ibc-go and CometBFT.

Decision

1. Connect specifications to code and tooling

Oftentimes, specifications are disconnected from the development and QA processes. This gives rise to problems where the specification does not reflect the actual state of the system and vice-versa. +Usually specifications are just text files that are rarely used and go unmaintained after a while, resulting in consistency issues and misleading instructions/expectations about system behavior.

Decision context and hypothesis

Specifications written in a dedicated and executable specification language are easier to maintain than the ones written entirely in text. +Additionally, we can create models based on the specification OR make the model equivalent to a specification.

Models do not care about the intricacies of implementation and neither do specifications. Since both models and specifications care about concisely and accurately describing a system (such as a finite state machine), we see a benefit of adding model based tools (such as quint) to our testing and development workflows.

Main benefit

MBT tooling can be used to generate test traces that can be executed by multiple different testing setups.

2. Improve e2e tooling

Matrix tests

Instead of only running tests against current main branch we should adopt an approach where we also:

  • run regression tests against different released software versions (ICS v1 vs v2 vs v3)
  • run non-determinism tests to uncover issues quickly

Matrix tests can be implemented using CometMock and refactoring our current e2e CI setup.

Introducing e2e regression testing

This e2e test suite would execute using a cronjob in our CI (nightly, multiple times a day etc.)

Briefly, the same set of traces is run against different maintained versions of the software and the main branch. +This would allow us to discover potential issues during development instead of in a testnet scenarios.

The most valuable issues that can be discovered in this way are state breaking changes, regressions and version incompatibilities.

The setup is illustrated by the image below. +e2e matrix tests

This table explains which versions are tested against each other for the same set of test traces:

  • ✅ marks a passing test
  • ❌ marks a failing test
USES: ICS v1 PROVIDERstart chainadd keydelegateundelegateredelegatedowntimeequivocationstop chain
v1 consumer (sdk45,ibc4.3)
v2 consumer (sdk45, ibc4.4)
v3 consumer (sdk47, ibc7)
main consumer
neutron
stride

Introducing e2e CometMock tests

CometMock is a mock implementation of the CometBFT consensus engine. It supports most operations performed by CometBFT while also being lightweight and relatively easy to use.

CometMock tests allow more nuanced control of test scenarios because CometMock can "fool" the blockchain app into thinking that a certain number of blocks had passed. +This allows us to test very nuanced scenarios, difficult edge cases and long-running operations (such as unbonding operations).

Examples of tests made easier with CometMock are listed below:

  • regression tests
  • non-determinism tests
  • upgrade tests
  • state-breaking changes

With CometMock, the matrix test approach can also be used. The image below illustrates a CometMock setup that can be used to discover non-deterministic behavior and state-breaking changes. +e2e matrix tests

This table explains which versions are tested against each other for the same set of test traces:

  • ✅ marks a passing test
  • ❌ marks a failing test
SCENARIOstart chainadd keydelegateundelegateredelegatedowntimeequivocationstop chain
v3 provi + v3 consu
main provi + main consu
commit provi + commit consu

Briefly; multiple versions of the application are run against the same CometMock instance and any deviations in app behavior would result in app hash errors (the apps would be in different states after performing the same set of actions).

3. Introduce innovative testing approaches

When discussing e2e testing, some very important patterns emerge - especially if test traces are used instead of ad-hoc tests written by hand.

We see a unique opportunity to clearly identify concerns and modularize the testing architecture.

The e2e testing frameworks can be split into a pipeline consisting of 3 parts: model, driver and harness.

Model

Model is the part of the system that can emulate the behavior of the system under test. +Ideally, it is very close to the specification and is written in a specification language such as quint, TLA+ or similar. +One of the purposes of the model is that it can be used to generate test traces.

Driver

The purpose of the driver is to accept test traces (generated by the model or written by hand), process them and provide inputs to the next part of the pipeline.

Basically, the driver sits between the model and the actual infrastructure on which the test traces are being executed on.

Harness

Harness is the infrastructure layer of the pipeline that accepts inputs from the driver.

There can be multiple harnesses as long as they can perform four things:

  • bootstrap a test execution environment (local, docker, k8s…)
  • accept inputs from drivers
  • perform the action specified by the driver
  • report results after performing actions

Consequences

The procedure outlined in this ADR is not an all-or-nothing approach. Concepts introduced here do not rely on each other, so this ADR may only be applied partially without negative impact on test coverage and code confidence.

Positive

  1. introduction of maintainable MBT solutions
  • improvement over the current "difftest" setup that relies on an opinionated typescript model and go driver
  1. increased code coverage and confidence
  • using CometMock allows us to run more tests in less time
  • adding matrix e2e tests allows us to quickly pinpoint differences between code versions

Negative

It might be easier to forgo the MBT tooling and instead focus on pure property based testing

The solutions are potentially expensive if we increase usage of the CI pipeline - this is fixed by running "expensive" tests using a cronjob, instead of running them on every commit.

Neutral

The process of changing development and testing process is not something that can be thought of and delivered quickly. Luckily, the changes can be rolled out incrementally without impacting existing workflows.

References

Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!

+ + + + \ No newline at end of file diff --git a/legacy/adrs/adr-011-improving-test-confidence.html.html b/legacy/adrs/adr-011-improving-test-confidence.html.html new file mode 100644 index 0000000000..56213acfd2 --- /dev/null +++ b/legacy/adrs/adr-011-improving-test-confidence.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/adrs/adr-012-separate-releasing.html b/legacy/adrs/adr-012-separate-releasing.html new file mode 100644 index 0000000000..dcd67676f7 --- /dev/null +++ b/legacy/adrs/adr-012-separate-releasing.html @@ -0,0 +1,23 @@ + + + + + +Separate Releasing | Interchain Security + + + + +
+
Version: Next

ADR 012: Separate Releasing

Changelog

  • {8/18/22}: Initial draft of idea in #801
  • {8/22/22}: Put idea in this ADR
  • {11/10/22}: Reject this ADR

Status

Rejected

Context

Spike results

I explored the idea of #801 with this spike branch. Here's my conclusions:

Splitting this repo to have multiple go.mods is possible. However there are various intricacies involved in decoupling the package hierarchy to have x/ccv/types as the lowest level dep, with x/ccv/consumer and x/ccv/provider being one dep layer above, with high-level tests depending on all three of the mentioned packages. I'd estimate this decoupling would take 2-5 workdays to finish, and require significant review effort.

Why go.mod split is not the way to go

Let's take a step back and remember the issue we're trying to solve - We need a clean way to decouple semver/releasing for the consumer and provider modules. After more consideration, splitting up go.mods gives us little benefit in achieving this. Reasons:

  • The go.mod dependency system is tied to git tags for the entire repo (ex: require github.com/cometbft/cometbft v0.37.2 refers to a historical tag for the entire cometbft repo).
  • It'd be an odd dev experience to allow modules to reference past releases of other modules in the same repo. When would we ever want the consumer module to reference a past release of the types module for example?
  • If we allow for go.mod replace statements to build from local source code, why split up the package deps at all?
  • Splitting go.mods adds a bunch of complexity with go.work files and all that shiz. VSCode does not play well with multiple module repos either.

Why separate repos is cool but also not the way to go

All this considered, the cleanest solution to decoupling semver/releasing for the consumer and provider modules would be to have multiple repos, each with their own go.mod (3-4 repos total including high level tests). With this scheme we could separately tag each repo as changes are merged, they could share some code from types being an external dep, etc.

I don't think any of us want to split up the monorepo, that's a lot of work and seems like bikeshedding. There's another solution that's very simple..

Decision

Slightly adapting the current semver ruleset:

  • A library API breaking change to EITHER the provider or consumer module will result in an increase of the MAJOR version number for BOTH modules (X.y.z-provider AND X.y.z-consumer).
  • A state breaking change (change requiring coordinated upgrade and/or state migration) will result in an increase of the MINOR version number for the AFFECTED module(s) (x.Y.z-provider AND/OR x.Y.z-consumer).
  • Any other changes (including node API breaking changes) will result in an increase of the PATCH version number for the AFFECTED module(s) (x.y.Z-provider AND/OR x.y.Z-consumer).

Example release flow

We upgrade main to use a new version of SDK. This is a major version bump, triggering a new release for both the provider and consumer modules, v5.0.0-provider and v5.0.0-consumer.

  • A state breaking change is merged to main for the provider module. We release only a v5.1.0-provider off main.
  • Another state breaking change is merged to main for the provider module. We release only a v5.2.0-provider off main.
  • At this point, the latest consumer version is still v5.0.0-consumer. We now merge a state breaking change for the consumer module to main, and consequently release v5.1.0-consumer. Note that v5.1.0-consumer is tagged off a LATER commit from main than v5.2.0-provider. This is fine, as the consumer module should not be affected by the provider module's state breaking changes.
  • Once either module sees a library API breaking change, we bump the major version for both modules. For example, we merge a library API breaking change to main for the provider module. We release v6.0.0-provider and v6.0.0-consumer off main. Note that most often, a library API breaking change will affect both modules simultaneously (example being bumping sdk version).

Consequences

Positive

  • Consumer repos have clear communication of what tagged versions are relevant to them. Consumer devs should know to never reference an ICS version that starts with provider, even if it'd technically build.
  • Consumer and provider modules do not deviate as long as we continually release off a shared main branch. Backporting remains relatively unchanged besides being explicit about what module(s) your changes should affect.
  • No code changes, just changes in process. Very simple.

Negative

  • Slightly more complexity.Considerably more complex to manage the ICS library. +This is because ICS needs to support multiple versions of SDK (e.g., 0.45, 0.47, 0.50). +In addition, ICS needs to support a special fork of SDK (with LSM included) for the Cosmos Hub. +This means that instead of focusing on main the development team needs to manage multiple release +branches with different dependency trees.
  • This solution does not allow having provider and consumer on separate versions of e.g. the Cosmos SDK.

Neutral

References

Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!

+ + + + \ No newline at end of file diff --git a/legacy/adrs/adr-012-separate-releasing.html.html b/legacy/adrs/adr-012-separate-releasing.html.html new file mode 100644 index 0000000000..dd7d935595 --- /dev/null +++ b/legacy/adrs/adr-012-separate-releasing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/adrs/adr-013-equivocation-slashing.html b/legacy/adrs/adr-013-equivocation-slashing.html new file mode 100644 index 0000000000..c5f877fc1f --- /dev/null +++ b/legacy/adrs/adr-013-equivocation-slashing.html @@ -0,0 +1,39 @@ + + + + + +Slashing on the provider for consumer equivocation | Interchain Security + + + + +
+
Version: Next

ADR 013: Slashing on the provider for consumer equivocation

Changelog

  • 1st Sept. 2023: Initial draft

Status

Proposed

Context

This ADR presents some approaches on how to slash on the provider chain validators that performed equivocations on consumer chains. +Currently, the provider chain can receive and verify evidence of equivocation, but it cannot slash the misbehaving validator.

In the remainder of this section, we explain how slashing is performed on a single chain and show why slashing on the provider for equivocation on the consumer is challenging.

Note that future versions of the Cosmos SDK, CometBFT, and ibc-go could modify the way we slash, etc. Therefore, a future reader of this ADR, should note that when we refer to Cosmos SDK, CometBFT, and ibc-go we specifically refer to their v0.47, v0.37 and v7.3.0 versions respectively.

Single-chain slashing

Slashing is implemented across the slashing +and staking modules. +The slashing module's keeper calls the staking module's Slash() method, passing among others, the infractionHeight (i.e., the height when the equivocation occurred), the validator's power at the infraction height, and the slashFactor (currently set to 5% in case of equivocation on the Cosmos Hub).

Slashing undelegations and redelegations

To slash undelegations, Slash goes through all undelegations and checks whether they started before or after the infraction occurred. If an undelegation started before the infractionHeight, then it is not slashed, otherwise it is slashed by slashFactor.

The slashing of redelegations happens in a similar way, meaning that Slash goes through all redelegations and checks whether the redelegations started before or after the infractionHeight.

Slashing delegations

Besides undelegations and redelegations, the validator's delegations need to also be slashed. +This is performed by deducting the appropriate amount of tokens from the validator. Note that this deduction is computed based on the voting power the misbehaving validator had at the height of the equivocation. As a result of the tokens deduction, +the tokens per share +reduce and hence later on, when delegators undelegate or redelegate, the delegators retrieve back less +tokens, effectively having their tokens slashed. The rationale behind this slashing mechanism, as mentioned in the Cosmos SDK documentation

[...] is to simplify the accounting around slashing. Rather than iteratively slashing the tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, effectively reducing the value of each issued delegator share.

This approach of slashing delegations does not utilize the +infractionHeight in any way and hence the following scenario could occur:

  1. a validator V performs an equivocation at a height Hi
  2. a new delegator D delegates to V after height Hi
  3. evidence of the equivocation by validator V is received
  4. the tokens of delegator D are slashed

In the above scenario, delegator D is slashed, even though D's voting power did not contribute to the infraction.

Old evidence

In the single-chain case, old evidence (e.g., from 3 years ago) is ignored. This is achieved through +CometBFT that ignores old evidence based on the parameters MaxAgeNumBlocks and MaxAgeDuration (see here). +Additionally, note that when the evidence is sent by CometBFT to the application, the evidence is rechecked in the evidence module of Cosmos SDK and if it is old, the evidence is ignored. +In Cosmos Hub, the MaxAgeNumBlocks is set to 1000000 (i.e., ~70 days if we assume we need ~6 sec per block) and MaxAgeDuration is set to 172800000000000 ns (i.e., 2 days). Because of this check, we can easily exclude old evidence.

Slashing for equivocation on the consumer

In the single-chain case, slashing requires both the infractionHeight and the voting power. +In order to slash on the provider for an equivocation on a consumer, we need to have both the provider's infractionHeight and voting power. +Note that the infractionHeight on the consumer chain must be mapped to a height on the provider chain. +Unless we have a way to find the corresponding infractionHeight and power on the provider chain, we cannot slash for equivocation on the consumer in the same way as we would slash in the single-chain case.

The challenge of figuring out the corresponding infractionHeight and power values on the provider chain is due to the following trust assumption:

  • We trust the consensus layer and validator set of the consumer chains, but we do not trust the application layer.

As a result, we cannot trust anything that stems from the application state of a consumer chain.

Note that when a relayer or a user sends evidence through a MsgSubmitConsumerDoubleVoting message, the provider gets access to DuplicateVoteEvidence:

type DuplicateVoteEvidence struct {
VoteA *Vote `json:"vote_a"`
VoteB *Vote `json:"vote_b"`

// abci specific information
TotalVotingPower int64
ValidatorPower int64
Timestamp time.Time
}

The "abci specific information" fields cannot be trusted because they are not signed. Therefore, +we can use neither ValidatorPower for slashing on the provider chain, nor the Timestamp to check the evidence age. We can get the infractionHeight from the votes, but this infractionHeight corresponds to the infraction height on the consumer and not on the provider chain. +Similarly, when a relayer or a user sends evidence through a MsgSubmitConsumerMisbehaviour message, the provider gets access to Misbehaviour that we cannot use to extract the infraction height, power, or the time on the provider chain.

Proposed solution

As a first iteration, we propose the following approach. At the moment the provider receives evidence of equivocation on a consumer:

  1. slash all the undelegations and redelegations using slashFactor;
  2. slash all delegations using as voting power the sum of the voting power of the misbehaving validator and the power of all the ongoing undelegations and redelegations.

Evidence expiration: Additionally, because we cannot infer the actual time of the evidence (i.e., the timestamp of the evidence cannot be trusted), we do not consider evidence expiration and hence old evidence is never ignored (e.g., the provider would act on 3 year-old evidence of equivocation on a consumer). +Additionally, we do not need to store equivocation evidence to avoid slashing a validator more than once, because we do not slash tombstoned validators and we tombstone a validator when slashed.

We do not act on evidence that was signed by a validator consensus key that is pruned when we receive the evidence. We prune a validator's consensus key if the validator has assigned a new consumer key (using MsgAssignConsumerKey) and an unbonding period on the consumer chain has elapsed (see key assignment ADR). Note that the provider chain is informed that the unbonding period has elapsed on the consumer when the provider receives a VSCMaturedPacket and because of this, if the consumer delays the sending of a VSCMaturedPacket, we would delay the pruning of the key as well.

Implementation

The following logic needs to be added to the HandleConsumerDoubleVoting and HandleConsumerMisbehaviour methods:

undelegationsInTokens := sdk.NewInt(0)
for _, v := range k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validatorAddress) {
for _, entry := range v.Entries {
if entry.IsMature(now) && !entry.OnHold() {
// undelegation no longer eligible for slashing, skip it
continue
}
undelegationsInTokens = undelegationsInTokens.Add(entry.InitialBalance)
}
}

redelegationsInTokens := sdk.NewInt(0)
for _, v := range k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validatorAddress) {
for _, entry := range v.Entries {
if entry.IsMature(now) && !entry.OnHold() {
// redelegation no longer eligible for slashing, skip it
continue
}
redelegationsInTokens = redelegationsInTokens.Add(entry.InitialBalance)
}
}

infractionHeight := 0
undelegationsAndRedelegationsInPower = sdk.TokensToConsensusPower(undelegationsInTokens.Add(redelegationsInTokens))
totalPower := validator's voting power + undelegationsAndRedelegationsInPower
slashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)

k.stakingKeeper.Slash(ctx, validatorConsAddress, infractionHeight, totalPower, slashFraction, DoubleSign)

Infraction height: We provide a zero infractionHeight to the Slash method in order to slash all ongoing undelegations and redelegations (see checks in Slash, SlashUnbondingDelegation, and SlashRedelegation).

Power: We pass the sum of the voting power of the misbehaving validator when the evidence was received (i.e., at evidence height) and the power of all the ongoing undelegations and redelegations. +If we assume that the slashFactor is 5%, then the voting power we pass is power + totalPower(undelegations) + totalPower(redelegations). +Hence, when the Slash method slashes all the undelegations and redelegations it would end up with 0.05 * power + 0.05 * totalPower(undelegations) + 0.05 * totalPower(redelegations) - 0.05 * totalPower(undelegations) - 0.05 * totalPower(redelegations) = 0.05 * power and hence it would slash 5% of the validator's power when the evidence is received.

Positive

With the proposed approach we can quickly implement slashing functionality on the provider chain for consumer chain equivocations. +This approach does not need to change the staking module and therefore does not change in any way how slashing is performed today for a single chain.

Negative

  • We definitely slash more when it comes to undelegations and redelegations because we slash for all of them without considering an infractionHeight.
  • We potentially slash more than what we would have slashed if we knew the voting power at the corresponding infractionHeight in the provider chain.
  • We slash on old evidence of equivocation on a consumer.

References

+ + + + \ No newline at end of file diff --git a/legacy/adrs/adr-013-equivocation-slashing.html.html b/legacy/adrs/adr-013-equivocation-slashing.html.html new file mode 100644 index 0000000000..8872c77fc4 --- /dev/null +++ b/legacy/adrs/adr-013-equivocation-slashing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/adrs/adr-template.html b/legacy/adrs/adr-template.html new file mode 100644 index 0000000000..347a8e7d51 --- /dev/null +++ b/legacy/adrs/adr-template.html @@ -0,0 +1,22 @@ + + + + + +ADR Template | Interchain Security + + + + +
+
Version: Next

ADR {ADR-NUMBER}: {TITLE}

Changelog

  • {date}: {changelog}

Status

A decision may be "proposed" if it hasn't been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement.

{Deprecated|Proposed|Accepted}

Context

This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution.

Decision

This section explains all of the details of the proposed solution, including implementation details. +It should also describe affects / corollary items that may need to be changed as a part of this. +If the proposed change will be large, please also indicate a way to do the change to maximize ease of review. +(e.g. the optimal split of things to do between separate PR's)

Consequences

This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones.

Positive

Negative

Neutral

References

Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!

  • {reference link}
+ + + + \ No newline at end of file diff --git a/legacy/adrs/adr-template.html.html b/legacy/adrs/adr-template.html.html new file mode 100644 index 0000000000..e1125a9d3f --- /dev/null +++ b/legacy/adrs/adr-template.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/adrs/intro.html b/legacy/adrs/intro.html new file mode 100644 index 0000000000..194c88850d --- /dev/null +++ b/legacy/adrs/intro.html @@ -0,0 +1,22 @@ + + + + + +ADRs | Interchain Security + + + + +
+
Version: Next

Architecture Decision Records (ADR)

This is a location to record all high-level architecture decisions in the Interchain Security project.

You can read more about the ADR concept in this blog post.

An ADR should provide:

  • Context on the relevant goals and the current state
  • Proposed changes to achieve the goals
  • Summary of pros and cons
  • References
  • Changelog

Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and +justification for a change in architecture, or for the architecture of something +new. The spec is much more compressed and streamlined summary of everything as +it is or should be.

If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match.

Note the context/background should be written in the present tense.

To suggest an ADR, please make use of the ADR template provided.

Table of Contents

ADR #DescriptionStatus
001Consumer chain key assignmentAccepted, Implemented
002Jail ThrottlingAccepted, Implemented
003Equivocation governance proposalAccepted, Implemented
004Denom DOS fixesAccepted, Implemented
005Cryptographic verification of equivocation evidenceAccepted, In-progress
007Pause validator unbonding during equivocation proposalProposed
008Throttle with retriesAccepted, In-progress
009Soft Opt-outAccepted, Implemented
010Standalone to Consumer ChangeoverAccepted, Implemented
011Improving testing and increasing confidenceProposed
012Separate ReleasingProposed
013Slashing on the provider for consumer equivocationProposed
+ + + + \ No newline at end of file diff --git a/legacy/adrs/intro.html.html b/legacy/adrs/intro.html.html new file mode 100644 index 0000000000..9f46b63d8e --- /dev/null +++ b/legacy/adrs/intro.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/assets/css/styles.f695a4a3.css b/legacy/assets/css/styles.f695a4a3.css new file mode 100644 index 0000000000..30e4206493 --- /dev/null +++ b/legacy/assets/css/styles.f695a4a3.css @@ -0,0 +1 @@ +.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500);--docsearch-searchbox-shadow:inset 0 0 0 1px var(--docsearch-primary-color)}*,:after,:before{box-sizing:border-box}html .menu__link:hover,html .table-of-contents__link--active,html .table-of-contents__link:hover{text-shadow:.1px .1px 0 var(--ifm-font-color-base),-.1px -.1px 0 var(--ifm-font-color-base),.1px -.1px 0 var(--ifm-font-color-base),-.1px .1px 0 var(--ifm-font-color-base),-.1px 0 0 var(--ifm-font-color-base),.1px 0 0 var(--ifm-font-color-base),0 .1px 0 var(--ifm-font-color-base),0 -.1px 0 var(--ifm-font-color-base)}.markdown,html .markdown{--ifm-heading-vertical-rhythm-bottom:1}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}.clean-list,.containsTaskList_mC6p,.details_lb9f>summary,.dropdown__menu,.menu__list{list-style:none}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}html{-webkit-font-smoothing:antialiased;color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);text-rendering:optimizelegibility}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width);padding:0 var(--ifm-spacing-horizontal);width:100%}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.px-0,.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.items-center,.menuExternalLink_NmtK,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width);padding:0 var(--ifm-spacing-horizontal);width:100%}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size)}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}html,html .navbar{background-color:var(--ifm-background-color)}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_EoeP .wordWrapButtonIcon_Bwma{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.admonitionHeading_tbUL,.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);color:var(--ifm-font-color-base);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}.button.button--secondary.button--outline:not(.button--active):not(:hover),.text-docusaurusColorBase,html .DocSearch-Button .DocSearch-Search-Icon,html .DocSearch-Hits mark{color:var(--ifm-font-color-base)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card--full-height{height:100%}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child),.pb-0{padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}#nprogress,.dropdown__menu,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);text-decoration:none}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}.footer__links{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item{margin-top:0}.admonitionContent_S0QG>:last-child,.collapsibleContent_i85q>:last-child,.footer__items,html .theme-doc-markdown li:last-child li:last-child{margin-bottom:0}.codeBlockStandalone_MEMb,.p-0,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.navbar-sidebar,.navbar-sidebar__backdrop{opacity:0;top:0;transition-duration:var(--ifm-transition-fast);transition-timing-function:ease-in-out;bottom:0;left:0;visibility:hidden}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color);text-decoration:none}.menu__caret:before,.menu__link--sublist-caret:after{height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;content:"";filter:var(--ifm-menu-link-sublist-icon-filter)}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.flex,.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.h-full,.navbar__logo img,body,html{height:100%}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand,html .theme-doc-sidebar-container>div:first-child>a{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{-webkit-appearance:none;appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);position:fixed;transform:translate3d(-100%,0,0);transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;position:fixed;right:0;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.hover\:shadow-lg:hover,.hover\:shadow-md:hover,.shadow,.shadow-none,html .navbar,html .pagination-nav>a:hover,html[data-theme=dark] .navbar-sidebar__brand{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.transform,html .theme-back-to-top-button{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination__link:hover{text-decoration:none}.pagination-nav{grid-gap:var(--ifm-spacing-horizontal);display:grid;gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover);text-decoration:none}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0;overflow-x:auto;padding-left:0}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.transition,.transition-all{transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.text-gray-1000,html #__docusaurus>div[role=banner]{color:rgb(0 0 0/var(--tw-text-opacity));--tw-text-opacity:1}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec;--ifm-color-primary:#fff;--ifm-color-primary-dark:#e6e6e6;--ifm-color-primary-darker:#d9d9d9;--ifm-color-primary-darkest:#b3b3b3;--ifm-color-primary-light:#fff;--ifm-color-primary-lighter:#fff;--ifm-color-primary-lightest:#fff;--ifm-background-color:#000;--docusaurus-highlighted-code-line-bg:#00000054;--docsearch-modal-background:#000!important;--docsearch-highlight-color:#ffffff70!important;--docsearch-hit-background:#181818ab!important;--docsearch-key-gradient:linear-gradient(-26.5deg,#5d5d5d,#3c3c3c)!important;--docsearch-key-shadow:inset 0 -2px 0 0 #353535,inset 0 0 1px 1px #7a7a7b,0 2px 2px 0 #2d2d2d4d!important}:root{--docusaurus-progress-bar-color:var(--ifm-color-primary);--ifm-color-primary:#1a45f0;--ifm-color-primary-dark:#000;--ifm-color-primary-darker:#000;--ifm-color-primary-darkest:#000;--ifm-color-primary-light:#000;--ifm-color-primary-lighter:#000;--ifm-color-primary-lightest:#000;--ifm-code-font-size:95%;--ifm-breadcrumb-item-background-active:#0000;--ifm-breadcrumb-padding-horizontal:0;--ifm-list-paragraph-margin:0;--ifm-spacing-horizontal:2rem;--ifm-blockquote-border-color:#000;--ifm-menu-link-padding-vertical:0.6rem;--ifm-background-color:#fff;--ifm-footer-link-color:var(--ifm-font-color-base);--ifm-menu-link-sublist-icon:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtMSAxIDQgNCA0LTQiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLW9wYWNpdHk9Ii42NjciIHN0cm9rZS1saW5lY2FwPSJzcXVhcmUiLz48L3N2Zz4=);--docsearch-searchbox-background:#f7f7f7;--docsearch-modal-background:#f7f7f7!important;--ifm-navbar-height:5.563rem;--ifm-navbar-sidebar-width:100vw;--docsearch-highlight-color:#181818ab!important;--aa-primary-color-rgb:0,0,0;--ifm-menu-color-background-active:none;--ifm-menu-color-background-hover:none;--docusaurus-highlighted-code-line-bg:#0000001a;--docusaurus-announcement-bar-height:auto;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300);--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}html{font-feature-settings:"kern","liga","calt","zero" 0;-webkit-font-feature-settings:"kern","liga","calt","zero" 0;-webkit-text-size-adjust:100%;text-size-adjust:100%;-moz-osx-font-smoothing:grayscale;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-kerning:normal;font-variant-ligatures:contextual common-ligatures;text-rendering:optimizeLegibility}@supports (font-variation-settings:normal){html{font-family:Inter var,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}}*,:after,:before{margin:0;--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.inline,.tags_jXut,svg{display:inline}::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }@font-face{font-display:swap;font-family:Inter;font-style:normal;font-weight:400;src:url(/interchain-security/legacy/assets/fonts/Inter-Regular-c8ba52b05a9ef10f47584d08ece2ec5c.woff2) format("woff2"),url(/interchain-security/legacy/assets/fonts/Inter-Regular-8c206db99195777c67691cbba9d64393.woff) format("woff")}@font-face{font-display:swap;font-family:Inter;font-style:normal;font-weight:500;src:url(/interchain-security/legacy/assets/fonts/Inter-Medium-293fd13dbca5a3e450ef1ebfb232a299.woff2) format("woff2"),url(/interchain-security/legacy/assets/fonts/Inter-Medium-9053572c46aeb4b16caafd643a543b8d.woff) format("woff")}@font-face{font-display:swap;font-family:Inter;font-style:normal;font-weight:700;src:url(/interchain-security/legacy/assets/fonts/Inter-Bold-ec64ea577b0349e055ad6646c1d8797a.woff2) format("woff2"),url(/interchain-security/legacy/assets/fonts/Inter-Bold-93c1301bd9f486c573b3d9001c6ec0e4.woff) format("woff")}@font-face{font-display:swap;font-family:Inter;font-style:normal;font-weight:900;src:url(/interchain-security/legacy/assets/fonts/Inter-Black-15ca31c0a2a68f76d2d12055bdf97bd0.woff2) format("woff2"),url(/interchain-security/legacy/assets/fonts/Inter-Black-c6938660eec019fefd684894b6d00900.woff) format("woff")}@font-face{font-display:swap;font-family:Inter var;font-style:oblique 0deg 10deg;font-weight:100 900;src:url(/interchain-security/legacy/assets/fonts/Inter.var-c2fe3cb2b7c746f7966a973d869d21c3.woff2) format("woff2")}@font-face{font-family:JetBrains Mono;font-style:normal;font-weight:400;src:url(/interchain-security/legacy/assets/fonts/JetBrainsMono-Regular-1e66c47aca088de94ae789a48719cb00.woff2) format("woff2")}.absolute{position:absolute}.relative{position:relative}.-left-\[calc\(theme\(space\.5\)\*1\+theme\(space\.7\)-theme\(space\.3\)\)\],html .theme-doc-sidebar-menu li li li .menu__link--active:not(.menu__link--sublist):before{left:-2.5rem}.-left-\[calc\(theme\(space\.5\)\*2\+theme\(space\.7\)-theme\(space\.3\)\)\],html .theme-doc-sidebar-menu li li li li .menu__link--active:not(.menu__link--sublist):before{left:-3.5rem}.-left-\[calc\(theme\(space\.5\)\*3\+theme\(space\.7\)-theme\(space\.3\)\)\],html .theme-doc-sidebar-menu li li li li li .menu__link--active:not(.menu__link--sublist):before{left:-4.5rem}.-left-\[calc\(theme\(space\.5\)\*4\+theme\(space\.7\)-theme\(space\.3\)\)\],html .theme-doc-sidebar-menu li li li li li li .menu__link--active:not(.menu__link--sublist):before{left:-5.5rem}.-left-\[calc\(theme\(space\.5\)\*5\+theme\(space\.7\)-theme\(space\.3\)\)\],html .theme-doc-sidebar-menu li li li li li li li .menu__link--active:not(.menu__link--sublist):before{left:-6.5rem}.-left-\[calc\(theme\(space\.7\)-theme\(space\.3\)\)\]{left:-1.5rem}.bottom-0{bottom:0}.left-0{left:0}.left-3{left:.5rem}.right-3{right:.5rem}.right-8{right:3rem}.top-0{top:0}.top-\[\.2rem\]{top:.2rem}.order-2{order:2}.order-first{order:-9999}.order-last{order:9999}.my-5,html .theme-doc-markdown li>ol,html .theme-doc-markdown li>ul{margin-bottom:1rem;margin-top:1rem}.mb-3{margin-bottom:.5rem}.mb-3\.5{margin-bottom:.625rem}.mb-4{margin-bottom:.75rem}.ml-0{margin-left:0}.ml-4{margin-left:.75rem}.mt-7{margin-top:2rem}.mt-9{margin-top:4rem}.block,.tocCollapsibleContent_vkbj a{display:block}.grid{display:grid}.hidden,html .DocSearch-Button .DocSearch-Button-Keys,html .breadcrumbs__item:first-child>a>svg{display:none}.h-8{height:3rem}.h-auto,.img_ev3q{height:auto}.h-px{height:1px}.w-8{width:3rem}.w-\[2px\]{width:2px}.w-auto{width:auto}.w-full,html .navbar-sidebar{width:100%}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.justify-start{justify-content:flex-start}.justify-center{justify-content:center}.gap-4{gap:.75rem}.rounded{border-radius:1rem}.rounded-s{border-radius:.5rem}.rounded-sm{border-radius:.625rem}.border{border-width:1px}.border-0{border-width:0}.border-t,html .footer{border-top-width:1px}.border-b,html .navbar{border-bottom-width:1px}.border-r{border-right-width:1px}.border-stone-200,[data-theme=dark] .dark\:hover\:border-stone-200:hover{--tw-border-opacity:1;border-color:rgb(231 229 228/var(--tw-border-opacity))}.border-b-docusaurusColorBorder,html .navbar{border-bottom-color:var(--ifm-color-emphasis-200)}.border-t-docusaurusColorBorder{border-top-color:var(--ifm-color-emphasis-200)}.bg-card{--tw-bg-opacity:1;background-color:rgb(247 247 247/var(--tw-bg-opacity))}.bg-fg,html[data-theme=dark] .navbar__toggle,html[data-theme=dark] .theme-doc-toc-mobile{background-color:#181818ab}.bg-gray-1000,html[data-theme=dark] .DocSearch-Footer,html[data-theme=dark] .DocSearch-Modal,html[data-theme=dark] .navbar-sidebar{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}.bg-gray-30{background-color:#00000008}.bg-linkHover{--tw-bg-opacity:1;background-color:rgb(85 85 85/var(--tw-bg-opacity))}.p-6{padding:1.5rem}.pt-\[calc\(theme\(spacing\.7\)-1rem\)\],.py-5,html .navbar{padding-top:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-5{padding-bottom:1rem}.py-5\.5{padding-bottom:1.25rem;padding-top:1.25rem}.pb-5,html .navbar{padding-bottom:1rem}.pb-5\.5{padding-bottom:1.25rem}.pb-7{padding-bottom:2rem}.pb-8{padding-bottom:3rem}.pl-0,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.pl-6{padding-left:1.5rem}.pl-8{padding-left:3rem}.pt-10{padding-top:6rem}.text-center{text-align:center}.font-intervar{font-family:Inter var,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.font-jetbrain,html .theme-code-block{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-3{font-size:1rem}.text-4{font-size:1.3125rem}.text-5{font-size:1.75rem}.text-7{font-size:2.375rem}.text-\[1\.2rem\],html .theme-doc-markdown blockquote,html .theme-doc-markdown ol,html .theme-doc-markdown p,html .theme-doc-markdown ul{font-size:1.2rem}.font-bold{font-weight:700}.font-semibold{font-weight:600}.leading-10{line-height:2.5rem}.leading-6{line-height:1.5rem}.leading-7{line-height:1.75rem}.leading-8{line-height:2rem}.leading-9{line-height:2.25rem}.tracking-tight{letter-spacing:-.025em}.text-inactive{color:#00000054}.text-inactiveLight{color:#ffffff70}.text-slate-500{--tw-text-opacity:1;color:rgb(100 116 139/var(--tw-text-opacity))}.hover\:underline:hover,.underline,html .footer__link-item:hover,html .theme-doc-markdown a{text-decoration-line:underline}.no-underline,html .card-section a{text-decoration-line:none}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow-none,html .navbar,html[data-theme=dark] .navbar-sidebar__brand{--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000}.grayscale{--tw-grayscale:grayscale(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter}.transition-all{transition-property:all}.duration-200{transition-duration:.2s}html #__docusaurus>div[role=banner]{background-color:#00000008;font-weight:400}html #__docusaurus>div[role=banner] a{font-size:.8125rem;text-decoration-line:none;width:100%}html .navbar{height:auto}html .DocSearch-Button,html .navbar__toggle{background-color:rgb(247 247 247/var(--tw-bg-opacity));height:3rem;width:3rem;--tw-bg-opacity:1}html .navbar__toggle{align-items:center;border-radius:.5rem;display:flex;justify-content:center}html .navbar__brand+*{margin-left:auto}html .menu__link,html .navbar__link--active{--tw-text-opacity:1;color:rgb(85 85 85/var(--tw-text-opacity))}html .navbar__items:not(:last-child){justify-content:space-between}html .navbar__items:not(:last-child) button{margin-right:0;order:2}html .navbar__items--right>:last-child{right:3.25rem}html[data-theme=dark] .menu__link,html[data-theme=dark] .navbar__item{color:#ffffffab}html .github-icon:hover{opacity:.5}html .DocSearch-Button{border-radius:.625rem;color:#00000054;justify-content:center;margin-right:.5rem}html .DocSearch-Button .DocSearch-Button-Placeholder{padding-right:6rem}html .DocSearch-Logo path{fill:var(--ifm-font-color-base)}html .navbar-sidebar__brand{height:auto;padding-left:1.5rem;padding-right:1.5rem}html .navbar-sidebar__item{padding-left:1.5rem;padding-right:1.5rem;width:100%}html .navbar-sidebar__back{display:none;padding-left:0;padding-right:0}html .navbar-sidebar__close{--tw-bg-opacity:1;align-items:center;background-color:rgb(0 0 0/var(--tw-bg-opacity));border-radius:.5rem;display:flex;height:3rem;justify-content:center;margin-left:0;width:3rem}html .navbar-sidebar__close>svg>g{stroke:#fff}html[data-theme=dark] .navbar-sidebar__brand{position:relative}html[data-theme=dark] .navbar-sidebar__brand:after{--tw-bg-opacity:1;background-color:rgb(85 85 85/var(--tw-bg-opacity));bottom:0;content:"";display:block;height:1px;left:0;margin-left:1.5rem;margin-right:1.5rem;position:absolute;right:.5rem}html[data-theme=dark] .navbar-sidebar__close{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}html[data-theme=dark] .navbar-sidebar__close>svg>g{stroke:#000}html[data-theme=dark] .DocSearch-Button{background-color:#181818ab;color:#ffffff70}html[data-theme=dark] .DocSearch-Button-Key{border-color:#ffffff70;color:#ffffff70}html .breadcrumbs__item:first-child>a:after{content:"Docs"}html .breadcrumbs__item:not(:last-child):after{background-image:none;content:">"}html .theme-doc-toc-mobile{--tw-bg-opacity:1;background-color:rgb(247 247 247/var(--tw-bg-opacity));border-radius:1rem;padding:1.25rem 1.5rem 0}html .theme-doc-toc-mobile>button{display:flex;justify-content:space-between;padding:0 0 1.25rem}html .theme-doc-toc-mobile>button:after{background-image:var(--ifm-menu-link-sublist-icon);background-size:70%;margin-left:1rem;order:9999}html .theme-doc-toc-mobile ul li{margin:1rem 0}html[data-theme=dark] .theme-doc-sidebar-menu .menu__list:before{background-color:#ffffff70}html .theme-doc-sidebar-menu{font-weight:400}html .theme-doc-sidebar-menu .menu__list{padding-left:0;position:relative}html .theme-doc-sidebar-menu .menu__list:before{background-color:#00000012;content:"";display:block;height:100%;left:.5rem;position:absolute;top:0;width:2px}#__docusaurus-base-url-issue-banner-container,.themedImage_ToTc,[data-theme=dark] .lightToggleIcon_pyhR,[data-theme=light] .darkToggleIcon_wfgR,html .footer__col:first-child .footer__title,html .footer__link-item>svg,html .menu__link>svg,html .theme-doc-sidebar-menu .menu__list ul:before,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j{display:none}html .theme-doc-sidebar-menu .menu__link{padding-left:0;padding-right:1rem}html .theme-doc-sidebar-menu .menu__link--active:not(.menu__link--sublist){color:var(--ifm-font-color-base);font-weight:500}html .theme-doc-sidebar-menu li li{padding-left:2rem}html .theme-doc-sidebar-menu li li .menu__link--active:not(.menu__link--sublist){color:var(--ifm-font-color-base);font-weight:500;position:relative}html .theme-doc-sidebar-menu li li .menu__link--active:not(.menu__link--sublist):before{background-color:var(--ifm-font-color-base);content:"";display:block;height:100%;left:-1.5rem;position:absolute;top:0;width:2px}html .theme-doc-sidebar-menu li li li{padding-left:1rem}html .theme-doc-sidebar-item-link .menu__link[target=_blank]:after{content:"\2197";margin-left:.25rem}html .menu__link:hover{color:var(--ifm-font-color-base)}html .menu__link--sublist-caret{display:flex}html .menu__link--sublist-caret:after{background-repeat:no-repeat;background-size:16px;margin-left:0;margin-right:.75rem;order:-9999}html .menu__list-item--collapsed .menu__caret:before,html .menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(0)}html[data-theme=dark] .pagination-nav>a{--tw-border-opacity:1;background-color:#181818ab;border-color:rgb(41 37 36/var(--tw-border-opacity))}html .pagination-nav{margin-top:4rem;padding-bottom:2rem}html .pagination-nav>a{--tw-border-opacity:1;border-color:rgb(231 229 228/var(--tw-border-opacity));border-radius:.625rem;grid-column:span 2/span 2;padding:1.5rem}html .pagination-nav>a:hover{--tw-border-opacity:1;--tw-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);border-color:rgb(214 211 209/var(--tw-border-opacity))}html .pagination-nav .pagination-nav__link--next{text-align:left}html .pagination-nav .pagination-nav__sublabel{--tw-text-opacity:1;color:rgb(100 116 139/var(--tw-text-opacity));font-size:1rem;margin-bottom:.625rem}[data-theme=dark] .dark\:text-docusaurusColorBase,[data-theme=dark] html .pagination-nav .pagination-nav__sublabel{color:var(--ifm-font-color-base)}html .pagination-nav .pagination-nav__label{font-size:1.3125rem;font-weight:600}html .footer{background-color:var(--ifm-background-color);border-top-color:var(--ifm-color-emphasis-200);margin-bottom:6rem;padding-top:6rem}html .footer__bottom{margin:0 calc(var(--ifm-spacing-horizontal)*-1)}html .footer__copyright{font-size:.8125rem;margin-top:4rem;text-align:center}html .footer__col:not(:first-child){flex-basis:50%}html .theme-back-to-top-button{--tw-rotate:180deg}html .theme-back-to-top-button:after{width:50%}html .theme-code-block{margin-top:.5rem}html .markdown{--ifm-h1-vertical-rhythm-bottom:1}html .theme-doc-markdown{border-bottom-color:#00000012;border-bottom-width:1px;margin-top:2rem;padding-bottom:3rem}.before\:border-current:before,html .theme-doc-markdown ul li li:before{border-color:currentColor;content:var(--tw-content)}html .theme-doc-markdown h1{font-size:2.375rem;font-weight:700;letter-spacing:-.025em;line-height:2.5rem;padding-top:1rem}html .theme-doc-markdown h2{font-size:1.75rem;font-weight:700;letter-spacing:-.025em;line-height:2.25rem}html .theme-doc-markdown h3{font-size:1.3125rem;font-weight:600;letter-spacing:-.025em;line-height:2rem}html .theme-doc-markdown h4{font-size:1rem;font-weight:600;letter-spacing:-.025em;line-height:1.75rem}html .theme-doc-markdown h5{font-size:1rem;font-weight:600;letter-spacing:.025em;line-height:1.5rem}html .theme-doc-markdown p{line-height:1.625}html .theme-doc-markdown code{border-width:0;padding-left:.5rem;padding-right:.5rem}html .theme-doc-markdown blockquote{margin-bottom:2rem;margin-top:2rem}html .theme-doc-markdown ol,html .theme-doc-markdown ul{margin-bottom:1.5rem;margin-top:1.5rem}html .theme-doc-markdown ul li{margin-bottom:.75rem;padding-left:1.5rem;position:relative}html .theme-doc-markdown ul li:before{background-color:currentColor;content:var(--tw-content);display:block;height:4px;left:0;position:absolute;top:.5em;width:4px}html .theme-doc-markdown ul li li:before{background-color:initial;border-width:1px}.last\:mb-6:last-child,html .theme-doc-markdown ul li li:last-child{margin-bottom:1.5rem}html .theme-doc-markdown ol{counter-reset:a;list-style-type:none}html .theme-doc-markdown ol>li{margin-bottom:.75rem;padding-left:3rem;position:relative}html .theme-doc-markdown ol>li:before{content:counters(a,".",decimal-leading-zero) ".";counter-increment:a;display:flex;font-size:1rem;font-weight:600;left:0;letter-spacing:-.025em;position:absolute;top:.2rem}html .theme-doc-markdown ol ol{counter-reset:b}html .theme-doc-markdown ol ol>li:before{content:counters(b,".",decimal-leading-zero) ".";counter-increment:b}.before\:absolute:before{content:var(--tw-content);position:absolute}.before\:left-0:before{content:var(--tw-content);left:0}.before\:top-\[calc\(1em\/2\)\]:before{content:var(--tw-content);top:.5em}.before\:block:before{content:var(--tw-content);display:block}.before\:h-\[4px\]:before{content:var(--tw-content);height:4px}.before\:w-\[4px\]:before{content:var(--tw-content);width:4px}.before\:border:before{border-width:1px;content:var(--tw-content)}.before\:bg-current:before{background-color:currentColor;content:var(--tw-content)}.hover\:border-stone-300:hover{--tw-border-opacity:1;border-color:rgb(214 211 209/var(--tw-border-opacity))}.hover\:shadow-lg:hover{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}[data-theme=dark] .dark\:border-stone-800{--tw-border-opacity:1;border-color:rgb(41 37 36/var(--tw-border-opacity))}[data-theme=dark] .dark\:bg-neutral-900{--tw-bg-opacity:1;background-color:rgb(23 23 23/var(--tw-bg-opacity))}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit;text-decoration:underline}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.toggleButton_gllP{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_aARS{cursor:not-allowed}.darkNavbarColorModeToggle_X3D1:hover{background:var(--ifm-color-gray-800)}[data-theme=dark] .themedImage--dark_i4oU,[data-theme=light] .themedImage--light_HNdA{display:initial}.iconExternalLink_nPIU{margin-left:.3rem}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}.errorBoundaryError_a6uf{color:red;white-space:pre-wrap}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.footerLogoLink_BH7S:hover,.hash-link:focus,:hover>.hash-link{opacity:1}.mainWrapper_z2l0{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color);text-decoration:none}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.lastUpdated_vwxv{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem);overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.anchorWithStickyNavbar_LWe7{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_WYt5{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup__atx button{opacity:.4}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:c;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(c);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{fill:currentColor;height:inherit;left:0;opacity:inherit;position:absolute;top:0;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.admonition_LlT9{margin-bottom:1em}.admonitionHeading_tbUL{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.3rem}.admonitionHeading_tbUL code{text-transform:none}.admonitionIcon_kALy{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_kALy svg{fill:var(--ifm-alert-foreground-color);display:inline-block;height:1.6em;width:1.6em}.breadcrumbHomeIcon_YNFT{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.collapseSidebarButton_PEFL{display:none;margin:0}.docSidebarContainer_b6E3,.sidebarLogo_isFc{display:none}.docMainContainer_gTbr,.docPage__5DB{display:flex;width:100%}.docPage__5DB{flex:1 0}.docsWrapper_BCFX{display:flex;flex:1 0 auto}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_m80_{background-color:var(--docusaurus-collapse-button-bg)}.tocMobile_ITEo,html .navbar__toggle{display:none}html .navbar__items:not(:last-child){justify-content:flex-start;padding-left:.5rem;padding-right:.5rem}html .DocSearch-Button{justify-content:space-between;width:auto}html .theme-doc-breadcrumbs{padding-top:1rem}html .theme-doc-sidebar-container{border-right-color:var(--ifm-color-emphasis-200);border-right-width:1px;margin-left:.75rem}html .pagination-nav>a{grid-column:span 1/span 1}.lastUpdated_vwxv,html .pagination-nav .pagination-nav__link--next{text-align:right}html .footer__col:not(:first-child){flex-basis:0}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.searchBox_ZlJk{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.docItemCol_VOVn{max-width:75%!important}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_BlDH,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_m80_:focus,.expandButton_m80_:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{opacity:0;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_m80_{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_BlDH{transform:rotate(180deg)}.docSidebarContainer_b6E3{border-right:1px solid var(--ifm-toc-border-color);-webkit-clip-path:inset(0);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_b3ry{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_Xe31{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_gTbr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_Uz_u{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_czyv{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}}@media (min-width:1024px){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.searchBox_ZlJk{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.docItemContainer_F8PC{padding:0 .3rem}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file diff --git a/legacy/assets/files/throttle_retry-5ae73abd8a25d0235e6447e71abd730b.go b/legacy/assets/files/throttle_retry-5ae73abd8a25d0235e6447e71abd730b.go new file mode 100644 index 0000000000..7f8d85191d --- /dev/null +++ b/legacy/assets/files/throttle_retry-5ae73abd8a25d0235e6447e71abd730b.go @@ -0,0 +1,108 @@ +package keeper + +import ( + "fmt" + + sdktypes "github.com/cosmos/cosmos-sdk/types" + + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" +) + +// +// Throttling with retries follows a finite-state machine design: +// +// 2 states: "No Slash" and "Standby". +// Initial State: "No Slash" +// Transition Event: ("No Slash", Slash packet sent) => ("Standby") +// Transition Event: ("Standby", V1Result ack received) => ("No Slash") +// Transition Event: ("Standby", Slash packet successfully handled) => ("No Slash") +// Internal Transition Event: ("Standby", Slash packet bounced) => ("Standby", with SlashRecord.WaitingOnReply = false) +// Transition Event: ("Standby", Retry sent) => ("Standby", new cycle) +// +// Description in words: +// +// 1. "No slash": If no slash record exists, the consumer is permitted to send packets from the pending packets queue. +// The consumer starts in this state from genesis. +// +// 2. On the event that a slash packet is obtained from the head of the pending packets queue and sent, +// a consumer transitions from "No Slash" to "Standby". A slash record is created upon entry to this state, +// and the consumer is now restricted from sending anymore packets. +// +// The slash packet remains at the head of the pending packets queue within the "Standby" state. +// +// - If the consumer receives a V1Result ack from the provider, +// OR if the consumer receives an ack from the provider that the slash packet was successfully handled, +// the consumer transitions from "Standby" to "No Slash". +// The slash record is cleared upon this transition, and the slash packet is popped from the pending packets queue. +// +// - Else if the consumer receives an ack from the provider that the slash packet was bounced (not handled), +// then SlashRecord.WaitingOnReply is set false, and the consumer retries sending the slash packet after a delay period. +// +// Once a retry is sent, the consumer enters a new cycle of the "Standby" state and the process repeats. +// +// This design is implemented below, and in relay.go under SendPackets() and OnAcknowledgementPacket(). +// + +// PacketSendingPermitted returns whether the consumer is allowed to send packets +// from the pending packets queue. +func (k Keeper) PacketSendingPermitted(ctx sdktypes.Context) bool { + record, found := k.GetSlashRecord(ctx) + if !found { + // no slash record exists, send is permitted + return true + } + if record.WaitingOnReply { + // We are waiting on a reply from provider, block sending + return false + } + // If retry delay period has elapsed, we can send again + return ctx.BlockTime().After(record.SendTime.Add(k.GetRetryDelayPeriod(ctx))) +} + +func (k Keeper) UpdateSlashRecordOnSend(ctx sdktypes.Context) { + record := consumertypes.NewSlashRecord( + ctx.BlockTime(), // sendTime + true, // waitingOnReply + ) + // We don't mind overwriting here, since this is either a retry or the first time we send a slash + k.SetSlashRecord(ctx, record) +} + +func (k Keeper) UpdateSlashRecordOnBounce(ctx sdktypes.Context) { + record, found := k.GetSlashRecord(ctx) + if !found { + // This should never happen + panic("could not find slash record, but reply was received from provider") + } + record.WaitingOnReply = false + k.SetSlashRecord(ctx, record) +} + +func (k Keeper) GetSlashRecord(ctx sdktypes.Context) (record consumertypes.SlashRecord, found bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(consumertypes.SlashRecordKey()) + if bz == nil { + return record, false + } + err := record.Unmarshal(bz) + if err != nil { + // This should never happen + panic(fmt.Sprintf("could not unmarshal slash record: %v", err)) + } + return record, true +} + +func (k Keeper) SetSlashRecord(ctx sdktypes.Context, record consumertypes.SlashRecord) { + store := ctx.KVStore(k.storeKey) + bz, err := record.Marshal() + if err != nil { + // This should never happen + panic(fmt.Sprintf("could not marshal slash record: %v", err)) + } + store.Set(consumertypes.SlashRecordKey(), bz) +} + +func (k Keeper) ClearSlashRecord(ctx sdktypes.Context) { + store := ctx.KVStore(k.storeKey) + store.Delete(consumertypes.SlashRecordKey()) +} diff --git a/legacy/assets/fonts/Inter-Black-15ca31c0a2a68f76d2d12055bdf97bd0.woff2 b/legacy/assets/fonts/Inter-Black-15ca31c0a2a68f76d2d12055bdf97bd0.woff2 new file mode 100644 index 0000000000..68f64c9ed9 Binary files /dev/null and b/legacy/assets/fonts/Inter-Black-15ca31c0a2a68f76d2d12055bdf97bd0.woff2 differ diff --git a/legacy/assets/fonts/Inter-Black-c6938660eec019fefd684894b6d00900.woff b/legacy/assets/fonts/Inter-Black-c6938660eec019fefd684894b6d00900.woff new file mode 100644 index 0000000000..a18593a096 Binary files /dev/null and b/legacy/assets/fonts/Inter-Black-c6938660eec019fefd684894b6d00900.woff differ diff --git a/legacy/assets/fonts/Inter-Bold-93c1301bd9f486c573b3d9001c6ec0e4.woff b/legacy/assets/fonts/Inter-Bold-93c1301bd9f486c573b3d9001c6ec0e4.woff new file mode 100644 index 0000000000..eaf3d4bfd7 Binary files /dev/null and b/legacy/assets/fonts/Inter-Bold-93c1301bd9f486c573b3d9001c6ec0e4.woff differ diff --git a/legacy/assets/fonts/Inter-Bold-ec64ea577b0349e055ad6646c1d8797a.woff2 b/legacy/assets/fonts/Inter-Bold-ec64ea577b0349e055ad6646c1d8797a.woff2 new file mode 100644 index 0000000000..2846f29cc8 Binary files /dev/null and b/legacy/assets/fonts/Inter-Bold-ec64ea577b0349e055ad6646c1d8797a.woff2 differ diff --git a/legacy/assets/fonts/Inter-Medium-293fd13dbca5a3e450ef1ebfb232a299.woff2 b/legacy/assets/fonts/Inter-Medium-293fd13dbca5a3e450ef1ebfb232a299.woff2 new file mode 100644 index 0000000000..f92498a2ec Binary files /dev/null and b/legacy/assets/fonts/Inter-Medium-293fd13dbca5a3e450ef1ebfb232a299.woff2 differ diff --git a/legacy/assets/fonts/Inter-Medium-9053572c46aeb4b16caafd643a543b8d.woff b/legacy/assets/fonts/Inter-Medium-9053572c46aeb4b16caafd643a543b8d.woff new file mode 100644 index 0000000000..d546843f28 Binary files /dev/null and b/legacy/assets/fonts/Inter-Medium-9053572c46aeb4b16caafd643a543b8d.woff differ diff --git a/legacy/assets/fonts/Inter-Regular-8c206db99195777c67691cbba9d64393.woff b/legacy/assets/fonts/Inter-Regular-8c206db99195777c67691cbba9d64393.woff new file mode 100644 index 0000000000..62d3a61871 Binary files /dev/null and b/legacy/assets/fonts/Inter-Regular-8c206db99195777c67691cbba9d64393.woff differ diff --git a/legacy/assets/fonts/Inter-Regular-c8ba52b05a9ef10f47584d08ece2ec5c.woff2 b/legacy/assets/fonts/Inter-Regular-c8ba52b05a9ef10f47584d08ece2ec5c.woff2 new file mode 100644 index 0000000000..6c2b6893d5 Binary files /dev/null and b/legacy/assets/fonts/Inter-Regular-c8ba52b05a9ef10f47584d08ece2ec5c.woff2 differ diff --git a/legacy/assets/fonts/Inter.var-c2fe3cb2b7c746f7966a973d869d21c3.woff2 b/legacy/assets/fonts/Inter.var-c2fe3cb2b7c746f7966a973d869d21c3.woff2 new file mode 100644 index 0000000000..365eedc50c Binary files /dev/null and b/legacy/assets/fonts/Inter.var-c2fe3cb2b7c746f7966a973d869d21c3.woff2 differ diff --git a/legacy/assets/fonts/JetBrainsMono-Regular-1e66c47aca088de94ae789a48719cb00.woff2 b/legacy/assets/fonts/JetBrainsMono-Regular-1e66c47aca088de94ae789a48719cb00.woff2 new file mode 100644 index 0000000000..8c862e334d Binary files /dev/null and b/legacy/assets/fonts/JetBrainsMono-Regular-1e66c47aca088de94ae789a48719cb00.woff2 differ diff --git a/legacy/assets/images/cometmock_matrix_test-714f36252aff9df4214823e3145d0ef5.png b/legacy/assets/images/cometmock_matrix_test-714f36252aff9df4214823e3145d0ef5.png new file mode 100644 index 0000000000..740005aed1 Binary files /dev/null and b/legacy/assets/images/cometmock_matrix_test-714f36252aff9df4214823e3145d0ef5.png differ diff --git a/legacy/assets/images/hypha-consumer-start-process-2141109f76c584706dd994d7965fd692.svg b/legacy/assets/images/hypha-consumer-start-process-2141109f76c584706dd994d7965fd692.svg new file mode 100644 index 0000000000..1be7b61b7d --- /dev/null +++ b/legacy/assets/images/hypha-consumer-start-process-2141109f76c584706dd994d7965fd692.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/legacy/assets/images/ics_changeover_timeline_stride-9bcad1834fef24a0fea7f2c80c9ccd71.png b/legacy/assets/images/ics_changeover_timeline_stride-9bcad1834fef24a0fea7f2c80c9ccd71.png new file mode 100644 index 0000000000..2cec12a6be Binary files /dev/null and b/legacy/assets/images/ics_changeover_timeline_stride-9bcad1834fef24a0fea7f2c80c9ccd71.png differ diff --git a/legacy/assets/images/matrix_e2e_tests-30681305077301daaf3097e1952b54bb.png b/legacy/assets/images/matrix_e2e_tests-30681305077301daaf3097e1952b54bb.png new file mode 100644 index 0000000000..4c94db81a3 Binary files /dev/null and b/legacy/assets/images/matrix_e2e_tests-30681305077301daaf3097e1952b54bb.png differ diff --git a/legacy/assets/js/00147ff4.3569d3ae.js b/legacy/assets/js/00147ff4.3569d3ae.js new file mode 100644 index 0000000000..2f9997b829 --- /dev/null +++ b/legacy/assets/js/00147ff4.3569d3ae.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2110],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>m});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),h=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=h(e.components);return r.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),d=h(n),p=a,m=d["".concat(c,".").concat(p)]||d[p]||u[p]||o;return n?r.createElement(m,i(i({ref:t},l),{},{components:n})):r.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=p;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:a,i[1]=s;for(var h=2;h{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>h});var r=n(7462),a=(n(7294),n(3905));const o={sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},i=void 0,s={unversionedId:"frequently-asked-questions",id:"frequently-asked-questions",title:"Frequently Asked Questions",description:"What is the meaning of Validator Set Replication?",source:"@site/docs/frequently-asked-questions.md",sourceDirName:".",slug:"/faq",permalink:"/interchain-security/legacy/faq",draft:!1,tags:[],version:"current",sidebarPosition:5,frontMatter:{sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},sidebar:"tutorialSidebar",previous:{title:"Joining Stride",permalink:"/interchain-security/legacy/validators/joining-stride"},next:{title:"ADRs",permalink:"/interchain-security/legacy/adrs/intro"}},c={},h=[{value:"What is the meaning of Validator Set Replication?",id:"what-is-the-meaning-of-validator-set-replication",level:2},{value:"What is a consumer chain?",id:"what-is-a-consumer-chain",level:2},{value:"What happens to consumer if provider is down?",id:"what-happens-to-consumer-if-provider-is-down",level:2},{value:"What happens to provider if consumer is down?",id:"what-happens-to-provider-if-consumer-is-down",level:2},{value:"Can I run the provider and consumer chains on the same machine?",id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine",level:2},{value:"Can the consumer chain have its own token?",id:"can-the-consumer-chain-have-its-own-token",level:2},{value:"How are Tx fees paid on consumer?",id:"how-are-tx-fees-paid-on-consumer",level:2},{value:"Are there any restrictions the consumer chains need to abide by?",id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by",level:2},{value:"What's in it for the validators and stakers?",id:"whats-in-it-for-the-validators-and-stakers",level:2},{value:"Can the consumer chain have its own governance?",id:"can-the-consumer-chain-have-its-own-governance",level:2},{value:"Can validators opt-out of replicated security?",id:"can-validators-opt-out-of-replicated-security",level:2},{value:"How does Equivocation Governance Slashing work?",id:"how-does-equivocation-governance-slashing-work",level:2},{value:"Can Consumer Chains perform Software Upgrades?",id:"can-consumer-chains-perform-software-upgrades",level:2},{value:"How can I connect to the testnets?",id:"how-can-i-connect-to-the-testnets",level:2},{value:"How do I start using ICS?",id:"how-do-i-start-using-ics",level:2},{value:"Which relayers are supported?",id:"which-relayers-are-supported",level:2},{value:"How does key delegation work in ICS?",id:"how-does-key-delegation-work-in-ics",level:2}],l={toc:h},d="wrapper";function u(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"what-is-the-meaning-of-validator-set-replication"},"What is the meaning of Validator Set Replication?"),(0,a.kt)("p",null,"VSR simply means that the same validator set is used to secure both the provider and consumer chains. VSR is ensured through ICS protocol which keeps consumers up to date with the validator set of the provider."),(0,a.kt)("h2",{id:"what-is-a-consumer-chain"},"What is a consumer chain?"),(0,a.kt)("p",null,"Consumer chain is blockchain operated by the same validator operators as the provider chain. The ICS protocol ensures the validator set replication properties (informs consumer chain about the current state of the validator set on the provider)"),(0,a.kt)("p",null,"Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements."),(0,a.kt)("h2",{id:"what-happens-to-consumer-if-provider-is-down"},"What happens to consumer if provider is down?"),(0,a.kt)("p",null,"In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set."),(0,a.kt)("p",null,"The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness."),(0,a.kt)("p",null,"However, if the ",(0,a.kt)("inlineCode",{parentName:"p"},"trusting_period")," (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain.\nThis means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about."),(0,a.kt)("p",null,'Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point.\nAt the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.'),(0,a.kt)("h2",{id:"what-happens-to-provider-if-consumer-is-down"},"What happens to provider if consumer is down?"),(0,a.kt)("p",null,"Consumer chains do not impact the provider chain.\nThe ICS protocol is concerned only with validator set replication and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events)."),(0,a.kt)("h2",{id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine"},"Can I run the provider and consumer chains on the same machine?"),(0,a.kt)("p",null,"Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation."),(0,a.kt)("h2",{id:"can-the-consumer-chain-have-its-own-token"},"Can the consumer chain have its own token?"),(0,a.kt)("p",null,"As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees."),(0,a.kt)("h2",{id:"how-are-tx-fees-paid-on-consumer"},"How are Tx fees paid on consumer?"),(0,a.kt)("p",null,"The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations."),(0,a.kt)("h2",{id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by"},"Are there any restrictions the consumer chains need to abide by?"),(0,a.kt)("p",null,"No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way.\nThe only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain."),(0,a.kt)("h2",{id:"whats-in-it-for-the-validators-and-stakers"},"What's in it for the validators and stakers?"),(0,a.kt)("p",null,"The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by ",(0,a.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction"),". The rewards are distributed (sent to the provider) every ",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission"),"."),(0,a.kt)("admonition",{type:"note"},(0,a.kt)("p",{parentName:"admonition"}," ",(0,a.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission")," are parameters defined in the ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," used to create the consumer chain. These parameters can be changed via consumer chain governance.")),(0,a.kt)("h2",{id:"can-the-consumer-chain-have-its-own-governance"},"Can the consumer chain have its own governance?"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Yes.")),(0,a.kt)("p",null,'In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.'),(0,a.kt)("p",null,"Validators can also be representatives but representatives are not required to run validator nodes."),(0,a.kt)("p",null,"This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance."),(0,a.kt)("h2",{id:"can-validators-opt-out-of-replicated-security"},"Can validators opt-out of replicated security?"),(0,a.kt)("p",null,"At present, the validators cannot opt-out of validating consumer chains."),(0,a.kt)("p",null,"There are multiple opt-out mechanisms under active research."),(0,a.kt)("h2",{id:"how-does-equivocation-governance-slashing-work"},"How does Equivocation Governance Slashing work?"),(0,a.kt)("p",null,"To avoid potential attacks directed at provider chain validators, a new mechanism was introduced:"),(0,a.kt)("p",null,"When a validator double-signs on the consumer chain, a special type of slash packet is relayed to the provider chain. The provider will store information about the double signing validator and allow a governance proposal to be submitted.\nIf the double-signing proposal passes, the offending validator will be slashed on the provider chain and tombstoned. Tombstoning will permanently exclude the validator from the active set of the provider."),(0,a.kt)("admonition",{type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"An equivocation proposal cannot be submitted for a validator that did not double sign on any of the consumer chains.")),(0,a.kt)("h2",{id:"can-consumer-chains-perform-software-upgrades"},"Can Consumer Chains perform Software Upgrades?"),(0,a.kt)("p",null,"Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM)."),(0,a.kt)("p",null,"Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module."),(0,a.kt)("h2",{id:"how-can-i-connect-to-the-testnets"},"How can I connect to the testnets?"),(0,a.kt)("p",null,"Check out the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/validators/joining-testnet"},"Joining Replicated Security testnet")," section."),(0,a.kt)("h2",{id:"how-do-i-start-using-ics"},"How do I start using ICS?"),(0,a.kt)("p",null,"To become a consumer chain use this ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/onboarding"},"checklist")," and check the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/app-integration"},"App integration section")),(0,a.kt)("h2",{id:"which-relayers-are-supported"},"Which relayers are supported?"),(0,a.kt)("p",null,"Currently supported versions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Hermes 1.4.1"),(0,a.kt)("li",{parentName:"ul"},"Support for the CCV module was added to the Go ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/relayer"},"relayer")," in v2.2.0 but v2.4.0 has significant performance fixes which makes it the earliest suggested version to use.")),(0,a.kt)("h2",{id:"how-does-key-delegation-work-in-ics"},"How does key delegation work in ICS?"),(0,a.kt)("p",null,"You can check the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/features/key-assignment"},"Key Assignment Guide")," for specific instructions."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/01ff7a4e.8ba03b4e.js b/legacy/assets/js/01ff7a4e.8ba03b4e.js new file mode 100644 index 0000000000..43f3af82a7 --- /dev/null +++ b/legacy/assets/js/01ff7a4e.8ba03b4e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8219],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>v});var i=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function r(e){for(var n=1;n=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=i.createContext({}),u=function(e){var n=i.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):r(r({},n),e)),t},p=function(e){var n=u(e.components);return i.createElement(l.Provider,{value:n},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},h=i.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=u(t),h=o,v=d["".concat(l,".").concat(h)]||d[h]||c[h]||a;return t?i.createElement(v,r(r({ref:n},p),{},{components:t})):i.createElement(v,r({ref:n},p))}));function v(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,r=new Array(a);r[0]=h;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:o,r[1]=s;for(var u=2;u{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>r,default:()=>c,frontMatter:()=>a,metadata:()=>s,toc:()=>u});var i=t(7462),o=(t(7294),t(3905));const a={sidebar_position:2,title:"ADR Template"},r="ADR 007: Pause validator unbonding during equivocation proposal",s={unversionedId:"adrs/adr-007-pause-unbonding-on-eqv-prop",id:"version-v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop",title:"ADR Template",description:"Changelog",source:"@site/versioned_docs/version-v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop.md",sourceDirName:"adrs",slug:"/adrs/adr-007-pause-unbonding-on-eqv-prop",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"ADR Template"},sidebar:"tutorialSidebar",previous:{title:"ADRs",permalink:"/interchain-security/legacy/v3.2.0/adrs/intro"},next:{title:"ADR Template",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-template"}},l={},u=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"How",id:"how",level:3},{value:"When pause",id:"when-pause",level:3},{value:"When unpause",id:"when-unpause",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],p={toc:u},d="wrapper";function c(e){let{components:n,...t}=e;return(0,o.kt)(d,(0,i.Z)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"adr-007-pause-validator-unbonding-during-equivocation-proposal"},"ADR 007: Pause validator unbonding during equivocation proposal"),(0,o.kt)("h2",{id:"changelog"},"Changelog"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"2023-05-16: Initial Draft")),(0,o.kt)("h2",{id:"status"},"Status"),(0,o.kt)("p",null,"Proposed"),(0,o.kt)("h2",{id:"context"},"Context"),(0,o.kt)("p",null,"Currently, if an equivocation slashing proposal is created after more than one\nweek has passed since the equivocation, it is possible that the validator in\nquestion could unbond and get away without being slashed, since the unbonding\nperiod is 3 weeks, and the voting period is 2 weeks. For this reason, it might\nbe good to pause unbondings for validators named in an equivocation slashing\nproposal until the proposal's voting period is over."),(0,o.kt)("h2",{id:"decision"},"Decision"),(0,o.kt)("h3",{id:"how"},"How"),(0,o.kt)("p",null,"Pausing the unbonding period is already possible thanks to the changes in the\n",(0,o.kt)("inlineCode",{parentName:"p"},"staking")," module of the cosmos-sdk:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"stakingKeeper.PutUnbondingOnHold")," pauses an unbonding period"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"stakingKeeper.UnbondingCanComplete")," unpauses an unbonding period")),(0,o.kt)("p",null,"These methods use a reference counter under the hood, that gets incremented\nevery time ",(0,o.kt)("inlineCode",{parentName:"p"},"PutUnbondingOnHold")," is called, and decreased when\n",(0,o.kt)("inlineCode",{parentName:"p"},"UnbondingCanComplete")," is called instead. A specific unbonding is considered\nfully unpaused when its underlying reference counter reaches 0. Therefore, as\nlong as we safeguard consistency - i.e. we make sure we eventually decrement\nthe reference counter for each time we have incremented it - we can safely use\nthis existing mechanism without conflicts with the ",(0,o.kt)("em",{parentName:"p"},"Completion of Unbonding\nOperations")," system."),(0,o.kt)("h3",{id:"when-pause"},"When pause"),(0,o.kt)("p",null,"The unbonding period (if there is any unbonding) should be paused once an\nequivocation proposal enters the voting period. For that, the ",(0,o.kt)("inlineCode",{parentName:"p"},"gov")," module's\nhook ",(0,o.kt)("inlineCode",{parentName:"p"},"AfterProposalDeposit")," can be used. "),(0,o.kt)("p",null,"If the hook is triggered with a an equivocation proposal in voting period, then\nfor each equivocation of the proposal, the unbonding operations of the related\nvalidator that were initiated after the equivocation block time must be paused"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"i.e. the underlying reference counter has to be increased.")),(0,o.kt)("p",null,"Note that even after the voting period has started, a proposal can receive\nadditional deposits. The hook is triggered however at arrival of a deposit, so\na check to verify that the proposal is not already in voting period is\nrequired."),(0,o.kt)("h3",{id:"when-unpause"},"When unpause"),(0,o.kt)("p",null,"We can use a ",(0,o.kt)("inlineCode",{parentName:"p"},"gov")," module's hook also here and it is\n",(0,o.kt)("inlineCode",{parentName:"p"},"AfterProposalVotingPeriodEnded"),"."),(0,o.kt)("p",null,"If the hook is triggered with an equivocation proposal, then for each\nassociated equivocation, the unbonding operations of the related validator that\nwere initiated between the equivocation block time and the start of the\nproposal voting period must be unpaused - i.e. decrease the underlying\nreference counter - regardless of the proposal outcome."),(0,o.kt)("h2",{id:"consequences"},"Consequences"),(0,o.kt)("h3",{id:"positive"},"Positive"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Validators subject to an equivocation proposal cannot finish unbonding\ntheir tokens before the end of the voting period.")),(0,o.kt)("h3",{id:"negative"},"Negative"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"A malicious consumer chain could forge slash packets enabling submission of\nan equivocation proposal on the provider chain, resulting in the freezing of\nvalidator's unbondings for an undeterminated amount of time."),(0,o.kt)("li",{parentName:"ul"},"Misbehavior on a consumer chain can potentially go unpunished, if no one\nsubmits an equivocation proposal in time, or if the proposal doesn't pass.")),(0,o.kt)("h3",{id:"neutral"},"Neutral"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"This feature can't be used for social slashing, because an equivocation\nproposal is only accepted if there's a slash log for the related\nvalidator(s), meaning the consumer chain has reported the equivocation to\nthe provider chain.")),(0,o.kt)("h2",{id:"references"},"References"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/747"},"https://github.com/cosmos/interchain-security/issues/747")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/791"},"https://github.com/cosmos/interchain-security/pull/791"))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/0251db3a.3cde3e2b.js b/legacy/assets/js/0251db3a.3cde3e2b.js new file mode 100644 index 0000000000..c665b8ae55 --- /dev/null +++ b/legacy/assets/js/0251db3a.3cde3e2b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4220],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=l(n),u=i,h=d["".concat(c,".").concat(u)]||d[u]||m[u]||o;return n?a.createElement(h,r(r({ref:t},p),{},{components:n})):a.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=u;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:i,r[1]=s;for(var l=2;l{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>m,frontMatter:()=>o,metadata:()=>s,toc:()=>l});var a=n(7462),i=(n(7294),n(3905));const o={sidebar_position:3,title:"Onboarding Checklist"},r="Consumer Onboarding Checklist",s={unversionedId:"consumer-development/onboarding",id:"version-v3.3.0/consumer-development/onboarding",title:"Onboarding Checklist",description:"The following checklists will aid in onboarding a new consumer chain to replicated security.",source:"@site/versioned_docs/version-v3.3.0/consumer-development/onboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/onboarding",permalink:"/interchain-security/legacy/v3.3.0/consumer-development/onboarding",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Onboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Consumer Chain Governance",permalink:"/interchain-security/legacy/v3.3.0/consumer-development/consumer-chain-governance"},next:{title:"Offboarding Checklist",permalink:"/interchain-security/legacy/v3.3.0/consumer-development/offboarding"}},c={},l=[{value:"1. Complete testing & integration",id:"1-complete-testing--integration",level:2},{value:"2. Create an Onboarding Repository",id:"2-create-an-onboarding-repository",level:2},{value:"3. Submit a Governance Proposal",id:"3-submit-a-governance-proposal",level:2},{value:"4. Launch",id:"4-launch",level:2}],p={toc:l},d="wrapper";function m(e){let{components:t,...n}=e;return(0,i.kt)(d,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"consumer-onboarding-checklist"},"Consumer Onboarding Checklist"),(0,i.kt)("p",null,"The following checklists will aid in onboarding a new consumer chain to replicated security."),(0,i.kt)("p",null,"Additionally, you can check the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md"},"testnet repo")," for a comprehensive guide on preparing and launching consumer chains."),(0,i.kt)("h2",{id:"1-complete-testing--integration"},"1. Complete testing & integration"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test integration with gaia"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test your protocol with supported relayer versions (minimum hermes 1.4.1)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","reach out to the ICS team if you are facing issues")),(0,i.kt)("h2",{id:"2-create-an-onboarding-repository"},"2. Create an Onboarding Repository"),(0,i.kt)("p",null,"To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain."),(0,i.kt)("p",null,"This should include (at minimum):"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json without CCV data (before the proposal passes)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see ",(0,i.kt)("a",{parentName:"li",href:"/interchain-security/legacy/v3.3.0/consumer-development/consumer-genesis-transformation"},"Transform Consumer Genesis"),")"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","information about relevant seed/peer nodes you are running"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","relayer information (compatible versions)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","copy of your governance proposal (as JSON)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","a script showing how to start your chain and connect to peers (optional)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable")),(0,i.kt)("p",null,"Example of such a repository can be found ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyphacoop/ics-testnets/tree/main/game-of-chains-2022/sputnik"},"here"),"."),(0,i.kt)("h2",{id:"3-submit-a-governance-proposal"},"3. Submit a Governance Proposal"),(0,i.kt)("p",null,"Before you submit a ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerChainAddition")," proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch.\nIf possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues."),(0,i.kt)("p",null,"Additionally, reach out to the community via the ",(0,i.kt)("a",{parentName:"p",href:"https://forum.cosmos.network/"},"forum")," to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine your chain's spawn time"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine consumer chain parameters to be put in the proposal"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take note to include a link to your onboarding repository"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","describe the purpose and benefits of running your chain")),(0,i.kt)("p",null,"Example of a consumer chain addition proposal."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},'// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.\n// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.\n// It is recommended that spawn time occurs after the proposal end time.\n{\n // Title of the proposal\n "title": "Add consumer chain",\n // Description of the proposal\n // format the text as a .md file and include the file in your onboarding repository\n "description": ".md description of your chain and all other relevant information",\n // Proposed chain-id of the new consumer chain.\n // Must be unique from all other consumer chain ids of the executing provider chain.\n "chain_id": "newchain-1",\n // Initial height of new consumer chain.\n // For a completely new chain, this will be {0,1}.\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Hash of the consumer chain genesis state without the consumer CCV module genesis params.\n // It is used for off-chain confirmation of genesis.json validity by validators and other parties.\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n // Hash of the consumer chain binary that should be run by validators on chain initialization.\n // It is used for off-chain confirmation of binary validity by validators and other parties.\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n // Unbonding period for the consumer chain.\n // It should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n // IBC transfer packets will timeout after this interval elapses.\n "transfer_timeout_period": 1800000000000,\n // The fraction of tokens allocated to the consumer redistribution address during distribution events.\n // The fraction is a string representing a decimal number. For example "0.75" would represent 75%.\n // The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.\n "consumer_redistribution_fraction": "0.75",\n // BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.\n // eg. send rewards to the provider every 1000 blocks\n "blocks_per_distribution_transmission": 1000,\n // The number of historical info entries to persist in store.\n // This param is a part of the cosmos sdk staking module. In the case of\n // a ccv enabled consumer chain, the ccv module acts as the staking module.\n "historical_entries": 10000,\n // The ID of a token transfer channel used for the Reward Distribution\n // sub-protocol. If DistributionTransmissionChannel == "", a new transfer\n // channel is created on top of the same connection as the CCV channel.\n // Note that transfer_channel_id is the ID of the channel end on the consumer chain.\n // it is most relevant for chains performing a sovereign to consumer changeover\n // in order to maintain the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123"\n}\n')),(0,i.kt)("h2",{id:"4-launch"},"4. Launch"),(0,i.kt)("p",null,"The consumer chain starts after at least 66.67% of all provider's voting power comes online. The consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","provide a repo with onboarding instructions for validators (it should already be listed in the proposal)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json with ccv data populated (MUST contain the initial validator set)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","have a block explorer in place to track chain activity & health")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/02951439.f3f01a29.js b/legacy/assets/js/02951439.f3f01a29.js new file mode 100644 index 0000000000..edd27870d5 --- /dev/null +++ b/legacy/assets/js/02951439.f3f01a29.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3734],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>y});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var p=r.createContext({}),s=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},l=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,c=e.originalType,p=e.parentName,l=a(e,["components","mdxType","originalType","parentName"]),u=s(n),d=i,y=u["".concat(p,".").concat(d)]||u[d]||f[d]||c;return n?r.createElement(y,o(o({ref:t},l),{},{components:n})):r.createElement(y,o({ref:t},l))}));function y(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var c=n.length,o=new Array(c);o[0]=d;var a={};for(var p in t)hasOwnProperty.call(t,p)&&(a[p]=t[p]);a.originalType=e,a[u]="string"==typeof e?e:i,o[1]=a;for(var s=2;s{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>f,frontMatter:()=>c,metadata:()=>a,toc:()=>s});var r=n(7462),i=(n(7294),n(3905));const c={sidebar_position:4},o="Technical Specification",a={unversionedId:"introduction/technical-specification",id:"version-v3.3.0/introduction/technical-specification",title:"Technical Specification",description:"For a technical deep dive into the replicated security protocol, see the specification.",source:"@site/versioned_docs/version-v3.3.0/introduction/technical-specification.md",sourceDirName:"introduction",slug:"/introduction/technical-specification",permalink:"/interchain-security/legacy/v3.3.0/introduction/technical-specification",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Parameters",permalink:"/interchain-security/legacy/v3.3.0/introduction/params"},next:{title:"Key Assignment",permalink:"/interchain-security/legacy/v3.3.0/features/key-assignment"}},p={},s=[],l={toc:s},u="wrapper";function f(e){let{components:t,...n}=e;return(0,i.kt)(u,(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"technical-specification"},"Technical Specification"),(0,i.kt)("p",null,"For a technical deep dive into the replicated security protocol, see the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/README.md"},"specification"),"."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/04f38623.0b0a20d5.js b/legacy/assets/js/04f38623.0b0a20d5.js new file mode 100644 index 0000000000..6bb9385d3a --- /dev/null +++ b/legacy/assets/js/04f38623.0b0a20d5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8956],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=l(n),u=i,h=d["".concat(c,".").concat(u)]||d[u]||m[u]||o;return n?a.createElement(h,r(r({ref:t},p),{},{components:n})):a.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=u;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:i,r[1]=s;for(var l=2;l{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>m,frontMatter:()=>o,metadata:()=>s,toc:()=>l});var a=n(7462),i=(n(7294),n(3905));const o={sidebar_position:4,title:"Onboarding Checklist"},r="Consumer Onboarding Checklist",s={unversionedId:"consumer-development/onboarding",id:"version-v2.0.0/consumer-development/onboarding",title:"Onboarding Checklist",description:"The following checklists will aid in onboarding a new consumer chain to replicated security.",source:"@site/versioned_docs/version-v2.0.0/consumer-development/onboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/onboarding",permalink:"/interchain-security/legacy/v2.0.0/consumer-development/onboarding",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Onboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Upgrading Consumer Chains",permalink:"/interchain-security/legacy/v2.0.0/consumer-development/consumer-chain-upgrade-procedure"},next:{title:"Offboarding Checklist",permalink:"/interchain-security/legacy/v2.0.0/consumer-development/offboarding"}},c={},l=[{value:"1. Complete testing & integration",id:"1-complete-testing--integration",level:2},{value:"2. Create an Onboarding Repository",id:"2-create-an-onboarding-repository",level:2},{value:"3. Submit a Governance Proposal",id:"3-submit-a-governance-proposal",level:2},{value:"4. Launch",id:"4-launch",level:2}],p={toc:l},d="wrapper";function m(e){let{components:t,...n}=e;return(0,i.kt)(d,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"consumer-onboarding-checklist"},"Consumer Onboarding Checklist"),(0,i.kt)("p",null,"The following checklists will aid in onboarding a new consumer chain to replicated security."),(0,i.kt)("p",null,"Additionally, you can check the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md"},"testnet repo")," for a comprehensive guide on preparing and launching consumer chains."),(0,i.kt)("h2",{id:"1-complete-testing--integration"},"1. Complete testing & integration"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test integration with gaia"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test your protocol with supported relayer versions (minimum hermes 1.4.1)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","reach out to the ICS team if you are facing issues")),(0,i.kt)("h2",{id:"2-create-an-onboarding-repository"},"2. Create an Onboarding Repository"),(0,i.kt)("p",null,"To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain."),(0,i.kt)("p",null,"This should include (at minimum):"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json witout CCV data (before the propsal passes)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json with CCV data (after spawn time passes)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","information about relevant seed/peer nodes you are running"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","relayer information (compatible versions)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","copy of your governance proposal (as JSON)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","a script showing how to start your chain and connect to peers (optional)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable")),(0,i.kt)("p",null,"Example of such a repository can be found ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyphacoop/ics-testnets/tree/main/game-of-chains-2022/sputnik"},"here"),"."),(0,i.kt)("h2",{id:"3-submit-a-governance-proposal"},"3. Submit a Governance Proposal"),(0,i.kt)("p",null,"Before you submit a ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerChainAddition")," proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch.\nIf possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues."),(0,i.kt)("p",null,"Additionally, reach out to the community via the ",(0,i.kt)("a",{parentName:"p",href:"https://forum.cosmos.network/"},"forum")," to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine your chain's spawn time"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine consumer chain parameters to be put in the proposal"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take note to include a link to your onboarding repository"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","describe the purpose and benefits of running your chain")),(0,i.kt)("p",null,"Example of a consumer chain addition proposal."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},'// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.\n// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.\n// It is recommended that spawn time occurs after the proposal end time.\n{\n // Title of the proposal\n "title": "Add consumer chain",\n // Description of the proposal\n // format the text as a .md file and include the file in your onboarding repository\n "description": ".md description of your chain and all other relevant information",\n // Proposed chain-id of the new consumer chain.\n // Must be unique from all other consumer chain ids of the executing provider chain.\n "chain_id": "newchain-1",\n // Initial height of new consumer chain.\n // For a completely new chain, this will be {0,1}.\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Hash of the consumer chain genesis state without the consumer CCV module genesis params.\n // It is used for off-chain confirmation of genesis.json validity by validators and other parties.\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n // Hash of the consumer chain binary that should be run by validators on chain initialization.\n // It is used for off-chain confirmation of binary validity by validators and other parties.\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n // Unbonding period for the consumer chain.\n // It should should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n // IBC transfer packets will timeout after this interval elapses.\n "transfer_timeout_period": 1800000000000,\n // The fraction of tokens allocated to the consumer redistribution address during distribution events.\n // The fraction is a string representing a decimal number. For example "0.75" would represent 75%.\n // The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.\n "consumer_redistribution_fraction": "0.75",\n // BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.\n // eg. send rewards to the provider every 1000 blocks\n "blocks_per_distribution_transmission": 1000,\n // The number of historical info entries to persist in store.\n // This param is a part of the cosmos sdk staking module. In the case of\n // a ccv enabled consumer chain, the ccv module acts as the staking module.\n "historical_entries": 10000,\n // The ID of a token transfer channel used for the Reward Distribution\n // sub-protocol. If DistributionTransmissionChannel == "", a new transfer\n // channel is created on top of the same connection as the CCV channel.\n // Note that transfer_channel_id is the ID of the channel end on the consumer chain.\n // it is most relevant for chains performing a sovereign to consumer changeover\n // in order to maintan the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123"\n}\n')),(0,i.kt)("h2",{id:"4-launch"},"4. Launch"),(0,i.kt)("p",null,"The consumer chain starts after at least 66.67% of all provider's voting power comes online. The consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","provide a repo with onboarding instructions for validators (it should already be listed in the proposal)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json with ccv data populated (MUST contain the initial validator set)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","have a block explorer in place to track chain activity & health")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/05354274.54e3067a.js b/legacy/assets/js/05354274.54e3067a.js new file mode 100644 index 0000000000..7209e9efcf --- /dev/null +++ b/legacy/assets/js/05354274.54e3067a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1614],{3905:(e,r,t)=>{t.d(r,{Zo:()=>d,kt:()=>f});var n=t(7294);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function o(e){for(var r=1;r=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=n.createContext({}),u=function(e){var r=n.useContext(s),t=r;return e&&(t="function"==typeof e?e(r):o(o({},r),e)),t},d=function(e){var r=u(e.components);return n.createElement(s.Provider,{value:r},e.children)},l="mdxType",m={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},p=n.forwardRef((function(e,r){var t=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,d=c(e,["components","mdxType","originalType","parentName"]),l=u(t),p=a,f=l["".concat(s,".").concat(p)]||l[p]||m[p]||i;return t?n.createElement(f,o(o({ref:r},d),{},{components:t})):n.createElement(f,o({ref:r},d))}));function f(e,r){var t=arguments,a=r&&r.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=p;var c={};for(var s in r)hasOwnProperty.call(r,s)&&(c[s]=r[s]);c.originalType=e,c[l]="string"==typeof e?e:a,o[1]=c;for(var u=2;u{t.d(r,{Z:()=>i});var n=t(7294);const a=function(e){return n.createElement("a",{href:e.href,className:"border shadow rounded-sm border-stone-200 dark:border-stone-800 dark:bg-neutral-900 hover:border-stone-300 hover:shadow-lg dark:hover:border-stone-200 transition-all duration-200 no-underline"},n.createElement("div",{className:"p-6"},n.createElement("h2",{className:""},e.header),n.createElement("p",{className:""},e.summary)))};const i=function(e){return n.createElement("div",{className:"card-section grid grid-cols-1 lg:grid-cols-2 gap-4 no-underline"},e.cards.map(((e,r)=>n.createElement(a,{key:r,href:e.href,header:e.header,summary:e.summary}))))}},8758:(e,r,t)=>{t.d(r,{Z:()=>n});const n=[{href:"/interchain-security/introduction/overview",header:"Basic concepts",summary:"Get started with the basic concepts and ideas."},{href:"/interchain-security/consumer-development/app-integration",header:"Start building",summary:"Click here to start building with Interchain security"},{href:"/interchain-security/features/key-assignment",header:"Feature: Key Assignment",summary:"Learn about the key assignment feature"},{href:"/interchain-security/features/reward-distribution",header:"Feature: Reward Distribution",summary:"Learn about consumer chain rewards distribution"},{href:"/interchain-security/consumer-development/onboarding",header:"Onboarding Checklist",summary:"Checklist to help you integrate Interchain Security, get support and onboard validators"},{href:"/interchain-security/faq",header:"FAQ",summary:"Frequently asked questions about the protocol and its implications"}]},3564:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>d,contentTitle:()=>s,default:()=>f,frontMatter:()=>c,metadata:()=>u,toc:()=>l});var n=t(7462),a=(t(7294),t(3905)),i=t(2307),o=t(8758);const c={sidebar_position:1},s="Interchain Security Docs",u={unversionedId:"index",id:"version-v2.0.0/index",title:"Interchain Security Docs",description:"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.",source:"@site/versioned_docs/version-v2.0.0/index.mdx",sourceDirName:".",slug:"/",permalink:"/interchain-security/legacy/v2.0.0/",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",next:{title:"Overview",permalink:"/interchain-security/legacy/v2.0.0/introduction/overview"}},d={},l=[],m={toc:l},p="wrapper";function f(e){let{components:r,...t}=e;return(0,a.kt)(p,(0,n.Z)({},m,t,{components:r,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"interchain-security-docs"},"Interchain Security Docs"),(0,a.kt)("p",null,"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains."),(0,a.kt)("p",null,"Here you can find information about replicated security, consumer chain development and instructions for validator onboarding."),(0,a.kt)(i.Z,{cards:o.Z,mdxType:"CardSection"}))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/0613ea9d.808de359.js b/legacy/assets/js/0613ea9d.808de359.js new file mode 100644 index 0000000000..1f73e338a3 --- /dev/null +++ b/legacy/assets/js/0613ea9d.808de359.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[495],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},d=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},h="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},p=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),h=c(n),p=r,m=h["".concat(l,".").concat(p)]||h[p]||u[p]||o;return n?a.createElement(m,s(s({ref:t},d),{},{components:n})):a.createElement(m,s({ref:t},d))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,s=new Array(o);s[0]=p;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[h]="string"==typeof e?e:r,s[1]=i;for(var c=2;c{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>c});var a=n(7462),r=(n(7294),n(3905));const o={sidebar_position:11,title:"Standalone to Consumer Changeover"},s=void 0,i={unversionedId:"adrs/adr-010-standalone-changeover",id:"version-v3.3.0/adrs/adr-010-standalone-changeover",title:"Standalone to Consumer Changeover",description:"ADR 010: Standalone to Consumer Changeover",source:"@site/versioned_docs/version-v3.3.0/adrs/adr-010-standalone-changeover.md",sourceDirName:"adrs",slug:"/adrs/adr-010-standalone-changeover",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-010-standalone-changeover",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:11,frontMatter:{sidebar_position:11,title:"Standalone to Consumer Changeover"},sidebar:"tutorialSidebar",previous:{title:"Soft Opt-Out",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-009-soft-opt-out"},next:{title:"Improving testing and increasing confidence",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-011-improving-test-confidence"}},l={},c=[{value:"ADR 010: Standalone to Consumer Changeover",id:"adr-010-standalone-to-consumer-changeover",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Process",id:"process",level:3},{value:"Changes to CCV Protocol",id:"changes-to-ccv-protocol",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}],d={toc:c},h="wrapper";function u(e){let{components:t,...n}=e;return(0,r.kt)(h,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"adr-010-standalone-to-consumer-changeover"},"ADR 010: Standalone to Consumer Changeover"),(0,r.kt)("h2",{id:"changelog"},"Changelog"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"6/30/23: Feature completed, first draft of ADR.")),(0,r.kt)("h2",{id:"status"},"Status"),(0,r.kt)("p",null,"Implemented"),(0,r.kt)("h2",{id:"context"},"Context"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/Stride-Labs/stride"},"Stride"),' will be the first consumer to "changeover" from a standalone cosmos blockchain, to a consumer chain secured by the Cosmos Hub. This document will outline the changes made to the replicated security protocol to support this changeover process.'),(0,r.kt)("h2",{id:"decision"},"Decision"),(0,r.kt)("h3",{id:"process"},"Process"),(0,r.kt)("p",null,'Prior to the changeover, the consumer chain will have an existing staking keeper and validator set, these may be referred to as the "standalone staking keeper" and "standalone validator set" respectively. '),(0,r.kt)("p",null,"The first step in the changeover process is to submit a ConsumerAdditionProposal. If the proposal passes, the provider will create a new IBC client for the consumer at spawn time, with the provider's validator set. A consumer genesis will also be constructed by the provider for validators to query. Within this consumer genesis contains the initial validator set for the consumer to apply after the changeover."),(0,r.kt)("p",null,"Next, the standalone consumer chain runs an upgrade which adds the CCV module, and is properly setup to execute changeover logic."),(0,r.kt)("p",null,"The consumer upgrade height must be reached after the provider has created the new IBC client. Any replicated security validators who will run the consumer, but are not a part of the sovereign validator set, must sync up a full node before the consumer upgrade height is reached. The disc state of said full node will be used to run the consumer chain after the changeover has completed."),(0,r.kt)("p",null,"The meat of the changeover logic is that the consumer chain validator set is updated to that which was specified by the provider via the queried consumer genesis. Validators which were a part of the old set, but not the new set, are given zero voting power. Once these validator updates are given to Comet, the set is committed, and in effect 2 blocks later (see ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/x/ccv/consumer/keeper/changeover.go#L19"},"FirstConsumerHeight"),")."),(0,r.kt)("p",null,"A relayer then establishes the new IBC connection between the provider and consumer. The CCV channel handshake is started on top of this connection. Once the CCV channel is established and VSC packets are being relayed, the consumer chain is secured by the provider."),(0,r.kt)("h3",{id:"changes-to-ccv-protocol"},"Changes to CCV Protocol"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Consumer Genesis state is updated to include a ",(0,r.kt)("inlineCode",{parentName:"li"},"PreCCV")," boolean. When this boolean is set true in the consumer genesis JSON, ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/x/ccv/consumer/keeper/changeover.go"},"special logic")," is executed on InitGenesis to trigger the changeover process on the consumer's first endblocker after the upgrade which adds the CCV module. Note that InitGenesis is not automatically called during chain upgrades, so the consumer must manually call the consumer's InitGenesis method in an upgrade handler."),(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal")," type is updated to include a ",(0,r.kt)("inlineCode",{parentName:"li"},"DistributionTransmissionChannel")," field. This field allows the consumer to use an existing IBC transfer channel to send rewards as a part of the CCV protocol. Consumers that're not changing over from a standalone chain will leave this field blank, indicating that a new transfer channel should be created on top of the same connection as the CCV channel."),(0,r.kt)("li",{parentName:"ul"},"The CCV consumer keeper is updated to contain an optional reference to the standalone staking keeper. The standalone staking keeper is used to slash for infractions that happened before the changeover was completed. Ie. any infraction from a block height before the changeover, that is submitted after the changeover, will call the standalone staking keeper's slash method. Note that a changeover consumer's standalone staking keeper becomes a democracy module keeper, so it is possible for a governance token to be slashed.")),(0,r.kt)("h2",{id:"consequences"},"Consequences"),(0,r.kt)("h3",{id:"positive"},"Positive"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Existing cosmos chains are now able to onboard over to a consumer chain secured by a provider."),(0,r.kt)("li",{parentName:"ul"},"The previous staking keepers for such chains can be transitioned to democracy staking module keepers.")),(0,r.kt)("h3",{id:"negative"},"Negative"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"The delineation between different types of consumers in this repo becomes less clear. Ie. there is code in the ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/app/consumer-democracy/app.go"},"democracy consumer's app.go")," that only applies to a previously standalone chain, but that file also serves as the base for a normal democracy consumer launched with RS from genesis.")),(0,r.kt)("h2",{id:"references"},"References"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"EPIC: Standalone to Consumer Changeover ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/756"},"#756")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt"},"Changeover diagram from Stride"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/07a13505.5d186dd7.js b/legacy/assets/js/07a13505.5d186dd7.js new file mode 100644 index 0000000000..e3fe93092e --- /dev/null +++ b/legacy/assets/js/07a13505.5d186dd7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5964],{302:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"v2.0.0","label":"v2.0.0","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-v2.0.0","isLast":false,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Interchain Security Docs","href":"/interchain-security/legacy/v2.0.0/","docId":"index"},{"type":"category","label":"Introduction","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/legacy/v2.0.0/introduction/overview","docId":"introduction/overview"},{"type":"link","label":"Terminology","href":"/interchain-security/legacy/v2.0.0/introduction/terminology","docId":"introduction/terminology"},{"type":"link","label":"Interchain Security Parameters","href":"/interchain-security/legacy/v2.0.0/introduction/params","docId":"introduction/params"},{"type":"link","label":"Technical Specification","href":"/interchain-security/legacy/v2.0.0/introduction/technical-specification","docId":"introduction/technical-specification"}]},{"type":"category","label":"Features","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Key Assignment","href":"/interchain-security/legacy/v2.0.0/features/key-assignment","docId":"features/key-assignment"},{"type":"link","label":"Reward distribution","href":"/interchain-security/legacy/v2.0.0/features/reward-distribution","docId":"features/reward-distribution"},{"type":"link","label":"ICS Provider Proposals","href":"/interchain-security/legacy/v2.0.0/features/proposals","docId":"features/proposals"},{"type":"link","label":"Consumer Initiated Slashing","href":"/interchain-security/legacy/v2.0.0/features/slashing","docId":"features/slashing"}]},{"type":"category","label":"Consumer Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Developing an ICS consumer chain","href":"/interchain-security/legacy/v2.0.0/consumer-development/app-integration","docId":"consumer-development/app-integration"},{"type":"link","label":"Consumer Chain Governance","href":"/interchain-security/legacy/v2.0.0/consumer-development/consumer-chain-governance","docId":"consumer-development/consumer-chain-governance"},{"type":"link","label":"Upgrading Consumer Chains","href":"/interchain-security/legacy/v2.0.0/consumer-development/consumer-chain-upgrade-procedure","docId":"consumer-development/consumer-chain-upgrade-procedure"},{"type":"link","label":"Onboarding Checklist","href":"/interchain-security/legacy/v2.0.0/consumer-development/onboarding","docId":"consumer-development/onboarding"},{"type":"link","label":"Offboarding Checklist","href":"/interchain-security/legacy/v2.0.0/consumer-development/offboarding","docId":"consumer-development/offboarding"}]},{"type":"category","label":"Validators Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/legacy/v2.0.0/validators/overview","docId":"validators/overview"},{"type":"link","label":"Joining Replicated Security testnet","href":"/interchain-security/legacy/v2.0.0/validators/joining-testnet","docId":"validators/joining-testnet"},{"type":"link","label":"Withdrawing consumer chain validator rewards","href":"/interchain-security/legacy/v2.0.0/validators/withdraw_rewards","docId":"validators/withdraw_rewards"}]},{"type":"link","label":"Frequently Asked Questions","href":"/interchain-security/legacy/v2.0.0/faq","docId":"frequently-asked-questions"},{"type":"category","label":"ADRs","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"ADRs","href":"/interchain-security/legacy/v2.0.0/adrs/intro","docId":"adrs/intro"},{"type":"link","label":"ADR Template","href":"/interchain-security/legacy/v2.0.0/adrs/adr-template","docId":"adrs/adr-template"},{"type":"link","label":"Key Assignment","href":"/interchain-security/legacy/v2.0.0/adrs/adr-001-key-assignment","docId":"adrs/adr-001-key-assignment"},{"type":"link","label":"Jail Throttling","href":"/interchain-security/legacy/v2.0.0/adrs/adr-002-throttle","docId":"adrs/adr-002-throttle"},{"type":"link","label":"Equivocation governance proposal","href":"/interchain-security/legacy/v2.0.0/adrs/adr-003-equivocation-gov-proposal","docId":"adrs/adr-003-equivocation-gov-proposal"}]}]},"docs":{"adrs/adr-001-key-assignment":{"id":"adrs/adr-001-key-assignment","title":"Key Assignment","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-002-throttle":{"id":"adrs/adr-002-throttle","title":"Jail Throttling","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-003-equivocation-gov-proposal":{"id":"adrs/adr-003-equivocation-gov-proposal","title":"Equivocation governance proposal","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-template":{"id":"adrs/adr-template","title":"ADR Template","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/intro":{"id":"adrs/intro","title":"ADRs","description":"This is a location to record all high-level architecture decisions in the Interchain Security project.","sidebar":"tutorialSidebar"},"consumer-development/app-integration":{"id":"consumer-development/app-integration","title":"Developing an ICS consumer chain","description":"When developing an ICS consumer chain, besides just focusing on your chain\'s logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.","sidebar":"tutorialSidebar"},"consumer-development/consumer-chain-governance":{"id":"consumer-development/consumer-chain-governance","title":"Consumer Chain Governance","description":"Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the \\"Whitelist\\" section below.","sidebar":"tutorialSidebar"},"consumer-development/consumer-chain-upgrade-procedure":{"id":"consumer-development/consumer-chain-upgrade-procedure","title":"Upgrading Consumer Chains","description":"","sidebar":"tutorialSidebar"},"consumer-development/offboarding":{"id":"consumer-development/offboarding","title":"Offboarding Checklist","description":"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).","sidebar":"tutorialSidebar"},"consumer-development/onboarding":{"id":"consumer-development/onboarding","title":"Onboarding Checklist","description":"The following checklists will aid in onboarding a new consumer chain to replicated security.","sidebar":"tutorialSidebar"},"features/key-assignment":{"id":"features/key-assignment","title":"Key Assignment","description":"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.","sidebar":"tutorialSidebar"},"features/proposals":{"id":"features/proposals","title":"ICS Provider Proposals","description":"Interchain security module introduces 3 new proposal types to the provider.","sidebar":"tutorialSidebar"},"features/reward-distribution":{"id":"features/reward-distribution","title":"Reward distribution","description":"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.","sidebar":"tutorialSidebar"},"features/slashing":{"id":"features/slashing","title":"Consumer Initiated Slashing","description":"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of it\'s own chain.","sidebar":"tutorialSidebar"},"frequently-asked-questions":{"id":"frequently-asked-questions","title":"Frequently Asked Questions","description":"What is the meaning of Validator Set Replication?","sidebar":"tutorialSidebar"},"index":{"id":"index","title":"Interchain Security Docs","description":"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.","sidebar":"tutorialSidebar"},"introduction/overview":{"id":"introduction/overview","title":"Overview","description":"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.","sidebar":"tutorialSidebar"},"introduction/params":{"id":"introduction/params","title":"Interchain Security Parameters","description":"The parameters necessary for Interchain Security (ICS) are defined in","sidebar":"tutorialSidebar"},"introduction/technical-specification":{"id":"introduction/technical-specification","title":"Technical Specification","description":"For a technical deep dive into the replicated security protocol, see the specification.","sidebar":"tutorialSidebar"},"introduction/terminology":{"id":"introduction/terminology","title":"Terminology","description":"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.","sidebar":"tutorialSidebar"},"validators/joining-testnet":{"id":"validators/joining-testnet","title":"Joining Replicated Security testnet","description":"This short guide will teach you how to join the Replicated Security testnet.","sidebar":"tutorialSidebar"},"validators/overview":{"id":"validators/overview","title":"Overview","description":"We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.","sidebar":"tutorialSidebar"},"validators/withdraw_rewards":{"id":"validators/withdraw_rewards","title":"Withdrawing consumer chain validator rewards","description":"Here are example steps for withdrawing rewards from consumer chains in the provider chain","sidebar":"tutorialSidebar"}}}')}}]); \ No newline at end of file diff --git a/legacy/assets/js/07d76e7d.fd454a42.js b/legacy/assets/js/07d76e7d.fd454a42.js new file mode 100644 index 0000000000..70944d9390 --- /dev/null +++ b/legacy/assets/js/07d76e7d.fd454a42.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2189],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>m});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=a.createContext({}),c=function(e){var n=a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=c(e.components);return a.createElement(l.Provider,{value:n},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},y=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=c(t),y=r,m=d["".concat(l,".").concat(y)]||d[y]||p[y]||i;return t?a.createElement(m,o(o({ref:n},u),{},{components:t})):a.createElement(m,o({ref:n},u))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,o=new Array(i);o[0]=y;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var c=2;c{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var a=t(7462),r=(t(7294),t(3905));const i={sidebar_position:1},o="Key Assignment",s={unversionedId:"features/key-assignment",id:"features/key-assignment",title:"Key Assignment",description:"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.",source:"@site/docs/features/key-assignment.md",sourceDirName:"features",slug:"/features/key-assignment",permalink:"/interchain-security/legacy/features/key-assignment",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Technical Specification",permalink:"/interchain-security/legacy/introduction/technical-specification"},next:{title:"Reward distribution",permalink:"/interchain-security/legacy/features/reward-distribution"}},l={},c=[{value:"Rules",id:"rules",level:2},{value:"Adding a key",id:"adding-a-key",level:2},{value:"Changing a key",id:"changing-a-key",level:2},{value:"Removing a key",id:"removing-a-key",level:2}],u={toc:c},d="wrapper";function p(e){let{components:n,...t}=e;return(0,r.kt)(d,(0,a.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"key-assignment"},"Key Assignment"),(0,r.kt)("p",null,"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.\nThere are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains."),(0,r.kt)("p",null,"The feature is outlined in this ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/adrs/adr-001-key-assignment"},"ADR-001")),(0,r.kt)("p",null,"By sending an ",(0,r.kt)("inlineCode",{parentName:"p"},"AssignConsumerKey")," transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity.")),(0,r.kt)("h2",{id:"rules"},"Rules"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"a key can be assigned before the consumer addition proposal passes on the provider"),(0,r.kt)("li",{parentName:"ul"},"validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider"),(0,r.kt)("li",{parentName:"ul"},"validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X"),(0,r.kt)("li",{parentName:"ul"},"a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Validators can use a different key for each consumer chain.")),(0,r.kt)("h2",{id:"adding-a-key"},"Adding a key"),(0,r.kt)("p",null,"First, create a new node on the consumer chain using the equivalent:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"consumerd init \n")),(0,r.kt)("p",null,"Then query your node for the consensus key."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":""}\n')),(0,r.kt)("p",null,"Then, make an ",(0,r.kt)("inlineCode",{parentName:"p"},"assign-consensus-key")," transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad tx provider assign-consensus-key '' --from --home --gas 900000 -b sync -y -o json\n")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"consumer-chain-id")," is the string identifier of the consumer chain, as assigned on the provider chain"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"consumer-pub-key")," has the following format ",(0,r.kt)("inlineCode",{parentName:"li"},'{"@type":"/cosmos.crypto.ed25519.PubKey","key":""}'))),(0,r.kt)("p",null,"Check that the key was assigned correctly by querying the provider:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad query provider validator-consumer-key cosmosvalcons1e....3xsj3ayzf4uv6\n")),(0,r.kt)("p",null,"You must use a ",(0,r.kt)("inlineCode",{parentName:"p"},"valcons")," address. You can obtain it by querying your node on the provider ",(0,r.kt)("inlineCode",{parentName:"p"},"gaiad tendermint show-address")),(0,r.kt)("p",null,"OR"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad query provider validator-provider-key consumervalcons1e....123asdnoaisdao\n")),(0,r.kt)("p",null,"You must use a ",(0,r.kt)("inlineCode",{parentName:"p"},"valcons")," address. You can obtain it by querying your node on the consumer ",(0,r.kt)("inlineCode",{parentName:"p"},"consumerd tendermint show-address")),(0,r.kt)("h2",{id:"changing-a-key"},"Changing a key"),(0,r.kt)("p",null,"To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied"),(0,r.kt)("h2",{id:"removing-a-key"},"Removing a key"),(0,r.kt)("p",null,"To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the ",(0,r.kt)("inlineCode",{parentName:"p"},"Adding a key")," section and using your provider consensus key."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/07e666cb.a5f5aa7e.js b/legacy/assets/js/07e666cb.a5f5aa7e.js new file mode 100644 index 0000000000..534157ad13 --- /dev/null +++ b/legacy/assets/js/07e666cb.a5f5aa7e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9783],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>d});var o=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function i(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=o.createContext({}),l=function(e){var n=o.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},u=function(e){var n=l(e.components);return o.createElement(s.Provider,{value:n},e.children)},m="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},h=o.forwardRef((function(e,n){var t=e.components,r=e.mdxType,a=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),m=l(t),h=r,d=m["".concat(s,".").concat(h)]||m[h]||p[h]||a;return t?o.createElement(d,i(i({ref:n},u),{},{components:t})):o.createElement(d,i({ref:n},u))}));function d(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var a=t.length,i=new Array(a);i[0]=h;var c={};for(var s in n)hasOwnProperty.call(n,s)&&(c[s]=n[s]);c.originalType=e,c[m]="string"==typeof e?e:r,i[1]=c;for(var l=2;l{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>p,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var o=t(7462),r=(t(7294),t(3905));const a={sidebar_position:1},i="Developing an ICS consumer chain",c={unversionedId:"consumer-development/app-integration",id:"version-v2.4.0-lsm/consumer-development/app-integration",title:"Developing an ICS consumer chain",description:"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.",source:"@site/versioned_docs/version-v2.4.0-lsm/consumer-development/app-integration.md",sourceDirName:"consumer-development",slug:"/consumer-development/app-integration",permalink:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/app-integration",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/legacy/v2.4.0-lsm/features/slashing"},next:{title:"Consumer Chain Governance",permalink:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/consumer-chain-governance"}},s={},l=[{value:"Basic consumer chain",id:"basic-consumer-chain",level:2},{value:"Democracy consumer chain",id:"democracy-consumer-chain",level:2},{value:"Standalone chain to consumer chain changeover",id:"standalone-chain-to-consumer-chain-changeover",level:2}],u={toc:l},m="wrapper";function p(e){let{components:n,...t}=e;return(0,r.kt)(m,(0,o.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"developing-an-ics-consumer-chain"},"Developing an ICS consumer chain"),(0,r.kt)("p",null,"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.\nTo help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications."),(0,r.kt)("h2",{id:"basic-consumer-chain"},"Basic consumer chain"),(0,r.kt)("p",null,"The source code for the example app can be found ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer"},"here"),"."),(0,r.kt)("p",null,"Please note that consumer chains do not implement the staking module - the validator set is replicated from the provider, meaning that the provider and the consumer use the same validator set and their stake on the provider directly determines their stake on the consumer.\nAt present there is no opt-in mechanism available, so all validators of the provider must also validate on the provider chain."),(0,r.kt)("p",null,"Your chain should import the consumer module from ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," and register it in the correct places in your ",(0,r.kt)("inlineCode",{parentName:"p"},"app.go"),".\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in.\nYou should not need to manage or override any code from the ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module."),(0,r.kt)("h2",{id:"democracy-consumer-chain"},"Democracy consumer chain"),(0,r.kt)("p",null,"The source code for the example app can be found ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy"},"here"),"."),(0,r.kt)("p",null,"This type of consumer chain wraps the basic CosmosSDK ",(0,r.kt)("inlineCode",{parentName:"p"},"x/distribution"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"x/staking")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"x/governance")," modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system."),(0,r.kt)("p",null,"This allows the consumer chain to leverage those modules while also using the ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module."),(0,r.kt)("p",null,'With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.'),(0,r.kt)("h2",{id:"standalone-chain-to-consumer-chain-changeover"},"Standalone chain to consumer chain changeover"),(0,r.kt)("p",null,"This feature is being actively worked on. Information will be provided at a later time."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/08757149.630ce891.js b/legacy/assets/js/08757149.630ce891.js new file mode 100644 index 0000000000..837032a14d --- /dev/null +++ b/legacy/assets/js/08757149.630ce891.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3913],{3905:(e,t,o)=>{o.d(t,{Zo:()=>c,kt:()=>m});var n=o(7294);function a(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function i(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,n)}return o}function r(e){for(var t=1;t=0||(a[o]=e[o]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(a[o]=e[o])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),o=t;return e&&(o="function"==typeof e?e(t):r(r({},t),e)),o},c=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var o=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),p=u(o),h=a,m=p["".concat(s,".").concat(h)]||p[h]||d[h]||i;return o?n.createElement(m,r(r({ref:t},c),{},{components:o})):n.createElement(m,r({ref:t},c))}));function m(e,t){var o=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=o.length,r=new Array(i);r[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:a,r[1]=l;for(var u=2;u{o.r(t),o.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>u});var n=o(7462),a=(o(7294),o(3905));const i={sidebar_position:10,title:"Soft Opt-Out"},r=void 0,l={unversionedId:"adrs/adr-009-soft-opt-out",id:"version-v3.1.0/adrs/adr-009-soft-opt-out",title:"Soft Opt-Out",description:"ADR 009: Soft Opt-Out",source:"@site/versioned_docs/version-v3.1.0/adrs/adr-009-soft-opt-out.md",sourceDirName:"adrs",slug:"/adrs/adr-009-soft-opt-out",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-009-soft-opt-out",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:10,frontMatter:{sidebar_position:10,title:"Soft Opt-Out"},sidebar:"tutorialSidebar",previous:{title:"Throttle with retries",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-008-throttle-retries"}},s={},u=[{value:"ADR 009: Soft Opt-Out",id:"adr-009-soft-opt-out",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],c={toc:u},p="wrapper";function d(e){let{components:t,...o}=e;return(0,a.kt)(p,(0,n.Z)({},c,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"adr-009-soft-opt-out"},"ADR 009: Soft Opt-Out"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"6/13/23: Initial draft of ADR. Feature already implemented and in production.")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"Some small validators may not have the resources needed to validate all consumer chains. Therefore a need exists to allow the bottom ",(0,a.kt)("inlineCode",{parentName:"p"},"x%")," of validators to opt-out of validating a consumer chain. Meaning downtime infractions for these validators are dropped without ever reaching the provider."),(0,a.kt)("p",null,"This document specifies a modification to the ccv protocol which allows the bottom x% of the validator set by power to opt out of validating consumer chains without being jailed or otherwise punished for it. The feature is implemented with entirely consumer-side code."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"A consumer param exists, known as ",(0,a.kt)("inlineCode",{parentName:"p"},"SoftOptOutThreshold"),", which is a string decimal in the range of ","[0, 0.2]",", that determines the portion of validators which are allowed to opt out of validating that specific consumer."),(0,a.kt)("p",null,"In every consumer beginblocker, a function is ran which determines the so called ",(0,a.kt)("em",{parentName:"p"},"smallest non opt-out voting power"),". Validators with voting power greater than or equal to this value must validate the consumer chain, while validators below this value may opt out of validating the consumer chain."),(0,a.kt)("p",null,"The smallest non opt-out voting power is recomputed every beginblocker in ",(0,a.kt)("inlineCode",{parentName:"p"},"UpdateSmallestNonOptOutPower()"),". In a nutshell, the method obtains the total voting power of the consumer, iterates through the full valset (ordered power ascending) keeping track of a power sum, and when ",(0,a.kt)("inlineCode",{parentName:"p"},"powerSum / totalPower > SoftOptOutThreshold"),", the ",(0,a.kt)("inlineCode",{parentName:"p"},"SmallestNonOptOutPower")," is found and persisted."),(0,a.kt)("p",null,"Then, whenever the ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash()")," interface is executed on the consumer, if the voting power of the relevant validator being slashed is less than ",(0,a.kt)("inlineCode",{parentName:"p"},"SmallestNonOptOutPower")," for that block, the slash request is dropped and never sent to the provider."),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Small validators can opt out of validating specific consumers without being punished for it.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"The bottom ",(0,a.kt)("inlineCode",{parentName:"li"},"x%")," is still part of the total voting power of the consumer chain. This means that if the soft opt-out threshold is set to ",(0,a.kt)("inlineCode",{parentName:"li"},"10%")," for example, and every validator in the bottom ",(0,a.kt)("inlineCode",{parentName:"li"},"10%")," opts out from validating the consumer, then a ",(0,a.kt)("inlineCode",{parentName:"li"},"24%")," downtime of the remaining voting power would halt the chain. This may be especially problematic during consumer upgrades."),(0,a.kt)("li",{parentName:"ul"},"In nominal scenarios, consumers with soft opt out enabled will be constructing slash packets for small vals, which may be dropped. This is wasted computation, but necessary to keep implementation simple. Note that the sdk's ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/cosmos-sdk/blob/d3f09c222243bb3da3464969f0366330dcb977a8/x/slashing/keeper/infractions.go#L75"},"full downtime logic")," is always executed on the consumer, which can be computationally expensive and slow down certain blocks.")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Validators in the bottom of the valset who don't have to validate, may receive large delegation(s) which suddenly boost the validator to the subset that has to validate. This may catch the validator off guard.")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Original issue with some napkin math ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/784"},"#784"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/0b7cd1ab.04a31874.js b/legacy/assets/js/0b7cd1ab.04a31874.js new file mode 100644 index 0000000000..6bb770338a --- /dev/null +++ b/legacy/assets/js/0b7cd1ab.04a31874.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6755],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>u});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=p(n),m=i,u=d["".concat(l,".").concat(m)]||d[m]||h[m]||o;return n?a.createElement(u,r(r({ref:t},c),{},{components:n})):a.createElement(u,r({ref:t},c))}));function u(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:i,r[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var a=n(7462),i=(n(7294),n(3905));const o={sidebar_position:5},r="Changeover Procedure",s={unversionedId:"consumer-development/changeover-procedure",id:"version-v3.2.0/consumer-development/changeover-procedure",title:"Changeover Procedure",description:"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.",source:"@site/versioned_docs/version-v3.2.0/consumer-development/changeover-procedure.md",sourceDirName:"consumer-development",slug:"/consumer-development/changeover-procedure",permalink:"/interchain-security/legacy/v3.2.0/consumer-development/changeover-procedure",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Offboarding Checklist",permalink:"/interchain-security/legacy/v3.2.0/consumer-development/offboarding"},next:{title:"Overview",permalink:"/interchain-security/legacy/v3.2.0/validators/overview"}},l={},p=[{value:"Overview",id:"overview",level:2},{value:"1. ConsumerAddition proposal submitted to the provider chain",id:"1-consumeraddition-proposal-submitted-to-the-provider-chain",level:3},{value:"2. upgrade proposal on standalone chain",id:"2-upgrade-proposal-on-standalone-chain",level:3},{value:"3. spawn time is reached",id:"3-spawn-time-is-reached",level:3},{value:"4. standalone chain upgrade",id:"4-standalone-chain-upgrade",level:3},{value:"Notes",id:"notes",level:4},{value:"Onboarding Checklist",id:"onboarding-checklist",level:2},{value:"1. Complete testing & integration",id:"1-complete-testing--integration",level:2},{value:"2. Create an Onboarding Repository",id:"2-create-an-onboarding-repository",level:2},{value:"3. Submit a ConsumerChainAddition Governance Proposal to the provider",id:"3-submit-a-consumerchainaddition-governance-proposal-to-the-provider",level:2},{value:"3. Submit an Upgrade Proposal & Prepare for Changeover",id:"3-submit-an-upgrade-proposal--prepare-for-changeover",level:2},{value:"4. Upgrade time \ud83d\ude80",id:"4-upgrade-time-",level:2}],c={toc:p},d="wrapper";function h(e){let{components:t,...n}=e;return(0,i.kt)(d,(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"changeover-procedure"},"Changeover Procedure"),(0,i.kt)("p",null,"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the ",(0,i.kt)("strong",{parentName:"p"},"changeover procedure")," and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain."),(0,i.kt)("p",null,"The relevant protocol specifications are available below:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md#channel-initialization-existing-chains"},"ICS-28 with existing chains"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/interchain-security/legacy/v3.2.0/adrs/adr-010-standalone-changeover"},"ADR in ICS repo"))),(0,i.kt)("h2",{id:"overview"},"Overview"),(0,i.kt)("p",null,"Standalone to consumer changeover procedure can rougly be separated into 4 parts:"),(0,i.kt)("h3",{id:"1-consumeraddition-proposal-submitted-to-the-provider-chain"},"1. ConsumerAddition proposal submitted to the ",(0,i.kt)("inlineCode",{parentName:"h3"},"provider")," chain"),(0,i.kt)("p",null,'The proposal is equivalent to the "normal" ConsumerAddition proposal submitted by new consumer chains.'),(0,i.kt)("p",null,"However, here are the most important notes and differences between a new consumer chain and a standalone chain performing a changeover:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"chain_id")," must be equal to the standalone chain id"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"initial_height")," field has additional rules to abide by:")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre"},'{\n...\n "initial_height" : {\n // must correspond to current revision number of standalone chain\n // e.g. stride-1 => "revision_number": 1\n "revision_number": 1,\n\n // must correspond to a height that is at least 1 block after the upgrade\n // that will add the `consumer` module to the standalone chain\n // e.g. "upgrade_height": 100 => "revision_height": 101\n "revision_height": 1,\n },\n...\n}\n')),(0,i.kt)("p",{parentName:"admonition"},"RevisionNumber: 0, RevisionHeight: 111")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"genesis_hash")," can be safely ignored because the chain is already running. A hash of the standalone chain's initial genesis may be used")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"binary_hash")," may not be available ahead of time. All chains performing the changeover go through rigorous testing - if bugs are caught and fixed the hash listed in the proposal may not be the most recent one.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," listed in the proposal MUST be before the ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height")," listed in the the upgrade proposal on the standalone chain."),(0,i.kt)("admonition",{parentName:"li",type:"caution"},(0,i.kt)("p",{parentName:"admonition"},(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," must occur before the ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height")," on the standalone chain is reached becasue the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider")," chain must generate the ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerGenesis")," that contains the ",(0,i.kt)("strong",{parentName:"p"},"validator set")," that will be used after the changeover."))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"unbonding_period")," must correspond to the value used on the standalone chain. Otherwise, the clients used for the ccv protocol may be incorrectly initialized.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"distribution_transmission_channel")," ",(0,i.kt)("strong",{parentName:"p"},"should be set"),"."))),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"Populating ",(0,i.kt)("inlineCode",{parentName:"p"},"distribution_transmission_channel")," will enable the standalone chain to re-use one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ",(0,i.kt)("inlineCode",{parentName:"p"},"ibc denom")," that may already be in use."),(0,i.kt)("p",{parentName:"admonition"},"If the parameter is not set, a new channel will be created.")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"ccv_timeout_period")," has no important notes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"transfer_timeout_period")," has no important notes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction")," has no important notes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission")," has no important notes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"historical_entries")," has no important notes"))),(0,i.kt)("h3",{id:"2-upgrade-proposal-on-standalone-chain"},"2. upgrade proposal on standalone chain"),(0,i.kt)("p",null,"The standalone chain creates an upgrade proposal to include the ",(0,i.kt)("inlineCode",{parentName:"p"},"interchain-security/x/ccv/consumer")," module."),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"The upgrade height in the proposal should correspond to a height that is after the ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," in the consumer addition proposal submitted to the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider")," chain.")),(0,i.kt)("p",null,"Otherwise, the upgrade is indistinguishable from a regular on-chain upgrade proposal."),(0,i.kt)("h3",{id:"3-spawn-time-is-reached"},"3. spawn time is reached"),(0,i.kt)("p",null,"When the ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," is reached on the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider")," it will generate a ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerGenesis")," that contains the validator set that will supercede the ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," validator set."),(0,i.kt)("p",null,"This ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerGenesis")," must be available on the standalone chain during the on-chain upgrade."),(0,i.kt)("h3",{id:"4-standalone-chain-upgrade"},"4. standalone chain upgrade"),(0,i.kt)("p",null,"Performing the on-chain upgrade on the standalone chain will add the ",(0,i.kt)("inlineCode",{parentName:"p"},"ccv/consumer")," module and allow the chain to become a ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer")," of replicated security."),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerGenesis")," must be exported to a file and placed in the correct folder on the standalone chain before the upgade."),(0,i.kt)("p",{parentName:"admonition"},"The file must be placed at the exact specified location, otherwise the upgrade will not be executed correctly."),(0,i.kt)("p",{parentName:"admonition"},"Usually the file is placed in ",(0,i.kt)("inlineCode",{parentName:"p"},"$NODE_HOME/config"),", but the file name and the exact directory is dictated by the upgrade code on the ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," chain."),(0,i.kt)("ul",{parentName:"admonition"},(0,i.kt)("li",{parentName:"ul"},"please check exact instructions provided by the ",(0,i.kt)("inlineCode",{parentName:"li"},"standalone")," chain team"))),(0,i.kt)("p",null,"After the ",(0,i.kt)("inlineCode",{parentName:"p"},"genesis.json")," file has been made available, the process is equivalent to a normal on-chain upgrade. The standalone validator set will sign the next couple of blocks before transferring control to ",(0,i.kt)("inlineCode",{parentName:"p"},"provider")," validator set."),(0,i.kt)("p",null,"The standalone validator set can still be slashed for any infractions if evidence is submitted within the ",(0,i.kt)("inlineCode",{parentName:"p"},"unboding_period"),"."),(0,i.kt)("h4",{id:"notes"},"Notes"),(0,i.kt)("p",null,"The changeover procedure may be updated in the future to create a seamless way of providing the validator set information to the standalone chain."),(0,i.kt)("h2",{id:"onboarding-checklist"},"Onboarding Checklist"),(0,i.kt)("p",null,"This onboarding checklist is slightly different from the one under ",(0,i.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.2.0/consumer-development/onboarding"},"Onboarding")),(0,i.kt)("p",null,"Additionally, you can check the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md"},"testnet repo")," for a comprehensive guide on preparing and launching consumer chains."),(0,i.kt)("h2",{id:"1-complete-testing--integration"},"1. Complete testing & integration"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test integration with gaia"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test your protocol with supported relayer versions (minimum hermes 1.4.1)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test the changeover procedure"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","reach out to the ICS team if you are facing issues")),(0,i.kt)("h2",{id:"2-create-an-onboarding-repository"},"2. Create an Onboarding Repository"),(0,i.kt)("p",null,"To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain."),(0,i.kt)("p",null,"This should include (at minimum):"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json with CCV data (after spawn time passes)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","information about relevant seed/peer nodes you are running"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","relayer information (compatible versions)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","copy of your governance proposal (as JSON)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","a script showing how to start your chain and connect to peers (optional)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable")),(0,i.kt)("p",null,"Example of such a repository can be found ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyphacoop/ics-testnets/tree/main/game-of-chains-2022/sputnik"},"here"),"."),(0,i.kt)("h2",{id:"3-submit-a-consumerchainaddition-governance-proposal-to-the-provider"},"3. Submit a ConsumerChainAddition Governance Proposal to the provider"),(0,i.kt)("p",null,"Before you submit a ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerChainAddition")," proposal, please provide a ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," that is ",(0,i.kt)("strong",{parentName:"p"},"before")," the the ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height")," of the upgrade that will introduce the ",(0,i.kt)("inlineCode",{parentName:"p"},"ccv module")," to your chain."),(0,i.kt)("admonition",{type:"danger"},(0,i.kt)("p",{parentName:"admonition"},"If the ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," happens after your ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height")," the provider will not be able to communicate the new validator set to be used after the changeover.")),(0,i.kt)("p",null,"Additionally, reach out to the community via the ",(0,i.kt)("a",{parentName:"p",href:"https://forum.cosmos.network/"},"forum")," to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine your chain's spawn time"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine consumer chain parameters to be put in the proposal"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take note to include a link to your onboarding repository")),(0,i.kt)("p",null,"Example of a consumer chain addition proposal."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},'// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain or add a standalone chain.\n// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.\n// It is recommended that spawn time occurs after the proposal end time and that it is scheduled to happen before the standalone chain upgrade\n// that sill introduce the ccv module.\n{\n // Title of the proposal\n "title": "Changeover Standalone chain",\n // Description of the proposal\n // format the text as a .md file and include the file in your onboarding repository\n "description": ".md description of your chain and all other relevant information",\n // Proposed chain-id of the new consumer chain.\n // Must be unique from all other consumer chain ids of the executing provider chain.\n "chain_id": "standalone-1",\n // Initial height of new consumer chain.\n // For a completely new chain, this will be {0,1}.\n "initial_height" : {\n // must correspond to current revision number of standalone chain\n // e.g. standalone-1 => "revision_number": 1\n "revision_number": 1,\n\n // must correspond to a height that is at least 1 block after the upgrade\n // that will add the `consumer` module to the standalone chain\n // e.g. "upgrade_height": 100 => "revision_height": 101\n "revision_number": 1,\n },\n // Hash of the consumer chain genesis state without the consumer CCV module genesis params.\n // => not relevant for changeover procedure\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n // Hash of the consumer chain binary that should be run by validators on standalone chain upgrade\n // => not relevant for changeover procedure as it may become stale\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n // Unbonding period for the consumer chain.\n // It should should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n // IBC transfer packets will timeout after this interval elapses.\n "transfer_timeout_period": 1800000000000,\n // The fraction of tokens allocated to the consumer redistribution address during distribution events.\n // The fraction is a string representing a decimal number. For example "0.75" would represent 75%.\n // The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.\n "consumer_redistribution_fraction": "0.75",\n // BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.\n // eg. send rewards to the provider every 1000 blocks\n "blocks_per_distribution_transmission": 1000,\n // The number of historical info entries to persist in store.\n // This param is a part of the cosmos sdk staking module. In the case of\n // a ccv enabled consumer chain, the ccv module acts as the staking module.\n "historical_entries": 10000,\n // The ID of a token transfer channel used for the Reward Distribution\n // sub-protocol. If DistributionTransmissionChannel == "", a new transfer\n // channel is created on top of the same connection as the CCV channel.\n // Note that transfer_channel_id is the ID of the channel end on the consumer chain.\n // it is most relevant for chains performing a standalone to consumer changeover\n // in order to maintan the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123" // NOTE: use existing transfer channel if available\n}\n')),(0,i.kt)("h2",{id:"3-submit-an-upgrade-proposal--prepare-for-changeover"},"3. Submit an Upgrade Proposal & Prepare for Changeover"),(0,i.kt)("p",null,"This proposal should add the ccv ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer")," module to your chain."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","proposal ",(0,i.kt)("inlineCode",{parentName:"li"},"upgrade_height")," must happen after ",(0,i.kt)("inlineCode",{parentName:"li"},"spawn_time")," in the ",(0,i.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal")),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","advise validators about the exact procedure for your chain and point them to your onboarding repository")),(0,i.kt)("h2",{id:"4-upgrade-time-"},"4. Upgrade time \ud83d\ude80"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","after ",(0,i.kt)("inlineCode",{parentName:"li"},"spawn_time"),", request ",(0,i.kt)("inlineCode",{parentName:"li"},"ConsumerGenesis")," from the ",(0,i.kt)("inlineCode",{parentName:"li"},"provider")," and place it in ",(0,i.kt)("inlineCode",{parentName:"li"},"/.sovereign/config/genesis.json")),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","upgrade the binary to the one listed in your ",(0,i.kt)("inlineCode",{parentName:"li"},"UpgradeProposal"))),(0,i.kt)("p",null,'The chain starts after at least 66.67% of standalone voting power comes online. The consumer chain is considered interchain secured once the "old" validator set signs a couple of blocks and transfers control to the ',(0,i.kt)("inlineCode",{parentName:"p"},"provider")," validator set."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","provide a repo with onboarding instructions for validators (it should already be listed in the proposal)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json after ",(0,i.kt)("inlineCode",{parentName:"li"},"spawn_time")," obtained from ",(0,i.kt)("inlineCode",{parentName:"li"},"provider")," (MUST contain the initial validator set)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/0c7ba0cc.5f25b7fc.js b/legacy/assets/js/0c7ba0cc.5f25b7fc.js new file mode 100644 index 0000000000..1067fceed3 --- /dev/null +++ b/legacy/assets/js/0c7ba0cc.5f25b7fc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4077],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>u});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=l(n),h=i,u=d["".concat(c,".").concat(h)]||d[h]||m[h]||o;return n?a.createElement(u,r(r({ref:t},p),{},{components:n})):a.createElement(u,r({ref:t},p))}));function u(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:i,r[1]=s;for(var l=2;l{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>m,frontMatter:()=>o,metadata:()=>s,toc:()=>l});var a=n(7462),i=(n(7294),n(3905));const o={sidebar_position:3,title:"Onboarding Checklist"},r="Consumer Onboarding Checklist",s={unversionedId:"consumer-development/onboarding",id:"version-v3.2.0/consumer-development/onboarding",title:"Onboarding Checklist",description:"The following checklists will aid in onboarding a new consumer chain to replicated security.",source:"@site/versioned_docs/version-v3.2.0/consumer-development/onboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/onboarding",permalink:"/interchain-security/legacy/v3.2.0/consumer-development/onboarding",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Onboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Consumer Chain Governance",permalink:"/interchain-security/legacy/v3.2.0/consumer-development/consumer-chain-governance"},next:{title:"Offboarding Checklist",permalink:"/interchain-security/legacy/v3.2.0/consumer-development/offboarding"}},c={},l=[{value:"1. Complete testing & integration",id:"1-complete-testing--integration",level:2},{value:"2. Create an Onboarding Repository",id:"2-create-an-onboarding-repository",level:2},{value:"3. Submit a Governance Proposal",id:"3-submit-a-governance-proposal",level:2},{value:"4. Launch",id:"4-launch",level:2}],p={toc:l},d="wrapper";function m(e){let{components:t,...n}=e;return(0,i.kt)(d,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"consumer-onboarding-checklist"},"Consumer Onboarding Checklist"),(0,i.kt)("p",null,"The following checklists will aid in onboarding a new consumer chain to replicated security."),(0,i.kt)("p",null,"Additionally, you can check the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md"},"testnet repo")," for a comprehensive guide on preparing and launching consumer chains."),(0,i.kt)("h2",{id:"1-complete-testing--integration"},"1. Complete testing & integration"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test integration with gaia"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test your protocol with supported relayer versions (minimum hermes 1.4.1)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","reach out to the ICS team if you are facing issues")),(0,i.kt)("h2",{id:"2-create-an-onboarding-repository"},"2. Create an Onboarding Repository"),(0,i.kt)("p",null,"To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain."),(0,i.kt)("p",null,"This should include (at minimum):"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json without CCV data (before the proposal passes)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json with CCV data (after spawn time passes)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","information about relevant seed/peer nodes you are running"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","relayer information (compatible versions)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","copy of your governance proposal (as JSON)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","a script showing how to start your chain and connect to peers (optional)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable")),(0,i.kt)("p",null,"Example of such a repository can be found ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyphacoop/ics-testnets/tree/main/game-of-chains-2022/sputnik"},"here"),"."),(0,i.kt)("h2",{id:"3-submit-a-governance-proposal"},"3. Submit a Governance Proposal"),(0,i.kt)("p",null,"Before you submit a ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerChainAddition")," proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch.\nIf possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues."),(0,i.kt)("p",null,"Additionally, reach out to the community via the ",(0,i.kt)("a",{parentName:"p",href:"https://forum.cosmos.network/"},"forum")," to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine your chain's spawn time"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine consumer chain parameters to be put in the proposal"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take note to include a link to your onboarding repository"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","describe the purpose and benefits of running your chain")),(0,i.kt)("p",null,"Example of a consumer chain addition proposal."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},'// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.\n// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.\n// It is recommended that spawn time occurs after the proposal end time.\n{\n // Title of the proposal\n "title": "Add consumer chain",\n // Description of the proposal\n // format the text as a .md file and include the file in your onboarding repository\n "description": ".md description of your chain and all other relevant information",\n // Proposed chain-id of the new consumer chain.\n // Must be unique from all other consumer chain ids of the executing provider chain.\n "chain_id": "newchain-1",\n // Initial height of new consumer chain.\n // For a completely new chain, this will be {0,1}.\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Hash of the consumer chain genesis state without the consumer CCV module genesis params.\n // It is used for off-chain confirmation of genesis.json validity by validators and other parties.\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n // Hash of the consumer chain binary that should be run by validators on chain initialization.\n // It is used for off-chain confirmation of binary validity by validators and other parties.\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n // Unbonding period for the consumer chain.\n // It should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n // IBC transfer packets will timeout after this interval elapses.\n "transfer_timeout_period": 1800000000000,\n // The fraction of tokens allocated to the consumer redistribution address during distribution events.\n // The fraction is a string representing a decimal number. For example "0.75" would represent 75%.\n // The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.\n "consumer_redistribution_fraction": "0.75",\n // BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.\n // eg. send rewards to the provider every 1000 blocks\n "blocks_per_distribution_transmission": 1000,\n // The number of historical info entries to persist in store.\n // This param is a part of the cosmos sdk staking module. In the case of\n // a ccv enabled consumer chain, the ccv module acts as the staking module.\n "historical_entries": 10000,\n // The ID of a token transfer channel used for the Reward Distribution\n // sub-protocol. If DistributionTransmissionChannel == "", a new transfer\n // channel is created on top of the same connection as the CCV channel.\n // Note that transfer_channel_id is the ID of the channel end on the consumer chain.\n // it is most relevant for chains performing a sovereign to consumer changeover\n // in order to maintain the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123"\n}\n')),(0,i.kt)("h2",{id:"4-launch"},"4. Launch"),(0,i.kt)("p",null,"The consumer chain starts after at least 66.67% of all provider's voting power comes online. The consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","provide a repo with onboarding instructions for validators (it should already be listed in the proposal)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json with ccv data populated (MUST contain the initial validator set)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","have a block explorer in place to track chain activity & health")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/0cb1d302.664303dc.js b/legacy/assets/js/0cb1d302.664303dc.js new file mode 100644 index 0000000000..aacdc6ad0f --- /dev/null +++ b/legacy/assets/js/0cb1d302.664303dc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1085],{3905:(e,t,r)=>{r.d(t,{Zo:()=>l,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},l=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),p=u(r),f=o,m=p["".concat(s,".").concat(f)]||p[f]||d[f]||i;return r?n.createElement(m,a(a({ref:t},l),{},{components:r})):n.createElement(m,a({ref:t},l))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[p]="string"==typeof e?e:o,a[1]=c;for(var u=2;u{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>d,frontMatter:()=>i,metadata:()=>c,toc:()=>u});var n=r(7462),o=(r(7294),r(3905));const i={sidebar_position:5},a="Joining Neutron",c={unversionedId:"validators/joining-neutron",id:"validators/joining-neutron",title:"Joining Neutron",description:"Neutron is the first consumer chain to implement ICS.",source:"@site/docs/validators/joining-neutron.md",sourceDirName:"validators",slug:"/validators/joining-neutron",permalink:"/interchain-security/legacy/validators/joining-neutron",draft:!1,tags:[],version:"current",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Validator instructions for Changeover Procedure",permalink:"/interchain-security/legacy/validators/changeover-procedure"},next:{title:"Joining Stride",permalink:"/interchain-security/legacy/validators/joining-stride"}},s={},u=[{value:"Resources",id:"resources",level:2}],l={toc:u},p="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(p,(0,n.Z)({},l,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"joining-neutron"},"Joining Neutron"),(0,o.kt)("p",null,"Neutron is the first consumer chain to implement ICS."),(0,o.kt)("p",null,"You can find instructions on joining the mainnet ",(0,o.kt)("a",{parentName:"p",href:"https://docs.neutron.org/neutron/consumer-chain-launch"},"here"),"."),(0,o.kt)("p",null,"To join Neutron chain on the replicated security testnet check ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security/pion-1"},"here")),(0,o.kt)("h2",{id:"resources"},"Resources"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.neutron.org"},"Neutron docs"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/10e700ac.642210c3.js b/legacy/assets/js/10e700ac.642210c3.js new file mode 100644 index 0000000000..65bacc5aa4 --- /dev/null +++ b/legacy/assets/js/10e700ac.642210c3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3493],{3905:(e,n,t)=>{t.d(n,{Zo:()=>m,kt:()=>d});var r=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var s=r.createContext({}),l=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},m=function(e){var n=l(e.components);return r.createElement(s.Provider,{value:n},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},p=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,m=c(e,["components","mdxType","originalType","parentName"]),u=l(t),p=o,d=u["".concat(s,".").concat(p)]||u[p]||h[p]||a;return t?r.createElement(d,i(i({ref:n},m),{},{components:t})):r.createElement(d,i({ref:n},m))}));function d(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=p;var c={};for(var s in n)hasOwnProperty.call(n,s)&&(c[s]=n[s]);c.originalType=e,c[u]="string"==typeof e?e:o,i[1]=c;for(var l=2;l{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>h,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var r=t(7462),o=(t(7294),t(3905));const a={sidebar_position:2},i="Consumer Chain Governance",c={unversionedId:"consumer-development/consumer-chain-governance",id:"version-v3.3.1-lsm/consumer-development/consumer-chain-governance",title:"Consumer Chain Governance",description:'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.',source:"@site/versioned_docs/version-v3.3.1-lsm/consumer-development/consumer-chain-governance.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-chain-governance",permalink:"/interchain-security/legacy/consumer-development/consumer-chain-governance",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/legacy/consumer-development/app-integration"},next:{title:"Onboarding Checklist",permalink:"/interchain-security/legacy/consumer-development/onboarding"}},s={},l=[{value:"Democracy module",id:"democracy-module",level:2},{value:"CosmWasm",id:"cosmwasm",level:2},{value:"The Whitelist",id:"the-whitelist",level:2}],m={toc:l},u="wrapper";function h(e){let{components:n,...t}=e;return(0,o.kt)(u,(0,r.Z)({},m,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-chain-governance"},"Consumer Chain Governance"),(0,o.kt)("p",null,'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.'),(0,o.kt)("h2",{id:"democracy-module"},"Democracy module"),(0,o.kt)("p",null,"The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy."),(0,o.kt)("p",null,"Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus."),(0,o.kt)("p",null,"For an example, see the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy"},"Democracy Consumer")),(0,o.kt)("h2",{id:"cosmwasm"},"CosmWasm"),(0,o.kt)("p",null,"There are several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain."),(0,o.kt)("p",null,"For an example, see ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/neutron-org/neutron/"},"Neutron"),"."),(0,o.kt)("h2",{id:"the-whitelist"},"The Whitelist"),(0,o.kt)("p",null,"Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/neutron-org/neutron/blob/main/app/proposals_allowlisting.go"},"Neutron's")," whitelist."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/11e17b14.970968fa.js b/legacy/assets/js/11e17b14.970968fa.js new file mode 100644 index 0000000000..a7c01550d8 --- /dev/null +++ b/legacy/assets/js/11e17b14.970968fa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6398],{3905:(e,r,n)=>{n.d(r,{Zo:()=>p,kt:()=>f});var t=n(7294);function o(e,r,n){return r in e?Object.defineProperty(e,r,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[r]=n,e}function i(e,r){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);r&&(t=t.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),n.push.apply(n,t)}return n}function a(e){for(var r=1;r=0||(o[n]=e[n]);return o}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=t.createContext({}),s=function(e){var r=t.useContext(u),n=r;return e&&(n="function"==typeof e?e(r):a(a({},r),e)),n},p=function(e){var r=s(e.components);return t.createElement(u.Provider,{value:r},e.children)},l="mdxType",m={inlineCode:"code",wrapper:function(e){var r=e.children;return t.createElement(t.Fragment,{},r)}},d=t.forwardRef((function(e,r){var n=e.components,o=e.mdxType,i=e.originalType,u=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),l=s(n),d=o,f=l["".concat(u,".").concat(d)]||l[d]||m[d]||i;return n?t.createElement(f,a(a({ref:r},p),{},{components:n})):t.createElement(f,a({ref:r},p))}));function f(e,r){var n=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var c={};for(var u in r)hasOwnProperty.call(r,u)&&(c[u]=r[u]);c.originalType=e,c[l]="string"==typeof e?e:o,a[1]=c;for(var s=2;s{n.r(r),n.d(r,{assets:()=>u,contentTitle:()=>a,default:()=>m,frontMatter:()=>i,metadata:()=>c,toc:()=>s});var t=n(7462),o=(n(7294),n(3905));const i={sidebar_position:3},a="Upgrading Consumer Chains",c={unversionedId:"consumer-development/consumer-chain-upgrade-procedure",id:"version-v2.0.0/consumer-development/consumer-chain-upgrade-procedure",title:"Upgrading Consumer Chains",description:"",source:"@site/versioned_docs/version-v2.0.0/consumer-development/consumer-chain-upgrade-procedure.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-chain-upgrade-procedure",permalink:"/interchain-security/legacy/v2.0.0/consumer-development/consumer-chain-upgrade-procedure",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Consumer Chain Governance",permalink:"/interchain-security/legacy/v2.0.0/consumer-development/consumer-chain-governance"},next:{title:"Onboarding Checklist",permalink:"/interchain-security/legacy/v2.0.0/consumer-development/onboarding"}},u={},s=[],p={toc:s},l="wrapper";function m(e){let{components:r,...n}=e;return(0,o.kt)(l,(0,t.Z)({},p,n,{components:r,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"upgrading-consumer-chains"},"Upgrading Consumer Chains"))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/14ce44a3.f1e70d90.js b/legacy/assets/js/14ce44a3.f1e70d90.js new file mode 100644 index 0000000000..3df24db628 --- /dev/null +++ b/legacy/assets/js/14ce44a3.f1e70d90.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9759],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>v});var i=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function r(e){for(var n=1;n=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=i.createContext({}),u=function(e){var n=i.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):r(r({},n),e)),t},p=function(e){var n=u(e.components);return i.createElement(l.Provider,{value:n},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},h=i.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=u(t),h=o,v=d["".concat(l,".").concat(h)]||d[h]||c[h]||a;return t?i.createElement(v,r(r({ref:n},p),{},{components:t})):i.createElement(v,r({ref:n},p))}));function v(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,r=new Array(a);r[0]=h;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:o,r[1]=s;for(var u=2;u{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>r,default:()=>c,frontMatter:()=>a,metadata:()=>s,toc:()=>u});var i=t(7462),o=(t(7294),t(3905));const a={sidebar_position:2,title:"ADR Template"},r="ADR 007: Pause validator unbonding during equivocation proposal",s={unversionedId:"adrs/adr-007-pause-unbonding-on-eqv-prop",id:"version-v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-prop",title:"ADR Template",description:"Changelog",source:"@site/versioned_docs/version-v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-prop.md",sourceDirName:"adrs",slug:"/adrs/adr-007-pause-unbonding-on-eqv-prop",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-prop",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"ADR Template"},sidebar:"tutorialSidebar",previous:{title:"ADRs",permalink:"/interchain-security/legacy/v3.1.0/adrs/intro"},next:{title:"ADR Template",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-template"}},l={},u=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"How",id:"how",level:3},{value:"When pause",id:"when-pause",level:3},{value:"When unpause",id:"when-unpause",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],p={toc:u},d="wrapper";function c(e){let{components:n,...t}=e;return(0,o.kt)(d,(0,i.Z)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"adr-007-pause-validator-unbonding-during-equivocation-proposal"},"ADR 007: Pause validator unbonding during equivocation proposal"),(0,o.kt)("h2",{id:"changelog"},"Changelog"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"2023-05-16: Initial Draft")),(0,o.kt)("h2",{id:"status"},"Status"),(0,o.kt)("p",null,"Proposed"),(0,o.kt)("h2",{id:"context"},"Context"),(0,o.kt)("p",null,"Currently, if an equivocation slashing proposal is created after more than one\nweek has passed since the equivocation, it is possible that the validator in\nquestion could unbond and get away without being slashed, since the unbonding\nperiod is 3 weeks, and the voting period is 2 weeks. For this reason, it might\nbe good to pause unbondings for validators named in an equivocation slashing\nproposal until the proposal's voting period is over."),(0,o.kt)("h2",{id:"decision"},"Decision"),(0,o.kt)("h3",{id:"how"},"How"),(0,o.kt)("p",null,"Pausing the unbonding period is already possible thanks to the changes in the\n",(0,o.kt)("inlineCode",{parentName:"p"},"staking")," module of the cosmos-sdk:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"stakingKeeper.PutUnbondingOnHold")," pauses an unbonding period"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"stakingKeeper.UnbondingCanComplete")," unpauses an unbonding period")),(0,o.kt)("p",null,"These methods use a reference counter under the hood, that gets incremented\nevery time ",(0,o.kt)("inlineCode",{parentName:"p"},"PutUnbondingOnHold")," is called, and decreased when\n",(0,o.kt)("inlineCode",{parentName:"p"},"UnbondingCanComplete")," is called instead. A specific unbonding is considered\nfully unpaused when its underlying reference counter reaches 0. Therefore, as\nlong as we safeguard consistency - i.e. we make sure we eventually decrement\nthe reference counter for each time we have incremented it - we can safely use\nthis existing mechanism without conflicts with the ",(0,o.kt)("em",{parentName:"p"},"Completion of Unbonding\nOperations")," system."),(0,o.kt)("h3",{id:"when-pause"},"When pause"),(0,o.kt)("p",null,"The unbonding period (if there is any unbonding) should be paused once an\nequivocation proposal enters the voting period. For that, the ",(0,o.kt)("inlineCode",{parentName:"p"},"gov")," module's\nhook ",(0,o.kt)("inlineCode",{parentName:"p"},"AfterProposalDeposit")," can be used. "),(0,o.kt)("p",null,"If the hook is triggered with a an equivocation proposal in voting period, then\nfor each equivocation of the proposal, the unbonding operations of the related\nvalidator that were initiated after the equivocation block time must be paused"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"i.e. the underlying reference counter has to be increased.")),(0,o.kt)("p",null,"Note that even after the voting period has started, a proposal can receive\nadditional deposits. The hook is triggered however at arrival of a deposit, so\na check to verify that the proposal is not already in voting period is\nrequired."),(0,o.kt)("h3",{id:"when-unpause"},"When unpause"),(0,o.kt)("p",null,"We can use a ",(0,o.kt)("inlineCode",{parentName:"p"},"gov")," module's hook also here and it is\n",(0,o.kt)("inlineCode",{parentName:"p"},"AfterProposalVotingPeriodEnded"),"."),(0,o.kt)("p",null,"If the hook is triggered with an equivocation proposal, then for each\nassociated equivocation, the unbonding operations of the related validator that\nwere initiated between the equivocation block time and the start of the\nproposal voting period must be unpaused - i.e. decrease the underlying\nreference counter - regardless of the proposal outcome."),(0,o.kt)("h2",{id:"consequences"},"Consequences"),(0,o.kt)("h3",{id:"positive"},"Positive"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Validators subject to an equivocation proposal cannot finish unbonding\ntheir tokens before the end of the voting period.")),(0,o.kt)("h3",{id:"negative"},"Negative"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"A malicious consumer chain could forge slash packets enabling submission of\nan equivocation proposal on the provider chain, resulting in the freezing of\nvalidator's unbondings for an undeterminated amount of time."),(0,o.kt)("li",{parentName:"ul"},"Misbehavior on a consumer chain can potentially go unpunished, if no one\nsubmits an equivocation proposal in time, or if the proposal doesn't pass.")),(0,o.kt)("h3",{id:"neutral"},"Neutral"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"This feature can't be used for social slashing, because an equivocation\nproposal is only accepted if there's a slash log for the related\nvalidator(s), meaning the consumer chain has reported the equivocation to\nthe provider chain.")),(0,o.kt)("h2",{id:"references"},"References"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/747"},"https://github.com/cosmos/interchain-security/issues/747")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/791"},"https://github.com/cosmos/interchain-security/pull/791"))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/1560cd4f.1afd62f5.js b/legacy/assets/js/1560cd4f.1afd62f5.js new file mode 100644 index 0000000000..a2089dc9ab --- /dev/null +++ b/legacy/assets/js/1560cd4f.1afd62f5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3858],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>h});var r=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function s(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function o(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var d=r.createContext({}),l=function(e){var n=r.useContext(d),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=l(e.components);return r.createElement(d.Provider,{value:n},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,s=e.originalType,d=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),c=l(t),m=a,h=c["".concat(d,".").concat(m)]||c[m]||p[m]||s;return t?r.createElement(h,o(o({ref:n},u),{},{components:t})):r.createElement(h,o({ref:n},u))}));function h(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var s=t.length,o=new Array(s);o[0]=m;var i={};for(var d in n)hasOwnProperty.call(n,d)&&(i[d]=n[d]);i.originalType=e,i[c]="string"==typeof e?e:a,o[1]=i;for(var l=2;l{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>p,frontMatter:()=>s,metadata:()=>i,toc:()=>l});var r=t(7462),a=(t(7294),t(3905));const s={sidebar_position:3,title:"Key Assignment"},o="ADR 001: Key Assignment",i={unversionedId:"adrs/adr-001-key-assignment",id:"version-v2.0.0/adrs/adr-001-key-assignment",title:"Key Assignment",description:"Changelog",source:"@site/versioned_docs/version-v2.0.0/adrs/adr-001-key-assignment.md",sourceDirName:"adrs",slug:"/adrs/adr-001-key-assignment",permalink:"/interchain-security/legacy/v2.0.0/adrs/adr-001-key-assignment",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Key Assignment"},sidebar:"tutorialSidebar",previous:{title:"ADR Template",permalink:"/interchain-security/legacy/v2.0.0/adrs/adr-template"},next:{title:"Jail Throttling",permalink:"/interchain-security/legacy/v2.0.0/adrs/adr-002-throttle"}},d={},l=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"State required",id:"state-required",level:3},{value:"Protocol overview",id:"protocol-overview",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],u={toc:l},c="wrapper";function p(e){let{components:n,...t}=e;return(0,a.kt)(c,(0,r.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-001-key-assignment"},"ADR 001: Key Assignment"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"2022-12-01: Initial Draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"It is possible to change the keys at any time by submitting a transaction (i.e., ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey"),")."),(0,a.kt)("h3",{id:"state-required"},"State required"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorConsumerPubKey")," - Stores the validator assigned keys for every consumer chain.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorByConsumerAddr")," - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"KeyAssignmentReplacements")," - Stores the key assignments that need to be replaced in the current block. Needed to apply the key assignments received in a block to the validator updates sent to the consumer chains.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"KeyAssignmentReplacementsBytePrefix | len(chainID) | chainID | providerConsAddress -> abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower},\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ConsumerAddrsToPrune")," - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ",(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorByConsumerAddr"),". ")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses\n")),(0,a.kt)("h3",{id:"protocol-overview"},"Protocol overview"),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey(chainID, providerAddr, consumerKey)")," message:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"// get validator from staking module \nvalidator, found := stakingKeeper.GetValidator(providerAddr)\nif !found {\n return ErrNoValidatorFound\n}\nproviderConsAddr := validator.GetConsAddr()\n\n// make sure consumer key is not in use\nconsumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)\nif _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {\n return ErrInvalidConsumerConsensusPubKey\n}\n\n// check whether the consumer chain is already registered\n// i.e., a client to the consumer was already created\nif _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {\n // get the previous key assigned for this validator on this consumer chain\n oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)\n if found {\n // mark this old consumer key as prunable once the VSCMaturedPacket\n // for the current VSC ID is received\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n vscID := GetValidatorSetUpdateId()\n AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)\n } else {\n // the validator had no key assigned on this consumer chain\n oldConsumerKey := validator.TmConsPublicKey()\n }\n\n // check whether the validator is valid, i.e., its power is positive\n if currentPower := stakingKeeper.GetLastValidatorPower(providerAddr); currentPower > 0 {\n // to enable multiple calls of AssignConsumerKey in the same block by the same validator\n // the key assignment replacement should not be overwritten\n if _, found := GetKeyAssignmentReplacement(chainID, providerConsAddr); !found {\n // store old key and power for modifying the valset update in EndBlock\n oldKeyAssignment := abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower}\n SetKeyAssignmentReplacement(chainID, providerConsAddr, oldKeyAssignment)\n }\n }\n} else {\n // if the consumer chain is not registered, then remove the previous reverse mapping\n if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)\n }\n}\n\n\n// set the mapping from this validator's provider address to the new consumer key\nSetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)\n\n// set the reverse mapping: from this validator's new consensus address \n// on the consumer to its consensus address on the provider\nSetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)\n")),(0,a.kt)("p",null,"When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see ",(0,a.kt)("inlineCode",{parentName:"p"},"MakeConsumerGenesis"),"). "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {\n // ...\n // get initial valset from the staking module\n var updates []abci.ValidatorUpdate{}\n stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {\n validator := stakingKeeper.GetValidator(providerAddr)\n providerKey := validator.TmConsPublicKey()\n updates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})\n return false\n })\n\n // applies the key assignment to the initial validator\n for i, update := range updates {\n providerAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)\n if consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {\n updates[i].PubKey = consumerKey\n }\n }\n gen.InitialValSet = updates\n\n // get a hash of the consumer validator set from the update\n updatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)\n hash := tendermint.NewValidatorSet(updatesAsValSet).Hash()\n\n return gen, hash, nil\n}\n")),(0,a.kt)("p",null,"On ",(0,a.kt)("inlineCode",{parentName:"p"},"EndBlock")," while queueing ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCPacket"),"s to send to registered consumer chains:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func QueueVSCPackets() {\n valUpdateID := GetValidatorSetUpdateId()\n // get the validator updates from the staking module\n valUpdates := stakingKeeper.GetValidatorUpdates()\n\n IterateConsumerChains(func(chainID, clientID string) (stop bool) {\n // apply the key assignment to the validator updates\n valUpdates := ApplyKeyAssignmentToValUpdates(chainID, valUpdates)\n // ..\n })\n // ...\n}\n\nfunc ApplyKeyAssignmentToValUpdates(\n chainID string, \n valUpdates []abci.ValidatorUpdate,\n) (newUpdates []abci.ValidatorUpdate) {\n for _, valUpdate := range valUpdates {\n providerAddr := utils.TMCryptoPublicKeyToConsAddr(valUpdate.PubKey)\n\n // if a key assignment replacement is found, then\n // remove the valupdate with the old consumer key\n // and create two new valupdates\n prevConsumerKey, _, found := GetKeyAssignmentReplacement(chainID, providerAddr)\n if found {\n // set the old consumer key's power to 0\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: prevConsumerKey,\n Power: 0,\n })\n // set the new consumer key's power to the power in the update\n newConsumerKey := GetValidatorConsumerPubKey(chainID, providerAddr)\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: newConsumerKey,\n Power: valUpdate.Power,\n })\n // delete key assignment replacement\n DeleteKeyAssignmentReplacement(chainID, providerAddr)\n } else {\n // there is no key assignment replacement;\n // check if the validator's key is assigned\n consumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr)\n if found {\n // replace the update containing the provider key \n // with an update containing the consumer key\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: consumerKey,\n Power: valUpdate.Power,\n })\n } else {\n // keep the same update\n newUpdates = append(newUpdates, valUpdate)\n }\n }\n }\n\n // iterate over the remaining key assignment replacements\n IterateKeyAssignmentReplacements(chainID, func(\n pAddr sdk.ConsAddress,\n prevCKey tmprotocrypto.PublicKey,\n power int64,\n ) (stop bool) {\n // set the old consumer key's power to 0\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: prevCKey,\n Power: 0,\n })\n // set the new consumer key's power to the power in key assignment replacement\n newConsumerKey := GetValidatorConsumerPubKey(chainID, pAddr)\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: newConsumerKey,\n Power: power,\n })\n return false\n })\n\n // remove all the key assignment replacements\n \n return newUpdates\n}\n")),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"SlashPacket")," from a consumer chain with id ",(0,a.kt)("inlineCode",{parentName:"p"},"chainID")," for a infraction of a validator ",(0,a.kt)("inlineCode",{parentName:"p"},"data.Validator"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {\n // ...\n // the slash packet validator address may be known only on the consumer chain;\n // in this case, it must be mapped back to the consensus address on the provider chain\n consumerAddr := sdk.ConsAddress(data.Validator.Address)\n providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)\n if !found {\n // the validator has the same key on the consumer as on the provider\n providerAddr = consumer\n }\n // ...\n}\n")),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCMatured"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {\n // ...\n // prune previous consumer validator address that are no longer needed\n consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n for _, addr := range consumerAddrs {\n DeleteValidatorByConsumerAddr(chainID, addr)\n }\n DeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n // ...\n}\n")),(0,a.kt)("p",null,"On stopping a consumer chain:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {\n // ...\n // deletes all the state needed for key assignments on this consumer chain\n // ...\n}\n")),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Validators can use different consensus keys on the consumer chains.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"None")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"The consensus state necessary to create a client to the consumer chain must use the hash returned by the ",(0,a.kt)("inlineCode",{parentName:"li"},"MakeConsumerGenesis")," method as the ",(0,a.kt)("inlineCode",{parentName:"li"},"nextValsHash"),"."),(0,a.kt)("li",{parentName:"ul"},"The consumer chain can no longer check the initial validator set against the consensus state on ",(0,a.kt)("inlineCode",{parentName:"li"},"InitGenesis"),".")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/26"},"Key assignment issue"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/17896441.a6244cb7.js b/legacy/assets/js/17896441.a6244cb7.js new file mode 100644 index 0000000000..ecea9c4ecc --- /dev/null +++ b/legacy/assets/js/17896441.a6244cb7.js @@ -0,0 +1 @@ +(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7918],{3905:(e,t,n)=>{"use strict";n.d(t,{Zo:()=>d,kt:()=>f});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var i=a.createContext({}),s=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},d=function(e){var t=s(e.components);return a.createElement(i.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},p=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,i=e.parentName,d=c(e,["components","mdxType","originalType","parentName"]),m=s(n),p=o,f=m["".concat(i,".").concat(p)]||m[p]||u[p]||r;return n?a.createElement(f,l(l({ref:t},d),{},{components:n})):a.createElement(f,l({ref:t},d))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,l=new Array(r);l[0]=p;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c[m]="string"==typeof e?e:o,l[1]=c;for(var s=2;se.reference?o.default.createElement(r.default,{...e}):o.default.createElement(l.default,{...e}))},5971:function(e,t,n){"use strict";var a=this&&this.__createBinding||(Object.create?function(e,t,n,a){void 0===a&&(a=n),Object.defineProperty(e,a,{enumerable:!0,get:function(){return t[n]}})}:function(e,t,n,a){void 0===a&&(a=n),e[a]=t[n]}),o=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),r=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&a(t,e,n);return o(t,e),t},l=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.codeReducer=t.parseReference=void 0;const c=r(n(7294)),i=l(n(614)),s={code:"loading...",error:null,loading:null},d={fontSize:".9em",fontWeight:600,color:"#0E75DD",textAlign:"center",paddingBottom:"13px",textDecoration:"underline"};function m(e){const t=e.slice(e.indexOf("https"),-1),[n,a]=t.split("#"),o=globalThis||{};o.URL||(o.URL=URL);const[r,l,c,i,...s]=new o.URL(n).pathname.split("/").slice(1),[d,m]=a?a.split("-").map((e=>parseInt(e.slice(1),10)-1)):[0,1/0];return{url:`https://raw.githubusercontent.com/${r}/${l}/${i}/${s.join("/")}`,fromLine:d,toLine:m,title:s.join("/")}}function u(e,{type:t,value:n}){switch(t){case"reset":return s;case"loading":return{...e,loading:!0};case"loaded":return{...e,code:n,loading:!1};case"error":return{...e,error:n,loading:!1};default:return e}}t.parseReference=m,t.codeReducer=u,t.default=function(e){var t,n,a;const[o,r]=c.useReducer(u,s),l=m(e.children);!1!==o.loading&&async function({url:e,fromLine:t,toLine:n},a){let o;try{o=await fetch(e)}catch(c){return a({type:"error",value:c})}if(200!==o.status)return a({type:"error",value:await o.text()});const r=(await o.text()).split("\n").slice(t,(n||t)+1),l=r.reduce(((e,t)=>{if(0===t.length)return e;const n=t.match(/^\s+/);return n?Math.min(e,n[0].length):0}),1/0);a({type:"loaded",value:r.map((e=>e.slice(l))).join("\n")})}(l,r);const p=null===(t=e.metastring)||void 0===t?void 0:t.match(/title="(?.*)"/),f={...e,metastring:(null===(n=null==p?void 0:p.groups)||void 0===n?void 0:n.title)?` title="${null===(a=null==p?void 0:p.groups)||void 0===a?void 0:a.title}"`:` title="${l.title}"`,children:s.code};return c.default.createElement("div",null,c.default.createElement(i.default,{...f},o.code),c.default.createElement("div",{style:d},c.default.createElement("a",{href:e.children,target:"_blank"},"See full example on GitHub")))}},614:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>F});var a=n(7462),o=n(7294),r=n(2389),l=n(6010),c=n(2949),i=n(6668);function s(){const{prism:e}=(0,i.L)(),{colorMode:t}=(0,c.I)(),n=e.theme,a=e.darkTheme||n;return"dark"===t?a:n}var d=n(5281),m=n(7594),u=n.n(m);const p=/title=(?<quote>["'])(?<title>.*?)\1/,f=/\{(?<range>[\d,-]+)\}/,h={js:{start:"\\/\\/",end:""},jsBlock:{start:"\\/\\*",end:"\\*\\/"},jsx:{start:"\\{\\s*\\/\\*",end:"\\*\\/\\s*\\}"},bash:{start:"#",end:""},html:{start:"\x3c!--",end:"--\x3e"}};function g(e,t){const n=e.map((e=>{const{start:n,end:a}=h[e];return`(?:${n}\\s*(${t.flatMap((e=>[e.line,e.block?.start,e.block?.end].filter(Boolean))).join("|")})\\s*${a})`})).join("|");return new RegExp(`^\\s*(?:${n})\\s*$`)}function b(e,t){let n=e.replace(/\n$/,"");const{language:a,magicComments:o,metastring:r}=t;if(r&&f.test(r)){const e=r.match(f).groups.range;if(0===o.length)throw new Error(`A highlight range has been given in code block's metastring (\`\`\` ${r}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges.`);const t=o[0].className,a=u()(e).filter((e=>e>0)).map((e=>[e-1,[t]]));return{lineClassNames:Object.fromEntries(a),code:n}}if(void 0===a)return{lineClassNames:{},code:n};const l=function(e,t){switch(e){case"js":case"javascript":case"ts":case"typescript":return g(["js","jsBlock"],t);case"jsx":case"tsx":return g(["js","jsBlock","jsx"],t);case"html":return g(["js","jsBlock","html"],t);case"python":case"py":case"bash":return g(["bash"],t);case"markdown":case"md":return g(["html","jsx","bash"],t);default:return g(Object.keys(h),t)}}(a,o),c=n.split("\n"),i=Object.fromEntries(o.map((e=>[e.className,{start:0,range:""}]))),s=Object.fromEntries(o.filter((e=>e.line)).map((e=>{let{className:t,line:n}=e;return[n,t]}))),d=Object.fromEntries(o.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.start,t]}))),m=Object.fromEntries(o.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.end,t]})));for(let u=0;u<c.length;){const e=c[u].match(l);if(!e){u+=1;continue}const t=e.slice(1).find((e=>void 0!==e));s[t]?i[s[t]].range+=`${u},`:d[t]?i[d[t]].start=u:m[t]&&(i[m[t]].range+=`${i[m[t]].start}-${u-1},`),c.splice(u,1)}n=c.join("\n");const p={};return Object.entries(i).forEach((e=>{let[t,{range:n}]=e;u()(n).forEach((e=>{p[e]??=[],p[e].push(t)}))})),{lineClassNames:p,code:n}}const v={codeBlockContainer:"codeBlockContainer_Ckt0"};function E(e){let{as:t,...n}=e;const r=function(e){const t={color:"--prism-color",backgroundColor:"--prism-background-color"},n={};return Object.entries(e.plain).forEach((e=>{let[a,o]=e;const r=t[a];r&&"string"==typeof o&&(n[r]=o)})),n}(s());return o.createElement(t,(0,a.Z)({},n,{style:r,className:(0,l.Z)(n.className,v.codeBlockContainer,d.k.common.codeBlock)}))}const y={codeBlockContent:"codeBlockContent_biex",codeBlockTitle:"codeBlockTitle_Ktv7",codeBlock:"codeBlock_bY9V",codeBlockStandalone:"codeBlockStandalone_MEMb",codeBlockLines:"codeBlockLines_e6Vv",codeBlockLinesWithNumbering:"codeBlockLinesWithNumbering_o6Pm",buttonGroup:"buttonGroup__atx"};function k(e){let{children:t,className:n}=e;return o.createElement(E,{as:"pre",tabIndex:0,className:(0,l.Z)(y.codeBlockStandalone,"thin-scrollbar",n)},o.createElement("code",{className:y.codeBlockLines},t))}var N=n(902);const C={attributes:!0,characterData:!0,childList:!0,subtree:!0};function L(e,t){const[n,a]=(0,o.useState)(),r=(0,o.useCallback)((()=>{a(e.current?.closest("[role=tabpanel][hidden]"))}),[e,a]);(0,o.useEffect)((()=>{r()}),[r]),function(e,t,n){void 0===n&&(n=C);const a=(0,N.zX)(t),r=(0,N.Ql)(n);(0,o.useEffect)((()=>{const t=new MutationObserver(a);return e&&t.observe(e,r),()=>t.disconnect()}),[e,a,r])}(n,(e=>{e.forEach((e=>{"attributes"===e.type&&"hidden"===e.attributeName&&(t(),r())}))}),{attributes:!0,characterData:!1,childList:!1,subtree:!1})}const _={plain:{backgroundColor:"#2a2734",color:"#9a86fd"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#6c6783"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#e09142"}},{types:["property","function"],style:{color:"#9a86fd"}},{types:["tag-id","selector","atrule-id"],style:{color:"#eeebff"}},{types:["attr-name"],style:{color:"#c4b9fe"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","atrule","placeholder","variable"],style:{color:"#ffcc99"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#c4b9fe"}}]};var w={Prism:n(7410).Z,theme:_};function T(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function x(){return x=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var a in n)Object.prototype.hasOwnProperty.call(n,a)&&(e[a]=n[a])}return e},x.apply(this,arguments)}var Z=/\r\n|\r|\n/,B=function(e){0===e.length?e.push({types:["plain"],content:"\n",empty:!0}):1===e.length&&""===e[0].content&&(e[0].content="\n",e[0].empty=!0)},O=function(e,t){var n=e.length;return n>0&&e[n-1]===t?e:e.concat(t)},j=function(e,t){var n=e.plain,a=Object.create(null),o=e.styles.reduce((function(e,n){var a=n.languages,o=n.style;return a&&!a.includes(t)||n.types.forEach((function(t){var n=x({},e[t],o);e[t]=n})),e}),a);return o.root=n,o.plain=x({},n,{backgroundColor:null}),o};function H(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&-1===t.indexOf(a)&&(n[a]=e[a]);return n}const A=function(e){function t(){for(var t=this,n=[],a=arguments.length;a--;)n[a]=arguments[a];e.apply(this,n),T(this,"getThemeDict",(function(e){if(void 0!==t.themeDict&&e.theme===t.prevTheme&&e.language===t.prevLanguage)return t.themeDict;t.prevTheme=e.theme,t.prevLanguage=e.language;var n=e.theme?j(e.theme,e.language):void 0;return t.themeDict=n})),T(this,"getLineProps",(function(e){var n=e.key,a=e.className,o=e.style,r=x({},H(e,["key","className","style","line"]),{className:"token-line",style:void 0,key:void 0}),l=t.getThemeDict(t.props);return void 0!==l&&(r.style=l.plain),void 0!==o&&(r.style=void 0!==r.style?x({},r.style,o):o),void 0!==n&&(r.key=n),a&&(r.className+=" "+a),r})),T(this,"getStyleForToken",(function(e){var n=e.types,a=e.empty,o=n.length,r=t.getThemeDict(t.props);if(void 0!==r){if(1===o&&"plain"===n[0])return a?{display:"inline-block"}:void 0;if(1===o&&!a)return r[n[0]];var l=a?{display:"inline-block"}:{},c=n.map((function(e){return r[e]}));return Object.assign.apply(Object,[l].concat(c))}})),T(this,"getTokenProps",(function(e){var n=e.key,a=e.className,o=e.style,r=e.token,l=x({},H(e,["key","className","style","token"]),{className:"token "+r.types.join(" "),children:r.content,style:t.getStyleForToken(r),key:void 0});return void 0!==o&&(l.style=void 0!==l.style?x({},l.style,o):o),void 0!==n&&(l.key=n),a&&(l.className+=" "+a),l})),T(this,"tokenize",(function(e,t,n,a){var o={code:t,grammar:n,language:a,tokens:[]};e.hooks.run("before-tokenize",o);var r=o.tokens=e.tokenize(o.code,o.grammar,o.language);return e.hooks.run("after-tokenize",o),r}))}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.render=function(){var e=this.props,t=e.Prism,n=e.language,a=e.code,o=e.children,r=this.getThemeDict(this.props),l=t.languages[n];return o({tokens:function(e){for(var t=[[]],n=[e],a=[0],o=[e.length],r=0,l=0,c=[],i=[c];l>-1;){for(;(r=a[l]++)<o[l];){var s=void 0,d=t[l],m=n[l][r];if("string"==typeof m?(d=l>0?d:["plain"],s=m):(d=O(d,m.type),m.alias&&(d=O(d,m.alias)),s=m.content),"string"==typeof s){var u=s.split(Z),p=u.length;c.push({types:d,content:u[0]});for(var f=1;f<p;f++)B(c),i.push(c=[]),c.push({types:d,content:u[f]})}else l++,t.push(d),n.push(s),a.push(0),o.push(s.length)}l--,t.pop(),n.pop(),a.pop(),o.pop()}return B(c),i}(void 0!==l?this.tokenize(t,a,l,n):[a]),className:"prism-code language-"+n,style:void 0!==r?r.root:{},getLineProps:this.getLineProps,getTokenProps:this.getTokenProps})},t}(o.Component),M={codeLine:"codeLine_lJS_",codeLineNumber:"codeLineNumber_Tfdd",codeLineContent:"codeLineContent_feaV"};function S(e){let{line:t,classNames:n,showLineNumbers:r,getLineProps:c,getTokenProps:i}=e;1===t.length&&"\n"===t[0].content&&(t[0].content="");const s=c({line:t,className:(0,l.Z)(n,r&&M.codeLine)}),d=t.map(((e,t)=>o.createElement("span",(0,a.Z)({key:t},i({token:e,key:t})))));return o.createElement("span",s,r?o.createElement(o.Fragment,null,o.createElement("span",{className:M.codeLineNumber}),o.createElement("span",{className:M.codeLineContent},d)):d,o.createElement("br",null))}var I=n(5999);function P(e){return o.createElement("svg",(0,a.Z)({viewBox:"0 0 24 24"},e),o.createElement("path",{fill:"currentColor",d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"}))}function U(e){return o.createElement("svg",(0,a.Z)({viewBox:"0 0 24 24"},e),o.createElement("path",{fill:"currentColor",d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"}))}const D={copyButtonCopied:"copyButtonCopied_obH4",copyButtonIcons:"copyButtonIcons_eSgA",copyButtonIcon:"copyButtonIcon_y97N",copyButtonSuccessIcon:"copyButtonSuccessIcon_LjdS"};function z(e){let{code:t,className:n}=e;const[a,r]=(0,o.useState)(!1),c=(0,o.useRef)(void 0),i=(0,o.useCallback)((()=>{!function(e,t){let{target:n=document.body}=void 0===t?{}:t;if("string"!=typeof e)throw new TypeError(`Expected parameter \`text\` to be a \`string\`, got \`${typeof e}\`.`);const a=document.createElement("textarea"),o=document.activeElement;a.value=e,a.setAttribute("readonly",""),a.style.contain="strict",a.style.position="absolute",a.style.left="-9999px",a.style.fontSize="12pt";const r=document.getSelection(),l=r.rangeCount>0&&r.getRangeAt(0);n.append(a),a.select(),a.selectionStart=0,a.selectionEnd=e.length;let c=!1;try{c=document.execCommand("copy")}catch{}a.remove(),l&&(r.removeAllRanges(),r.addRange(l)),o&&o.focus()}(t),r(!0),c.current=window.setTimeout((()=>{r(!1)}),1e3)}),[t]);return(0,o.useEffect)((()=>()=>window.clearTimeout(c.current)),[]),o.createElement("button",{type:"button","aria-label":a?(0,I.I)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,I.I)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"}),title:(0,I.I)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,l.Z)("clean-btn",n,D.copyButton,a&&D.copyButtonCopied),onClick:i},o.createElement("span",{className:D.copyButtonIcons,"aria-hidden":"true"},o.createElement(P,{className:D.copyButtonIcon}),o.createElement(U,{className:D.copyButtonSuccessIcon})))}function R(e){return o.createElement("svg",(0,a.Z)({viewBox:"0 0 24 24"},e),o.createElement("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"}))}const V={wordWrapButtonIcon:"wordWrapButtonIcon_Bwma",wordWrapButtonEnabled:"wordWrapButtonEnabled_EoeP"};function W(e){let{className:t,onClick:n,isEnabled:a}=e;const r=(0,I.I)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return o.createElement("button",{type:"button",onClick:n,className:(0,l.Z)("clean-btn",t,a&&V.wordWrapButtonEnabled),"aria-label":r,title:r},o.createElement(R,{className:V.wordWrapButtonIcon,"aria-hidden":"true"}))}function $(e){let{children:t,className:n="",metastring:r,title:c,showLineNumbers:d,language:m}=e;const{prism:{defaultLanguage:u,magicComments:f}}=(0,i.L)(),h=m??function(e){const t=e.split(" ").find((e=>e.startsWith("language-")));return t?.replace(/language-/,"")}(n)??u,g=s(),v=function(){const[e,t]=(0,o.useState)(!1),[n,a]=(0,o.useState)(!1),r=(0,o.useRef)(null),l=(0,o.useCallback)((()=>{const n=r.current.querySelector("code");e?n.removeAttribute("style"):(n.style.whiteSpace="pre-wrap",n.style.overflowWrap="anywhere"),t((e=>!e))}),[r,e]),c=(0,o.useCallback)((()=>{const{scrollWidth:e,clientWidth:t}=r.current,n=e>t||r.current.querySelector("code").hasAttribute("style");a(n)}),[r]);return L(r,c),(0,o.useEffect)((()=>{c()}),[e,c]),(0,o.useEffect)((()=>(window.addEventListener("resize",c,{passive:!0}),()=>{window.removeEventListener("resize",c)})),[c]),{codeBlockRef:r,isEnabled:e,isCodeScrollable:n,toggle:l}}(),k=function(e){return e?.match(p)?.groups.title??""}(r)||c,{lineClassNames:N,code:C}=b(t,{metastring:r,language:h,magicComments:f}),_=d??function(e){return Boolean(e?.includes("showLineNumbers"))}(r);return o.createElement(E,{as:"div",className:(0,l.Z)(n,h&&!n.includes(`language-${h}`)&&`language-${h}`)},k&&o.createElement("div",{className:y.codeBlockTitle},k),o.createElement("div",{className:y.codeBlockContent},o.createElement(A,(0,a.Z)({},w,{theme:g,code:C,language:h??"text"}),(e=>{let{className:t,tokens:n,getLineProps:a,getTokenProps:r}=e;return o.createElement("pre",{tabIndex:0,ref:v.codeBlockRef,className:(0,l.Z)(t,y.codeBlock,"thin-scrollbar")},o.createElement("code",{className:(0,l.Z)(y.codeBlockLines,_&&y.codeBlockLinesWithNumbering)},n.map(((e,t)=>o.createElement(S,{key:t,line:e,getLineProps:a,getTokenProps:r,classNames:N[t],showLineNumbers:_})))))})),o.createElement("div",{className:y.buttonGroup},(v.isEnabled||v.isCodeScrollable)&&o.createElement(W,{className:y.codeButton,onClick:()=>v.toggle(),isEnabled:v.isEnabled}),o.createElement(z,{className:y.codeButton,code:C}))))}function F(e){let{children:t,...n}=e;const l=(0,r.Z)(),c=function(e){return o.Children.toArray(e).some((e=>(0,o.isValidElement)(e)))?e:Array.isArray(e)?e.join(""):e}(t),i="string"==typeof c?$:k;return o.createElement(i,(0,a.Z)({key:String(l)},n),c)}},3431:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>qe});var a=n(7294),o=n(1944),r=n(902);const l=a.createContext(null);function c(e){let{children:t,content:n}=e;const o=function(e){return(0,a.useMemo)((()=>({metadata:e.metadata,frontMatter:e.frontMatter,assets:e.assets,contentTitle:e.contentTitle,toc:e.toc})),[e])}(n);return a.createElement(l.Provider,{value:o},t)}function i(){const e=(0,a.useContext)(l);if(null===e)throw new r.i6("DocProvider");return e}function s(){const{metadata:e,frontMatter:t,assets:n}=i();return a.createElement(o.d,{title:e.title,description:e.description,keywords:t.keywords,image:n.image??t.image})}var d=n(6010),m=n(7524),u=n(7462),p=n(5999),f=n(9960);function h(e){const{permalink:t,title:n,subLabel:o,isNext:r}=e;return a.createElement(f.Z,{className:(0,d.Z)("pagination-nav__link",r?"pagination-nav__link--next":"pagination-nav__link--prev"),to:t},o&&a.createElement("div",{className:"pagination-nav__sublabel"},o),a.createElement("div",{className:"pagination-nav__label"},n))}function g(e){const{previous:t,next:n}=e;return a.createElement("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,p.I)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages",description:"The ARIA label for the docs pagination"})},t&&a.createElement(h,(0,u.Z)({},t,{subLabel:a.createElement(p.Z,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc"},"Previous")})),n&&a.createElement(h,(0,u.Z)({},n,{subLabel:a.createElement(p.Z,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc"},"Next"),isNext:!0})))}function b(){const{metadata:e}=i();return a.createElement(g,{previous:e.previous,next:e.next})}var v=n(2263),E=n(143),y=n(5281),k=n(373),N=n(4477);const C={unreleased:function(e){let{siteTitle:t,versionMetadata:n}=e;return a.createElement(p.Z,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:t,versionLabel:a.createElement("b",null,n.label)}},"This is unreleased documentation for {siteTitle} {versionLabel} version.")},unmaintained:function(e){let{siteTitle:t,versionMetadata:n}=e;return a.createElement(p.Z,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:t,versionLabel:a.createElement("b",null,n.label)}},"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.")}};function L(e){const t=C[e.versionMetadata.banner];return a.createElement(t,e)}function _(e){let{versionLabel:t,to:n,onClick:o}=e;return a.createElement(p.Z,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:t,latestVersionLink:a.createElement("b",null,a.createElement(f.Z,{to:n,onClick:o},a.createElement(p.Z,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label"},"latest version")))}},"For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).")}function w(e){let{className:t,versionMetadata:n}=e;const{siteConfig:{title:o}}=(0,v.Z)(),{pluginId:r}=(0,E.gA)({failfast:!0}),{savePreferredVersionName:l}=(0,k.J)(r),{latestDocSuggestion:c,latestVersionSuggestion:i}=(0,E.Jo)(r),s=c??(m=i).docs.find((e=>e.id===m.mainDocId));var m;return a.createElement("div",{className:(0,d.Z)(t,y.k.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert"},a.createElement("div",null,a.createElement(L,{siteTitle:o,versionMetadata:n})),a.createElement("div",{className:"margin-top--md"},a.createElement(_,{versionLabel:i.label,to:s.path,onClick:()=>l(i.name)})))}function T(e){let{className:t}=e;const n=(0,N.E)();return n.banner?a.createElement(w,{className:t,versionMetadata:n}):null}function x(e){let{className:t}=e;const n=(0,N.E)();return n.badge?a.createElement("span",{className:(0,d.Z)(t,y.k.docs.docVersionBadge,"badge badge--secondary")},a.createElement(p.Z,{id:"theme.docs.versionBadge.label",values:{versionLabel:n.label}},"Version: {versionLabel}")):null}function Z(e){let{lastUpdatedAt:t,formattedLastUpdatedAt:n}=e;return a.createElement(p.Z,{id:"theme.lastUpdated.atDate",description:"The words used to describe on which date a page has been last updated",values:{date:a.createElement("b",null,a.createElement("time",{dateTime:new Date(1e3*t).toISOString()},n))}}," on {date}")}function B(e){let{lastUpdatedBy:t}=e;return a.createElement(p.Z,{id:"theme.lastUpdated.byUser",description:"The words used to describe by who the page has been last updated",values:{user:a.createElement("b",null,t)}}," by {user}")}function O(e){let{lastUpdatedAt:t,formattedLastUpdatedAt:n,lastUpdatedBy:o}=e;return a.createElement("span",{className:y.k.common.lastUpdated},a.createElement(p.Z,{id:"theme.lastUpdated.lastUpdatedAtBy",description:"The sentence used to display when a page has been last updated, and by who",values:{atDate:t&&n?a.createElement(Z,{lastUpdatedAt:t,formattedLastUpdatedAt:n}):"",byUser:o?a.createElement(B,{lastUpdatedBy:o}):""}},"Last updated{atDate}{byUser}"),!1)}const j={iconEdit:"iconEdit_Z9Sw"};function H(e){let{className:t,...n}=e;return a.createElement("svg",(0,u.Z)({fill:"currentColor",height:"20",width:"20",viewBox:"0 0 40 40",className:(0,d.Z)(j.iconEdit,t),"aria-hidden":"true"},n),a.createElement("g",null,a.createElement("path",{d:"m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"})))}function A(e){let{editUrl:t}=e;return a.createElement("a",{href:t,target:"_blank",rel:"noreferrer noopener",className:y.k.common.editThisPage},a.createElement(H,null),a.createElement(p.Z,{id:"theme.common.editThisPage",description:"The link label to edit the current page"},"Edit this page"))}const M={tag:"tag_zVej",tagRegular:"tagRegular_sFm0",tagWithCount:"tagWithCount_h2kH"};function S(e){let{permalink:t,label:n,count:o}=e;return a.createElement(f.Z,{href:t,className:(0,d.Z)(M.tag,o?M.tagWithCount:M.tagRegular)},n,o&&a.createElement("span",null,o))}const I={tags:"tags_jXut",tag:"tag_QGVx"};function P(e){let{tags:t}=e;return a.createElement(a.Fragment,null,a.createElement("b",null,a.createElement(p.Z,{id:"theme.tags.tagsListLabel",description:"The label alongside a tag list"},"Tags:")),a.createElement("ul",{className:(0,d.Z)(I.tags,"padding--none","margin-left--sm")},t.map((e=>{let{label:t,permalink:n}=e;return a.createElement("li",{key:n,className:I.tag},a.createElement(S,{label:t,permalink:n}))}))))}const U={lastUpdated:"lastUpdated_vwxv"};function D(e){return a.createElement("div",{className:(0,d.Z)(y.k.docs.docFooterTagsRow,"row margin-bottom--sm")},a.createElement("div",{className:"col"},a.createElement(P,e)))}function z(e){let{editUrl:t,lastUpdatedAt:n,lastUpdatedBy:o,formattedLastUpdatedAt:r}=e;return a.createElement("div",{className:(0,d.Z)(y.k.docs.docFooterEditMetaRow,"row")},a.createElement("div",{className:"col"},t&&a.createElement(A,{editUrl:t})),a.createElement("div",{className:(0,d.Z)("col",U.lastUpdated)},(n||o)&&a.createElement(O,{lastUpdatedAt:n,formattedLastUpdatedAt:r,lastUpdatedBy:o})))}function R(){const{metadata:e}=i(),{editUrl:t,lastUpdatedAt:n,formattedLastUpdatedAt:o,lastUpdatedBy:r,tags:l}=e,c=l.length>0,s=!!(t||n||r);return c||s?a.createElement("footer",{className:(0,d.Z)(y.k.docs.docFooter,"docusaurus-mt-lg")},c&&a.createElement(D,{tags:l}),s&&a.createElement(z,{editUrl:t,lastUpdatedAt:n,lastUpdatedBy:r,formattedLastUpdatedAt:o})):null}var V=n(6043),W=n(6668);function $(e){const t=e.map((e=>({...e,parentIndex:-1,children:[]}))),n=Array(7).fill(-1);t.forEach(((e,t)=>{const a=n.slice(2,e.level);e.parentIndex=Math.max(...a),n[e.level]=t}));const a=[];return t.forEach((e=>{const{parentIndex:n,...o}=e;n>=0?t[n].children.push(o):a.push(o)})),a}function F(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:a}=e;return t.flatMap((e=>{const t=F({toc:e.children,minHeadingLevel:n,maxHeadingLevel:a});return function(e){return e.level>=n&&e.level<=a}(e)?[{...e,children:t}]:t}))}function q(e){const t=e.getBoundingClientRect();return t.top===t.bottom?q(e.parentNode):t}function G(e,t){let{anchorTopOffset:n}=t;const a=e.find((e=>q(e).top>=n));if(a){return function(e){return e.top>0&&e.bottom<window.innerHeight/2}(q(a))?a:e[e.indexOf(a)-1]??null}return e[e.length-1]??null}function Y(){const e=(0,a.useRef)(0),{navbar:{hideOnScroll:t}}=(0,W.L)();return(0,a.useEffect)((()=>{e.current=t?0:document.querySelector(".navbar").clientHeight}),[t]),e}function J(e){const t=(0,a.useRef)(void 0),n=Y();(0,a.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:a,linkActiveClassName:o,minHeadingLevel:r,maxHeadingLevel:l}=e;function c(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(a),c=function(e){let{minHeadingLevel:t,maxHeadingLevel:n}=e;const a=[];for(let o=t;o<=n;o+=1)a.push(`h${o}.anchor`);return Array.from(document.querySelectorAll(a.join()))}({minHeadingLevel:r,maxHeadingLevel:l}),i=G(c,{anchorTopOffset:n.current}),s=e.find((e=>i&&i.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,n){n?(t.current&&t.current!==e&&t.current.classList.remove(o),e.classList.add(o),t.current=e):e.classList.remove(o)}(e,e===s)}))}return document.addEventListener("scroll",c),document.addEventListener("resize",c),c(),()=>{document.removeEventListener("scroll",c),document.removeEventListener("resize",c)}}),[e,n])}function Q(e){let{toc:t,className:n,linkClassName:o,isChild:r}=e;return t.length?a.createElement("ul",{className:r?void 0:n},t.map((e=>a.createElement("li",{key:e.id},a.createElement("a",{href:`#${e.id}`,className:o??void 0,dangerouslySetInnerHTML:{__html:e.value}}),a.createElement(Q,{isChild:!0,toc:e.children,className:n,linkClassName:o}))))):null}const X=a.memo(Q);function K(e){let{toc:t,className:n="table-of-contents table-of-contents__left-border",linkClassName:o="table-of-contents__link",linkActiveClassName:r,minHeadingLevel:l,maxHeadingLevel:c,...i}=e;const s=(0,W.L)(),d=l??s.tableOfContents.minHeadingLevel,m=c??s.tableOfContents.maxHeadingLevel,p=function(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:o}=e;return(0,a.useMemo)((()=>F({toc:$(t),minHeadingLevel:n,maxHeadingLevel:o})),[t,n,o])}({toc:t,minHeadingLevel:d,maxHeadingLevel:m});return J((0,a.useMemo)((()=>{if(o&&r)return{linkClassName:o,linkActiveClassName:r,minHeadingLevel:d,maxHeadingLevel:m}}),[o,r,d,m])),a.createElement(X,(0,u.Z)({toc:p,className:n,linkClassName:o},i))}const ee={tocCollapsibleButton:"tocCollapsibleButton_TO0P",tocCollapsibleButtonExpanded:"tocCollapsibleButtonExpanded_MG3E"};function te(e){let{collapsed:t,...n}=e;return a.createElement("button",(0,u.Z)({type:"button"},n,{className:(0,d.Z)("clean-btn",ee.tocCollapsibleButton,!t&&ee.tocCollapsibleButtonExpanded,n.className)}),a.createElement(p.Z,{id:"theme.TOCCollapsible.toggleButtonLabel",description:"The label used by the button on the collapsible TOC component"},"On this page"))}const ne={tocCollapsible:"tocCollapsible_ETCw",tocCollapsibleContent:"tocCollapsibleContent_vkbj",tocCollapsibleExpanded:"tocCollapsibleExpanded_sAul"};function ae(e){let{toc:t,className:n,minHeadingLevel:o,maxHeadingLevel:r}=e;const{collapsed:l,toggleCollapsed:c}=(0,V.u)({initialState:!0});return a.createElement("div",{className:(0,d.Z)(ne.tocCollapsible,!l&&ne.tocCollapsibleExpanded,n)},a.createElement(te,{collapsed:l,onClick:c}),a.createElement(V.z,{lazy:!0,className:ne.tocCollapsibleContent,collapsed:l},a.createElement(K,{toc:t,minHeadingLevel:o,maxHeadingLevel:r})))}const oe={tocMobile:"tocMobile_ITEo"};function re(){const{toc:e,frontMatter:t}=i();return a.createElement(ae,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:(0,d.Z)(y.k.docs.docTocMobile,oe.tocMobile)})}const le={tableOfContents:"tableOfContents_bqdL",docItemContainer:"docItemContainer_F8PC"},ce="table-of-contents__link toc-highlight",ie="table-of-contents__link--active";function se(e){let{className:t,...n}=e;return a.createElement("div",{className:(0,d.Z)(le.tableOfContents,"thin-scrollbar",t)},a.createElement(K,(0,u.Z)({},n,{linkClassName:ce,linkActiveClassName:ie})))}function de(){const{toc:e,frontMatter:t}=i();return a.createElement(se,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:y.k.docs.docTocDesktop})}const me={anchorWithStickyNavbar:"anchorWithStickyNavbar_LWe7",anchorWithHideOnScrollNavbar:"anchorWithHideOnScrollNavbar_WYt5"};function ue(e){let{as:t,id:n,...o}=e;const{navbar:{hideOnScroll:r}}=(0,W.L)();if("h1"===t||!n)return a.createElement(t,(0,u.Z)({},o,{id:void 0}));const l=(0,p.I)({id:"theme.common.headingLinkTitle",message:"Direct link to {heading}",description:"Title for link to heading"},{heading:"string"==typeof o.children?o.children:n});return a.createElement(t,(0,u.Z)({},o,{className:(0,d.Z)("anchor",r?me.anchorWithHideOnScrollNavbar:me.anchorWithStickyNavbar,o.className),id:n}),o.children,a.createElement(f.Z,{className:"hash-link",to:`#${n}`,"aria-label":l,title:l},"\u200b"))}var pe=n(3905),fe=n(5742);var he=n(7951),ge=n.n(he);var be=n(2389);const ve={details:"details_lb9f",isBrowser:"isBrowser_bmU9",collapsibleContent:"collapsibleContent_i85q"};function Ee(e){return!!e&&("SUMMARY"===e.tagName||Ee(e.parentElement))}function ye(e,t){return!!e&&(e===t||ye(e.parentElement,t))}function ke(e){let{summary:t,children:n,...o}=e;const r=(0,be.Z)(),l=(0,a.useRef)(null),{collapsed:c,setCollapsed:i}=(0,V.u)({initialState:!o.open}),[s,m]=(0,a.useState)(o.open),p=a.isValidElement(t)?t:a.createElement("summary",null,t??"Details");return a.createElement("details",(0,u.Z)({},o,{ref:l,open:s,"data-collapsed":c,className:(0,d.Z)(ve.details,r&&ve.isBrowser,o.className),onMouseDown:e=>{Ee(e.target)&&e.detail>1&&e.preventDefault()},onClick:e=>{e.stopPropagation();const t=e.target;Ee(t)&&ye(t,l.current)&&(e.preventDefault(),c?(i(!1),m(!0)):i(!0))}}),p,a.createElement(V.z,{lazy:!1,collapsed:c,disableSSRStyle:!0,onCollapseTransitionEnd:e=>{i(e),m(!e)}},a.createElement("div",{className:ve.collapsibleContent},n)))}const Ne={details:"details_b_Ee"},Ce="alert alert--info";function Le(e){let{...t}=e;return a.createElement(ke,(0,u.Z)({},t,{className:(0,d.Z)(Ce,Ne.details,t.className)}))}function _e(e){return a.createElement(ue,e)}const we={containsTaskList:"containsTaskList_mC6p"};const Te={img:"img_ev3q"};const xe={admonition:"admonition_LlT9",admonitionHeading:"admonitionHeading_tbUL",admonitionIcon:"admonitionIcon_kALy",admonitionContent:"admonitionContent_S0QG"};const Ze={note:{infimaClassName:"secondary",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 14 16"},a.createElement("path",{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))},label:a.createElement(p.Z,{id:"theme.admonition.note",description:"The default label used for the Note admonition (:::note)"},"note")},tip:{infimaClassName:"success",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 12 16"},a.createElement("path",{fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"}))},label:a.createElement(p.Z,{id:"theme.admonition.tip",description:"The default label used for the Tip admonition (:::tip)"},"tip")},danger:{infimaClassName:"danger",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 12 16"},a.createElement("path",{fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"}))},label:a.createElement(p.Z,{id:"theme.admonition.danger",description:"The default label used for the Danger admonition (:::danger)"},"danger")},info:{infimaClassName:"info",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 14 16"},a.createElement("path",{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))},label:a.createElement(p.Z,{id:"theme.admonition.info",description:"The default label used for the Info admonition (:::info)"},"info")},caution:{infimaClassName:"warning",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 16 16"},a.createElement("path",{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"}))},label:a.createElement(p.Z,{id:"theme.admonition.caution",description:"The default label used for the Caution admonition (:::caution)"},"caution")}},Be={secondary:"note",important:"info",success:"tip",warning:"danger"};function Oe(e){const{mdxAdmonitionTitle:t,rest:n}=function(e){const t=a.Children.toArray(e),n=t.find((e=>a.isValidElement(e)&&"mdxAdmonitionTitle"===e.props?.mdxType)),o=a.createElement(a.Fragment,null,t.filter((e=>e!==n)));return{mdxAdmonitionTitle:n,rest:o}}(e.children);return{...e,title:e.title??t,children:n}}const je={head:function(e){const t=a.Children.map(e.children,(e=>a.isValidElement(e)?function(e){if(e.props?.mdxType&&e.props.originalType){const{mdxType:t,originalType:n,...o}=e.props;return a.createElement(e.props.originalType,o)}return e}(e):e));return a.createElement(fe.Z,e,t)},code:function(e){const t=["a","abbr","b","br","button","cite","code","del","dfn","em","i","img","input","ins","kbd","label","object","output","q","ruby","s","small","span","strong","sub","sup","time","u","var","wbr"];return a.Children.toArray(e.children).every((e=>"string"==typeof e&&!e.includes("\n")||(0,a.isValidElement)(e)&&t.includes(e.props?.mdxType)))?a.createElement("code",e):a.createElement(ge(),e)},a:function(e){return a.createElement(f.Z,e)},pre:function(e){return a.createElement(ge(),(0,a.isValidElement)(e.children)&&"code"===e.children.props?.originalType?e.children.props:{...e})},details:function(e){const t=a.Children.toArray(e.children),n=t.find((e=>a.isValidElement(e)&&"summary"===e.props?.mdxType)),o=a.createElement(a.Fragment,null,t.filter((e=>e!==n)));return a.createElement(Le,(0,u.Z)({},e,{summary:n}),o)},ul:function(e){return a.createElement("ul",(0,u.Z)({},e,{className:(t=e.className,(0,d.Z)(t,t?.includes("contains-task-list")&&we.containsTaskList))}));var t},img:function(e){return a.createElement("img",(0,u.Z)({loading:"lazy"},e,{className:(t=e.className,(0,d.Z)(t,Te.img))}));var t},h1:e=>a.createElement(_e,(0,u.Z)({as:"h1"},e)),h2:e=>a.createElement(_e,(0,u.Z)({as:"h2"},e)),h3:e=>a.createElement(_e,(0,u.Z)({as:"h3"},e)),h4:e=>a.createElement(_e,(0,u.Z)({as:"h4"},e)),h5:e=>a.createElement(_e,(0,u.Z)({as:"h5"},e)),h6:e=>a.createElement(_e,(0,u.Z)({as:"h6"},e)),admonition:function(e){const{children:t,type:n,title:o,icon:r}=Oe(e),l=function(e){const t=Be[e]??e,n=Ze[t];return n||(console.warn(`No admonition config found for admonition type "${t}". Using Info as fallback.`),Ze.info)}(n),c=o??l.label,{iconComponent:i}=l,s=r??a.createElement(i,null);return a.createElement("div",{className:(0,d.Z)(y.k.common.admonition,y.k.common.admonitionType(e.type),"alert",`alert--${l.infimaClassName}`,xe.admonition)},a.createElement("div",{className:xe.admonitionHeading},a.createElement("span",{className:xe.admonitionIcon},s),c),a.createElement("div",{className:xe.admonitionContent},t))},mermaid:n(1875).Z};function He(e){let{children:t}=e;return a.createElement(pe.Zo,{components:je},t)}function Ae(e){let{children:t}=e;const n=function(){const{metadata:e,frontMatter:t,contentTitle:n}=i();return t.hide_title||void 0!==n?null:e.title}();return a.createElement("div",{className:(0,d.Z)(y.k.docs.docMarkdown,"markdown")},n&&a.createElement("header",null,a.createElement(ue,{as:"h1"},n)),a.createElement(He,null,t))}var Me=n(2802),Se=n(8596),Ie=n(4996);function Pe(e){return a.createElement("svg",(0,u.Z)({viewBox:"0 0 24 24"},e),a.createElement("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"}))}const Ue={breadcrumbHomeIcon:"breadcrumbHomeIcon_YNFT"};function De(){const e=(0,Ie.Z)("/");return a.createElement("li",{className:"breadcrumbs__item"},a.createElement(f.Z,{"aria-label":(0,p.I)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:"breadcrumbs__link",href:e},a.createElement(Pe,{className:Ue.breadcrumbHomeIcon})))}const ze={breadcrumbsContainer:"breadcrumbsContainer_Z_bl"};function Re(e){let{children:t,href:n,isLast:o}=e;const r="breadcrumbs__link";return o?a.createElement("span",{className:r,itemProp:"name"},t):n?a.createElement(f.Z,{className:r,href:n,itemProp:"item"},a.createElement("span",{itemProp:"name"},t)):a.createElement("span",{className:r},t)}function Ve(e){let{children:t,active:n,index:o,addMicrodata:r}=e;return a.createElement("li",(0,u.Z)({},r&&{itemScope:!0,itemProp:"itemListElement",itemType:"https://schema.org/ListItem"},{className:(0,d.Z)("breadcrumbs__item",{"breadcrumbs__item--active":n})}),t,a.createElement("meta",{itemProp:"position",content:String(o+1)}))}function We(){const e=(0,Me.s1)(),t=(0,Se.Ns)();return e?a.createElement("nav",{className:(0,d.Z)(y.k.docs.docBreadcrumbs,ze.breadcrumbsContainer),"aria-label":(0,p.I)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"})},a.createElement("ul",{className:"breadcrumbs",itemScope:!0,itemType:"https://schema.org/BreadcrumbList"},t&&a.createElement(De,null),e.map(((t,n)=>{const o=n===e.length-1;return a.createElement(Ve,{key:n,active:o,index:n,addMicrodata:!!t.href},a.createElement(Re,{href:t.href,isLast:o},t.label))})))):null}const $e={docItemContainer:"docItemContainer_Djhp",docItemCol:"docItemCol_VOVn"};function Fe(e){let{children:t}=e;const n=function(){const{frontMatter:e,toc:t}=i(),n=(0,m.i)(),o=e.hide_table_of_contents,r=!o&&t.length>0;return{hidden:o,mobile:r?a.createElement(re,null):void 0,desktop:!r||"desktop"!==n&&"ssr"!==n?void 0:a.createElement(de,null)}}();return a.createElement("div",{className:"row"},a.createElement("div",{className:(0,d.Z)("col",!n.hidden&&$e.docItemCol)},a.createElement(T,null),a.createElement("div",{className:$e.docItemContainer},a.createElement("article",null,a.createElement(We,null),a.createElement(x,null),n.mobile,a.createElement(Ae,null,t),a.createElement(R,null)),a.createElement(b,null))),n.desktop&&a.createElement("div",{className:"col col--3"},n.desktop))}function qe(e){const t=`docs-doc-id-${e.content.metadata.unversionedId}`,n=e.content;return a.createElement(c,{content:e.content},a.createElement(o.FG,{className:t},a.createElement(s,null),a.createElement(Fe,null,a.createElement(n,null))))}},4477:(e,t,n)=>{"use strict";n.d(t,{E:()=>c,q:()=>l});var a=n(7294),o=n(902);const r=a.createContext(null);function l(e){let{children:t,version:n}=e;return a.createElement(r.Provider,{value:n},t)}function c(){const e=(0,a.useContext)(r);if(null===e)throw new o.i6("DocsVersionProvider");return e}},7594:(e,t)=>{function n(e){let t,n=[];for(let a of e.split(",").map((e=>e.trim())))if(/^-?\d+$/.test(a))n.push(parseInt(a,10));else if(t=a.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[e,a,o,r]=t;if(a&&r){a=parseInt(a),r=parseInt(r);const e=a<r?1:-1;"-"!==o&&".."!==o&&"\u2025"!==o||(r+=e);for(let t=a;t!==r;t+=e)n.push(t)}}return n}t.default=n,e.exports=n}}]); \ No newline at end of file diff --git a/legacy/assets/js/1833c00d.1278baf4.js b/legacy/assets/js/1833c00d.1278baf4.js new file mode 100644 index 0000000000..f3b1ae4504 --- /dev/null +++ b/legacy/assets/js/1833c00d.1278baf4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[542],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>m});var n=a(7294);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?r(Object(a),!0).forEach((function(t){i(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):r(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function l(e,t){if(null==e)return{};var a,n,i=function(e,t){if(null==e)return{};var a,n,i={},r=Object.keys(e);for(n=0;n<r.length;n++)a=r[n],t.indexOf(a)>=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n<r.length;n++)a=r[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var s=n.createContext({}),h=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},d=function(e){var t=h(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=h(a),u=i,m=c["".concat(s,".").concat(u)]||c[u]||p[u]||r;return a?n.createElement(m,o(o({ref:t},d),{},{components:a})):n.createElement(m,o({ref:t},d))}));function m(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=a.length,o=new Array(r);o[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:i,o[1]=l;for(var h=2;h<r;h++)o[h]=a[h];return n.createElement.apply(null,o)}return n.createElement.apply(null,a)}u.displayName="MDXCreateElement"},4682:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>p,frontMatter:()=>r,metadata:()=>l,toc:()=>h});var n=a(7462),i=(a(7294),a(3905));const r={sidebar_position:3,title:"Jail Throttling"},o="ADR 002: Jail Throttling",l={unversionedId:"adrs/adr-002-throttle",id:"version-v3.3.0/adrs/adr-002-throttle",title:"Jail Throttling",description:"Changelog",source:"@site/versioned_docs/version-v3.3.0/adrs/adr-002-throttle.md",sourceDirName:"adrs",slug:"/adrs/adr-002-throttle",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-002-throttle",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Jail Throttling"},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-001-key-assignment"},next:{title:"Equivocation governance proposal",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-003-equivocation-gov-proposal"}},s={},h=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Required State",id:"required-state",level:3},{value:"Params",id:"params",level:3},{value:"Protocol Overview",id:"protocol-overview",level:3},{value:"OnRecvSlashPacket",id:"onrecvslashpacket",level:4},{value:"OnRecvVSCMaturedPacket",id:"onrecvvscmaturedpacket",level:4},{value:"Endblocker",id:"endblocker",level:4},{value:"Slash Meter Replenishment",id:"slash-meter-replenishment",level:5},{value:"Handle Leading VSCMaturedPackets",id:"handle-leading-vscmaturedpackets",level:5},{value:"Handle Throttle Queues",id:"handle-throttle-queues",level:5},{value:"System Properties",id:"system-properties",level:3},{value:"Main Throttling Property",id:"main-throttling-property",level:3},{value:"How Unjailing Affects the Main Throttling Property",id:"how-unjailing-affects-the-main-throttling-property",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],d={toc:h},c="wrapper";function p(e){let{components:t,...a}=e;return(0,i.kt)(c,(0,n.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"adr-002-jail-throttling"},"ADR 002: Jail Throttling"),(0,i.kt)("h2",{id:"changelog"},"Changelog"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"2023-01-26: Initial Draft"),(0,i.kt)("li",{parentName:"ul"},"2023-02-07: Property refined, ADR ready to review/merge"),(0,i.kt)("li",{parentName:"ul"},"2023-11-22: Refactor for better understanding")),(0,i.kt)("h2",{id:"status"},"Status"),(0,i.kt)("p",null,"Accepted"),(0,i.kt)("h2",{id:"context"},"Context"),(0,i.kt)("p",null,"The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols.\nIn practice, this assumption may not hold.\nA malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider."),(0,i.kt)("p",null,"Before the throttling feature was implemented, the following attack was possible.\nAttacker(s) would create provider validators just below the provider's active set.\nUsing a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once.\nControl of the provider would then pass over to the attackers' validators.\nThis enables the attacker(s) to halt the provider.\nOr even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC."),(0,i.kt)("h2",{id:"decision"},"Decision"),(0,i.kt)("p",null,"The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack,\ni.e., this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time."),(0,i.kt)("h3",{id:"required-state"},"Required State"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Slash meter:")," There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time.\nThis meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Global entry queue:"),' There exists a single queue which stores "global slash entries".\nThese entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering.\nThis queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.'),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Per-chain data queue:"),' For each established consumer, there exists a queue which stores "throttled packet data",\ni.e.,pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering.\nOrder is enforced by IBC sequence number.\nThese "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.'),(0,i.kt)("p",null,(0,i.kt)("em",{parentName:"p"},"Note:")," The reason for a multiple-queue design is the ",(0,i.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order")," property (see ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"spec"),").\nThere are other ways to ensure such a property (like a queue of linked lists, etc.), but the proposed approach seemed to be the most understandable and easiest to implement with a KV store."),(0,i.kt)("h3",{id:"params"},"Params"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishPeriod")," -- the period after which the slash meter is replenished. "),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction")," -- the portion (in range ","[0, 1]",") of total voting power that is replenished to the slash meter when a replenishment occurs. This param also serves as a maximum fraction of total voting power that the slash meter can hold."),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"MaxThrottledPackets")," -- the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value.\nThis param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness."),(0,i.kt)("h3",{id:"protocol-overview"},"Protocol Overview"),(0,i.kt)("h4",{id:"onrecvslashpacket"},"OnRecvSlashPacket"),(0,i.kt)("p",null,"Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"A global slash entry is queued."),(0,i.kt)("li",{parentName:"ol"},"The data of such a packet is added to the per-chain queue.")),(0,i.kt)("h4",{id:"onrecvvscmaturedpacket"},"OnRecvVSCMaturedPacket"),(0,i.kt)("p",null,"Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue."),(0,i.kt)("h4",{id:"endblocker"},"Endblocker"),(0,i.kt)("p",null,"In the ",(0,i.kt)("inlineCode",{parentName:"p"},"EndBlock")," of the provider CCV module, there are three actions performed:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"replenish the slash meter;"),(0,i.kt)("li",{parentName:"ul"},"handle the leading ",(0,i.kt)("inlineCode",{parentName:"li"},"VSCMaturedPackets"),";"),(0,i.kt)("li",{parentName:"ul"},"and handle the throttle queues.")),(0,i.kt)("h5",{id:"slash-meter-replenishment"},"Slash Meter Replenishment"),(0,i.kt)("p",null,"Once the slash meter becomes not full, it'll be replenished after ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishPeriod")," by incrementing the meter with its allowance for the replenishment block, where ",(0,i.kt)("inlineCode",{parentName:"p"},"allowance")," = ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction")," * ",(0,i.kt)("inlineCode",{parentName:"p"},"currentTotalVotingPower"),".\nThe slash meter will never exceed its current allowance (function of the total voting power for the block) in value. "),(0,i.kt)("p",null,"Note a few things:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power.\nIn such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods."),(0,i.kt)("li",{parentName:"ol"},"Total voting power of a chain changes over time, especially as validators are jailed.\nAs validators are jailed, total voting power decreases, and so does the jailing allowance.\nSee below for more detailed throttling property discussion."),(0,i.kt)("li",{parentName:"ol"},"The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1.\nIf the ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," is set too low, integer rounding will put this minimum value into effect.\nThat is, if ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," * ",(0,i.kt)("inlineCode",{parentName:"li"},"currentTotalVotingPower")," < 1, then the effective allowance would be 1.\nThis min value of allowance ensures that there's some packets handled over time, even if that is a very long time.\nIt's a crude solution to an edge case caused by too small of a replenishment fraction.")),(0,i.kt)("p",null,"The behavior described above is achieved by executing ",(0,i.kt)("inlineCode",{parentName:"p"},"CheckForSlashMeterReplenishment()")," every ",(0,i.kt)("inlineCode",{parentName:"p"},"EndBlock"),", BEFORE ",(0,i.kt)("inlineCode",{parentName:"p"},"HandleThrottleQueues()")," is executed."),(0,i.kt)("h5",{id:"handle-leading-vscmaturedpackets"},"Handle Leading VSCMaturedPackets"),(0,i.kt)("p",null,"In every block, it is possible that ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPacket"),' data was queued before any slash packet data.\nSince this "leading" VSCMatured packet data does not have to be throttled (see ',(0,i.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order"),"), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes."),(0,i.kt)("h5",{id:"handle-throttle-queues"},"Handle Throttle Queues"),(0,i.kt)("p",null,"In every ",(0,i.kt)("inlineCode",{parentName:"p"},"EndBlock"),", the following logic is executed to handle data from the throttle queues."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"meter := getSlashMeter()\n\n// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist \nwhile meter.IsPositiveOrZero() && entriesExist() {\n // Get next entry in queue\n entry := getNextGlobalSlashEntry()\n // Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet\n valPower := entry.getValPower()\n meter = meter - valPower\n // Using the per-chain queue, handle the single slash packet using its queued data,\n // then handle all trailing VSCMatured packets for this consumer\n handleSlashPacketAndTrailingVSCMaturedPackets(entry)\n // Delete entry in global queue, delete handled data\n entry.Delete()\n deleteThrottledSlashPacketData()\n deleteTrailingVSCMaturedPacketData()\n}\n")),(0,i.kt)("h3",{id:"system-properties"},"System Properties"),(0,i.kt)("p",null,"All CCV system properties should be maintained by implementing this feature, see ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"CCV spec - Consumer Initiated Slashing"),"."),(0,i.kt)("p",null,"One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than ",(0,i.kt)("inlineCode",{parentName:"p"},"MaxThrottledPackets"),", then the provider binary will panic, and the provider chain will halt.\nTherefore this param should be set carefully. See ",(0,i.kt)("inlineCode",{parentName:"p"},"SetThrottledPacketDataSize"),".\nThis behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators."),(0,i.kt)("h3",{id:"main-throttling-property"},"Main Throttling Property"),(0,i.kt)("p",null,"Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions."),(0,i.kt)("p",null,"First, we introduce the following definitions:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},'A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.'),(0,i.kt)("li",{parentName:"ul"},'The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.'),(0,i.kt)("li",{parentName:"ul"},"There is a list of honest validators such that if they are jailed, ",(0,i.kt)("inlineCode",{parentName:"li"},"X"),"% of the initial validator set will be jailed.")),(0,i.kt)("p",null,"For the Throttling Property to hold, the following assumptions must be true:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack."),(0,i.kt)("li",{parentName:"ol"},"No validator has more than ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," of total voting power on the provider."),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," is large enough that ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," * ",(0,i.kt)("inlineCode",{parentName:"li"},"currentTotalVotingPower")," > 1,\ni.e., the replenish fraction is set high enough that we can ignore the effects of rounding."),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishPeriod")," is sufficiently longer than the time it takes to produce a block.")),(0,i.kt)("p",null,(0,i.kt)("em",{parentName:"p"},"Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined.")),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Throttling Property"),": The time it takes to jail/tombstone ",(0,i.kt)("inlineCode",{parentName:"p"},"X"),"% of the initial validator set will be greater than or equal to\n$\\mathit{SlashMeterReplenishPeriod} \\cdot \\frac{X}{\\mathit{SlashMeterReplenishFraction}} - 2 \\cdot \\mathit{SlashMeterReplenishPeriod}$."),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("strong",{parentName:"p"},"Intuition")),(0,i.kt)("p",{parentName:"blockquote"},"Let's use the following notation:"),(0,i.kt)("ul",{parentName:"blockquote"},(0,i.kt)("li",{parentName:"ul"},"$C$: Number of replenishment cycles"),(0,i.kt)("li",{parentName:"ul"},"$P$: $\\mathit{SlashMeterReplenishPeriod}$"),(0,i.kt)("li",{parentName:"ul"},"$F$: $\\mathit{SlashMeterReplenishFraction}$"),(0,i.kt)("li",{parentName:"ul"},"$V_{\\mathit{max}}$: Max power of a validator as a fraction of total voting power")),(0,i.kt)("p",{parentName:"blockquote"},"In $C$ number of replenishment cycles, the fraction of total voting power that can be removed, $a$, is $a \\leq F \\cdot C + V",(0,i.kt)("em",{parentName:"p"},"{\\mathit{max}}$ (where $V"),"{\\mathit{max}}$ is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value)."),(0,i.kt)("p",{parentName:"blockquote"},"So, we need at least $C \\geq \\frac{a - V_{\\mathit{max}}}{F}$ cycles to remove $a$ fraction of the total voting power."),(0,i.kt)("p",{parentName:"blockquote"},"Since we defined the start of the attack to be the moment when the first slash request arrives, then $F$ fraction of the initial validator set can be jailed immediately. For the remaining $X - F$ fraction of the initial validator set to be jailed, it takes at least $C \\geq \\frac{(X - F) - V",(0,i.kt)("em",{parentName:"p"},"{\\mathit{max}}}{F}$ cycles. Using the assumption that $V"),"{\\mathit{max}} \\leq F$ (assumption 2), we get $C \\geq \\frac{X - 2F}{F}$ cycles."),(0,i.kt)("p",{parentName:"blockquote"},"In order to execute $C$ cycles, we need $C \\cdot P$ time."),(0,i.kt)("p",{parentName:"blockquote"},"Thus, jailing the remaining $X - F$ fraction of the initial validator set corresponds to $\\frac{P \\cdot (X - 2F)}{F}$ time."),(0,i.kt)("p",{parentName:"blockquote"},"In other words, the attack must take at least $\\frac{P \\cdot X}{F} - 2P$ time (in the units of replenish period $P$).")),(0,i.kt)("p",null,"This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests.\nFor example, if ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction")," is set to ",(0,i.kt)("inlineCode",{parentName:"p"},"0.06"),", then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub.\nNote that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power."),(0,i.kt)("p",null,"Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings."),(0,i.kt)("h3",{id:"how-unjailing-affects-the-main-throttling-property"},"How Unjailing Affects the Main Throttling Property"),(0,i.kt)("p",null,"Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained."),(0,i.kt)("p",null,"If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider."),(0,i.kt)("p",null,"In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack."),(0,i.kt)("h2",{id:"consequences"},"Consequences"),(0,i.kt)("h3",{id:"positive"},"Positive"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"The described attack is slowed down in seemingly all cases."),(0,i.kt)("li",{parentName:"ul"},"If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded.")),(0,i.kt)("h3",{id:"negative"},"Negative"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below.\nHowever, this is sacrificing liveness in a edge case scenario for the sake of security.\nAs an improvement, ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/713"},"using retries")," would fully prevent this attack vector.")),(0,i.kt)("h3",{id:"neutral"},"Neutral"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Additional state is introduced to the provider chain."),(0,i.kt)("li",{parentName:"ul"},"VSCMatured and slash packet data is not always handled in the same block that it is received.")),(0,i.kt)("h2",{id:"references"},"References"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/404"},"Original issue inspiring throttling feature")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/594"},"Issue on DOS vector")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/685"},"Consideration of another attack vector"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/1a009efd.75aaa0fa.js b/legacy/assets/js/1a009efd.75aaa0fa.js new file mode 100644 index 0000000000..dedfa05370 --- /dev/null +++ b/legacy/assets/js/1a009efd.75aaa0fa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[324],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>y});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?c(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):c(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function a(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},c=Object.keys(e);for(r=0;r<c.length;r++)n=c[r],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(r=0;r<c.length;r++)n=c[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var p=r.createContext({}),s=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},l=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,c=e.originalType,p=e.parentName,l=a(e,["components","mdxType","originalType","parentName"]),u=s(n),d=i,y=u["".concat(p,".").concat(d)]||u[d]||f[d]||c;return n?r.createElement(y,o(o({ref:t},l),{},{components:n})):r.createElement(y,o({ref:t},l))}));function y(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var c=n.length,o=new Array(c);o[0]=d;var a={};for(var p in t)hasOwnProperty.call(t,p)&&(a[p]=t[p]);a.originalType=e,a[u]="string"==typeof e?e:i,o[1]=a;for(var s=2;s<c;s++)o[s]=n[s];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},3610:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>f,frontMatter:()=>c,metadata:()=>a,toc:()=>s});var r=n(7462),i=(n(7294),n(3905));const c={sidebar_position:4},o="Technical Specification",a={unversionedId:"introduction/technical-specification",id:"version-v3.1.0/introduction/technical-specification",title:"Technical Specification",description:"For a technical deep dive into the replicated security protocol, see the specification.",source:"@site/versioned_docs/version-v3.1.0/introduction/technical-specification.md",sourceDirName:"introduction",slug:"/introduction/technical-specification",permalink:"/interchain-security/legacy/v3.1.0/introduction/technical-specification",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Parameters",permalink:"/interchain-security/legacy/v3.1.0/introduction/params"},next:{title:"Key Assignment",permalink:"/interchain-security/legacy/v3.1.0/features/key-assignment"}},p={},s=[],l={toc:s},u="wrapper";function f(e){let{components:t,...n}=e;return(0,i.kt)(u,(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"technical-specification"},"Technical Specification"),(0,i.kt)("p",null,"For a technical deep dive into the replicated security protocol, see the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/README.md"},"specification"),"."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/1a276578.896dcb3b.js b/legacy/assets/js/1a276578.896dcb3b.js new file mode 100644 index 0000000000..c6c3a2c92d --- /dev/null +++ b/legacy/assets/js/1a276578.896dcb3b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2087],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>m});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),h=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=h(e.components);return r.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),d=h(n),p=a,m=d["".concat(c,".").concat(p)]||d[p]||u[p]||o;return n?r.createElement(m,i(i({ref:t},l),{},{components:n})):r.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=p;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:a,i[1]=s;for(var h=2;h<o;h++)i[h]=n[h];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}p.displayName="MDXCreateElement"},2806:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>h});var r=n(7462),a=(n(7294),n(3905));const o={sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},i=void 0,s={unversionedId:"frequently-asked-questions",id:"version-v2.0.0/frequently-asked-questions",title:"Frequently Asked Questions",description:"What is the meaning of Validator Set Replication?",source:"@site/versioned_docs/version-v2.0.0/frequently-asked-questions.md",sourceDirName:".",slug:"/faq",permalink:"/interchain-security/legacy/v2.0.0/faq",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:5,frontMatter:{sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},sidebar:"tutorialSidebar",previous:{title:"Withdrawing consumer chain validator rewards",permalink:"/interchain-security/legacy/v2.0.0/validators/withdraw_rewards"},next:{title:"ADRs",permalink:"/interchain-security/legacy/v2.0.0/adrs/intro"}},c={},h=[{value:"What is the meaning of Validator Set Replication?",id:"what-is-the-meaning-of-validator-set-replication",level:2},{value:"What even is a consumer chain?",id:"what-even-is-a-consumer-chain",level:2},{value:"What happens to consumer if provider is down?",id:"what-happens-to-consumer-if-provider-is-down",level:2},{value:"What happens to provider if consumer is down?",id:"what-happens-to-provider-if-consumer-is-down",level:2},{value:"Can I run the provider and consumer chains on the same machine?",id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine",level:2},{value:"Can the consumer chain have its own token?",id:"can-the-consumer-chain-have-its-own-token",level:2},{value:"How are Tx fees paid on consumer?",id:"how-are-tx-fees-paid-on-consumer",level:2},{value:"Are there any restrictions the consumer chains need to abide by?",id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by",level:2},{value:"What's in it for the validators and stakers?",id:"whats-in-it-for-the-validators-and-stakers",level:2},{value:"Can the consumer chain have its own governance?",id:"can-the-consumer-chain-have-its-own-governance",level:2},{value:"Can validators opt-out of replicated security?",id:"can-validators-opt-out-of-replicated-security",level:2},{value:"How does Equivocation Governance Slashing work?",id:"how-does-equivocation-governance-slashing-work",level:2},{value:"Can Consumer Chains perform Software Upgrades?",id:"can-consumer-chains-perform-software-upgrades",level:2},{value:"How can I connect to the testnets?",id:"how-can-i-connect-to-the-testnets",level:2},{value:"How do I start using ICS?",id:"how-do-i-start-using-ics",level:2},{value:"Which relayers are supported?",id:"which-relayers-are-supported",level:2},{value:"How does key delegation work in ICS?",id:"how-does-key-delegation-work-in-ics",level:2}],l={toc:h},d="wrapper";function u(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"what-is-the-meaning-of-validator-set-replication"},"What is the meaning of Validator Set Replication?"),(0,a.kt)("p",null,"VSR simply means that the same validator set is used to secure both the provider and consumer chains. VSR is ensured through ICS protocol which keeps consumers up to date with the validator set of the provider."),(0,a.kt)("h2",{id:"what-even-is-a-consumer-chain"},"What even is a consumer chain?"),(0,a.kt)("p",null,"Consumer chain is blockchain operated by the same validator operators as the provider chain. The ICS protocol ensures the validator set replication properties (informs consumer chain about the current state of the validator set on the provider)"),(0,a.kt)("p",null,"Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements."),(0,a.kt)("h2",{id:"what-happens-to-consumer-if-provider-is-down"},"What happens to consumer if provider is down?"),(0,a.kt)("p",null,"In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set."),(0,a.kt)("p",null,"The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness."),(0,a.kt)("p",null,"However, if the ",(0,a.kt)("inlineCode",{parentName:"p"},"trusting_period")," (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain.\nThis means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about."),(0,a.kt)("p",null,'Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point.\nAt the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.'),(0,a.kt)("h2",{id:"what-happens-to-provider-if-consumer-is-down"},"What happens to provider if consumer is down?"),(0,a.kt)("p",null,"Consumer chains do not impact the provider chain.\nThe ICS protocol is concerned only with validator set replication and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events)."),(0,a.kt)("h2",{id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine"},"Can I run the provider and consumer chains on the same machine?"),(0,a.kt)("p",null,"Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation."),(0,a.kt)("h2",{id:"can-the-consumer-chain-have-its-own-token"},"Can the consumer chain have its own token?"),(0,a.kt)("p",null,"As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees."),(0,a.kt)("h2",{id:"how-are-tx-fees-paid-on-consumer"},"How are Tx fees paid on consumer?"),(0,a.kt)("p",null,"The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations."),(0,a.kt)("h2",{id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by"},"Are there any restrictions the consumer chains need to abide by?"),(0,a.kt)("p",null,"No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way.\nThe only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain."),(0,a.kt)("h2",{id:"whats-in-it-for-the-validators-and-stakers"},"What's in it for the validators and stakers?"),(0,a.kt)("p",null,"The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by ",(0,a.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction"),". The rewards are distributed (sent to the provider) every ",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission"),"."),(0,a.kt)("admonition",{type:"note"},(0,a.kt)("p",{parentName:"admonition"}," ",(0,a.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission")," are parameters defined in the ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," used to create the consumer chain. These parameters can be changed via consumer chain governance.")),(0,a.kt)("h2",{id:"can-the-consumer-chain-have-its-own-governance"},"Can the consumer chain have its own governance?"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Yes.")),(0,a.kt)("p",null,'In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.'),(0,a.kt)("p",null,"Validators can also be representatives but representatives are not required to run validator nodes."),(0,a.kt)("p",null,"This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance."),(0,a.kt)("h2",{id:"can-validators-opt-out-of-replicated-security"},"Can validators opt-out of replicated security?"),(0,a.kt)("p",null,"At present, the validators cannot opt-out of validating consumer chains."),(0,a.kt)("p",null,"There are multiple opt-out mechanisms under active research."),(0,a.kt)("h2",{id:"how-does-equivocation-governance-slashing-work"},"How does Equivocation Governance Slashing work?"),(0,a.kt)("p",null,"To avoid potential attacks directed at provider chain validators, a new mechanism was introduced:"),(0,a.kt)("p",null,"When a validator double-signs on the consumer chain, a special type of slash packet is relayed to the provider chain. The provider will store information about the double signing validator and allow a governance proposal to be submitted.\nIf the double-signing proposal passes, the offending validator will be slashed on the provider chain and tombstoned. Tombstoning will permanently exclude the validator from the active set of the provider."),(0,a.kt)("admonition",{type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"An equivocation proposal cannot be submitted for a validator that did not double sign on any of the consumer chains.")),(0,a.kt)("h2",{id:"can-consumer-chains-perform-software-upgrades"},"Can Consumer Chains perform Software Upgrades?"),(0,a.kt)("p",null,"Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM)."),(0,a.kt)("p",null,"Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module."),(0,a.kt)("h2",{id:"how-can-i-connect-to-the-testnets"},"How can I connect to the testnets?"),(0,a.kt)("p",null,"Check out the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.0.0/validators/joining-testnet"},"Joining Replicated Security testnet")," section."),(0,a.kt)("h2",{id:"how-do-i-start-using-ics"},"How do I start using ICS?"),(0,a.kt)("p",null,"To become a consumer chain use this ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.0.0/consumer-development/onboarding"},"checklist")," and check the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.0.0/consumer-development/app-integration"},"App integration section")),(0,a.kt)("h2",{id:"which-relayers-are-supported"},"Which relayers are supported?"),(0,a.kt)("p",null,"Currently supported versions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Hermes 1.4.1")),(0,a.kt)("h2",{id:"how-does-key-delegation-work-in-ics"},"How does key delegation work in ICS?"),(0,a.kt)("p",null,"You can check the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.0.0/features/key-assignment"},"Key Assignment Guide")," for specific instructions."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/1bcdc660.1290b87e.js b/legacy/assets/js/1bcdc660.1290b87e.js new file mode 100644 index 0000000000..21a6067015 --- /dev/null +++ b/legacy/assets/js/1bcdc660.1290b87e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2148],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>m});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?i(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,a,r=function(e,n){if(null==e)return{};var t,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=a.createContext({}),c=function(e){var n=a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=c(e.components);return a.createElement(l.Provider,{value:n},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},y=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=c(t),y=r,m=d["".concat(l,".").concat(y)]||d[y]||p[y]||i;return t?a.createElement(m,o(o({ref:n},u),{},{components:t})):a.createElement(m,o({ref:n},u))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,o=new Array(i);o[0]=y;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var c=2;c<i;c++)o[c]=t[c];return a.createElement.apply(null,o)}return a.createElement.apply(null,t)}y.displayName="MDXCreateElement"},2282:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var a=t(7462),r=(t(7294),t(3905));const i={sidebar_position:1},o="Key Assignment",s={unversionedId:"features/key-assignment",id:"version-v3.1.0/features/key-assignment",title:"Key Assignment",description:"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.",source:"@site/versioned_docs/version-v3.1.0/features/key-assignment.md",sourceDirName:"features",slug:"/features/key-assignment",permalink:"/interchain-security/legacy/v3.1.0/features/key-assignment",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Technical Specification",permalink:"/interchain-security/legacy/v3.1.0/introduction/technical-specification"},next:{title:"Reward distribution",permalink:"/interchain-security/legacy/v3.1.0/features/reward-distribution"}},l={},c=[{value:"Rules",id:"rules",level:2},{value:"Adding a key",id:"adding-a-key",level:2},{value:"Changing a key",id:"changing-a-key",level:2},{value:"Removing a key",id:"removing-a-key",level:2}],u={toc:c},d="wrapper";function p(e){let{components:n,...t}=e;return(0,r.kt)(d,(0,a.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"key-assignment"},"Key Assignment"),(0,r.kt)("p",null,"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.\nThere are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains."),(0,r.kt)("p",null,"The feature is outlined in this ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.1.0/adrs/adr-001-key-assignment"},"ADR-001")),(0,r.kt)("p",null,"By sending an ",(0,r.kt)("inlineCode",{parentName:"p"},"AssignConsumerKey")," transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity.")),(0,r.kt)("h2",{id:"rules"},"Rules"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"a key can be assigned before the consumer addition proposal passes on the provider"),(0,r.kt)("li",{parentName:"ul"},"validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider"),(0,r.kt)("li",{parentName:"ul"},"validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X"),(0,r.kt)("li",{parentName:"ul"},"a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Validators can use a different key for each consumer chain.")),(0,r.kt)("h2",{id:"adding-a-key"},"Adding a key"),(0,r.kt)("p",null,"First, create a new node on the consumer chain using the equivalent:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"consumerd init <moniker>\n")),(0,r.kt)("p",null,"Then query your node for the consensus key."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}\n')),(0,r.kt)("p",null,"Then, make an ",(0,r.kt)("inlineCode",{parentName:"p"},"assign-consensus-key")," transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad tx provider assign-consensus-key <consumer-chain-id> '<pubkey>' --from <tx-signer> --home <home_dir> --gas 900000 -b sync -y -o json\n")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"consumer-chain-id")," is the string identifier of the consumer chain, as assigned on the provider chain"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"consumer-pub-key")," has the following format ",(0,r.kt)("inlineCode",{parentName:"li"},'{"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}'))),(0,r.kt)("p",null,"Check that the key was assigned correcly by querying the provider:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad query provider validator-consumer-key <consumer-chain-id> cosmosvalcons1e....3xsj3ayzf4uv6\n")),(0,r.kt)("p",null,"You must use a ",(0,r.kt)("inlineCode",{parentName:"p"},"valcons")," address. You can obtain it by querying your node on the provider ",(0,r.kt)("inlineCode",{parentName:"p"},"gaiad tendermint show-address")),(0,r.kt)("p",null,"OR"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad query provider validator-provider-key <consumer-chain-id> consumervalcons1e....123asdnoaisdao\n")),(0,r.kt)("p",null,"You must use a ",(0,r.kt)("inlineCode",{parentName:"p"},"valcons")," address. You can obtain it by querying your node on the consumer ",(0,r.kt)("inlineCode",{parentName:"p"},"consumerd tendermint show-address")),(0,r.kt)("h2",{id:"changing-a-key"},"Changing a key"),(0,r.kt)("p",null,"To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied"),(0,r.kt)("h2",{id:"removing-a-key"},"Removing a key"),(0,r.kt)("p",null,"To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the ",(0,r.kt)("inlineCode",{parentName:"p"},"Adding a key")," section and using your provider consensus key."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/1bdc04ff.80430411.js b/legacy/assets/js/1bdc04ff.80430411.js new file mode 100644 index 0000000000..f039e64b32 --- /dev/null +++ b/legacy/assets/js/1bdc04ff.80430411.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8685],{3905:(e,n,t)=>{t.d(n,{Zo:()=>c,kt:()=>h});var r=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,r,o=function(e,n){if(null==e)return{};var t,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=r.createContext({}),p=function(e){var n=r.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},c=function(e){var n=p(e.components);return r.createElement(l.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=p(t),m=o,h=d["".concat(l,".").concat(m)]||d[m]||u[m]||a;return t?r.createElement(h,i(i({ref:n},c),{},{components:t})):r.createElement(h,i({ref:n},c))}));function h(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=m;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:o,i[1]=s;for(var p=2;p<a;p++)i[p]=t[p];return r.createElement.apply(null,i)}return r.createElement.apply(null,t)}m.displayName="MDXCreateElement"},7108:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>s,toc:()=>p});var r=t(7462),o=(t(7294),t(3905));const a={sidebar_position:3},i="ICS Provider Proposals",s={unversionedId:"features/proposals",id:"version-v2.4.0-lsm/features/proposals",title:"ICS Provider Proposals",description:"Interchain security module introduces 3 new proposal types to the provider.",source:"@site/versioned_docs/version-v2.4.0-lsm/features/proposals.md",sourceDirName:"features",slug:"/features/proposals",permalink:"/interchain-security/legacy/v2.4.0-lsm/features/proposals",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Reward distribution",permalink:"/interchain-security/legacy/v2.4.0-lsm/features/reward-distribution"},next:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/legacy/v2.4.0-lsm/features/slashing"}},l={},p=[{value:"<code>ConsumerAdditionProposal</code>",id:"consumeradditionproposal",level:2},{value:"<code>ConsumerRemovalProposal</code>",id:"consumerremovalproposal",level:2},{value:"ChangeRewardDenomProposal",id:"changerewarddenomproposal",level:2}],c={toc:p},d="wrapper";function u(e){let{components:n,...t}=e;return(0,o.kt)(d,(0,r.Z)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"ics-provider-proposals"},"ICS Provider Proposals"),(0,o.kt)("p",null,"Interchain security module introduces 3 new proposal types to the provider."),(0,o.kt)("p",null,"The proposals are used to propose upcoming interchain security events through governance."),(0,o.kt)("h2",{id:"consumeradditionproposal"},(0,o.kt)("inlineCode",{parentName:"h2"},"ConsumerAdditionProposal")),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"If you are preparing a ",(0,o.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," you can find more information in the ",(0,o.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/onboarding"},"consumer onboarding checklist"),".")),(0,o.kt)("p",null,"Proposal type used to suggest adding a new consumer chain."),(0,o.kt)("p",null,"When proposals of this type are passed and the ",(0,o.kt)("inlineCode",{parentName:"p"},"spawn_time")," specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain."),(0,o.kt)("p",null,"Minimal example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'{\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n "title": "Add consumer chain",\n "description": ".md description of your chain and all other relevant information",\n "chain_id": "newchain-1",\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Unbonding period for the consumer chain.\n // It should should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n "transfer_timeout_period": 1800000000000,\n "consumer_redistribution_fraction": "0.75",\n "blocks_per_distribution_transmission": 1000,\n "historical_entries": 10000,\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1"\n // relevant for chains performing a sovereign to consumer changeover\n // in order to maintan the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123"\n}\n')),(0,o.kt)("p",null,"More examples can be found in the replicated security testnet repository ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/stopped/baryon-1/proposal-baryon-1.json"},"here")," and ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/stopped/noble-1/start-proposal-noble-1.json"},"here"),"."),(0,o.kt)("h2",{id:"consumerremovalproposal"},(0,o.kt)("inlineCode",{parentName:"h2"},"ConsumerRemovalProposal")),(0,o.kt)("p",null,"Proposal type used to suggest removing an existing consumer chain."),(0,o.kt)("p",null,"When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain.\nAfter the consumer chain removal, the chain in question will no longer be secured by the provider's validator set."),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain.\nAdditional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set.\nMore information will be made available in the ",(0,o.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/offboarding"},"Consumer Offboarding Checklist"),".")),(0,o.kt)("p",null,"Minimal example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'{\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details"\n}\n')),(0,o.kt)("h2",{id:"changerewarddenomproposal"},"ChangeRewardDenomProposal"),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"ChangeRewardDenomProposal")," will only be accepted on the provider chain if at least one of the denomsToAdd or denomsToRemove fields is populated with at least one denom. Also, a denom cannot be repeated in both sets.")),(0,o.kt)("p",null,"Proposal type used to mutate the set of denoms accepted by the provider as rewards."),(0,o.kt)("p",null,"Minimal example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'{\n "title": "Add untrn as a reward denom",\n "description": "Here is more information about the proposal",\n "denomsToAdd": ["untrn"],\n "denomsToRemove": []\n}\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/1be78505.9ab70eac.js b/legacy/assets/js/1be78505.9ab70eac.js new file mode 100644 index 0000000000..f79fb7264b --- /dev/null +++ b/legacy/assets/js/1be78505.9ab70eac.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9514,4972],{9963:(e,t,n)=>{n.r(t),n.d(t,{default:()=>he});var a=n(7294),o=n(6010),l=n(1944),r=n(5281),i=n(3320),c=n(2802),s=n(4477),d=n(1116),m=n(7961),u=n(5999),b=n(2466),p=n(5936);const h={backToTopButton:"backToTopButton_sjWU",backToTopButtonShow:"backToTopButtonShow_xfvO"};function E(){const{shown:e,scrollToTop:t}=function(e){let{threshold:t}=e;const[n,o]=(0,a.useState)(!1),l=(0,a.useRef)(!1),{startScroll:r,cancelScroll:i}=(0,b.Ct)();return(0,b.RF)(((e,n)=>{let{scrollY:a}=e;const r=n?.scrollY;r&&(l.current?l.current=!1:a>=r?(i(),o(!1)):a<t?o(!1):a+window.innerHeight<document.documentElement.scrollHeight&&o(!0))})),(0,p.S)((e=>{e.location.hash&&(l.current=!0,o(!1))})),{shown:n,scrollToTop:()=>r(0)}}({threshold:300});return a.createElement("button",{"aria-label":(0,u.I)({id:"theme.BackToTopButton.buttonAriaLabel",message:"Scroll back to top",description:"The ARIA label for the back to top button"}),className:(0,o.Z)("clean-btn",r.k.common.backToTopButton,h.backToTopButton,e&&h.backToTopButtonShow),type:"button",onClick:t})}var f=n(1442),g=n(6550),v=n(7524),k=n(6668),_=n(1327),C=n(7462);function S(e){return a.createElement("svg",(0,C.Z)({width:"20",height:"20","aria-hidden":"true"},e),a.createElement("g",{fill:"#7a7a7a"},a.createElement("path",{d:"M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"}),a.createElement("path",{d:"M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"})))}const I={collapseSidebarButton:"collapseSidebarButton_PEFL",collapseSidebarButtonIcon:"collapseSidebarButtonIcon_kv0_"};function N(e){let{onClick:t}=e;return a.createElement("button",{type:"button",title:(0,u.I)({id:"theme.docs.sidebar.collapseButtonTitle",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),"aria-label":(0,u.I)({id:"theme.docs.sidebar.collapseButtonAriaLabel",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),className:(0,o.Z)("button button--secondary button--outline",I.collapseSidebarButton),onClick:t},a.createElement(S,{className:I.collapseSidebarButtonIcon}))}var T=n(9689),x=n(902);const Z=Symbol("EmptyContext"),B=a.createContext(Z);function w(e){let{children:t}=e;const[n,o]=(0,a.useState)(null),l=(0,a.useMemo)((()=>({expandedItem:n,setExpandedItem:o})),[n]);return a.createElement(B.Provider,{value:l},t)}var y=n(6043),L=n(8596),A=n(9960),H=n(2389);function M(e){let{categoryLabel:t,onClick:n}=e;return a.createElement("button",{"aria-label":(0,u.I)({id:"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel",message:"Toggle the collapsible sidebar category '{label}'",description:"The ARIA label to toggle the collapsible sidebar category"},{label:t}),type:"button",className:"clean-btn menu__caret",onClick:n})}function F(e){let{item:t,onItemClick:n,activePath:l,level:i,index:s,...d}=e;const{items:m,label:u,collapsible:b,className:p,href:h}=t,{docs:{sidebar:{autoCollapseCategories:E}}}=(0,k.L)(),f=function(e){const t=(0,H.Z)();return(0,a.useMemo)((()=>e.href?e.href:!t&&e.collapsible?(0,c.Wl)(e):void 0),[e,t])}(t),g=(0,c._F)(t,l),v=(0,L.Mg)(h,l),{collapsed:_,setCollapsed:S}=(0,y.u)({initialState:()=>!!b&&(!g&&t.collapsed)}),{expandedItem:I,setExpandedItem:N}=function(){const e=(0,a.useContext)(B);if(e===Z)throw new x.i6("DocSidebarItemsExpandedStateProvider");return e}(),T=function(e){void 0===e&&(e=!_),N(e?null:s),S(e)};return function(e){let{isActive:t,collapsed:n,updateCollapsed:o}=e;const l=(0,x.D9)(t);(0,a.useEffect)((()=>{t&&!l&&n&&o(!1)}),[t,l,n,o])}({isActive:g,collapsed:_,updateCollapsed:T}),(0,a.useEffect)((()=>{b&&null!=I&&I!==s&&E&&S(!0)}),[b,I,s,S,E]),a.createElement("li",{className:(0,o.Z)(r.k.docs.docSidebarItemCategory,r.k.docs.docSidebarItemCategoryLevel(i),"menu__list-item",{"menu__list-item--collapsed":_},p)},a.createElement("div",{className:(0,o.Z)("menu__list-item-collapsible",{"menu__list-item-collapsible--active":v})},a.createElement(A.Z,(0,C.Z)({className:(0,o.Z)("menu__link",{"menu__link--sublist":b,"menu__link--sublist-caret":!h&&b,"menu__link--active":g}),onClick:b?e=>{n?.(t),h?T(!1):(e.preventDefault(),T())}:()=>{n?.(t)},"aria-current":v?"page":void 0,"aria-expanded":b?!_:void 0,href:b?f??"#":f},d),u),h&&b&&a.createElement(M,{categoryLabel:u,onClick:e=>{e.preventDefault(),T()}})),a.createElement(y.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:_},a.createElement(j,{items:m,tabIndex:_?-1:0,onItemClick:n,activePath:l,level:i+1})))}var P=n(3919),W=n(9471);const D={menuExternalLink:"menuExternalLink_NmtK"};function R(e){let{item:t,onItemClick:n,activePath:l,level:i,index:s,...d}=e;const{href:m,label:u,className:b,autoAddBaseUrl:p}=t,h=(0,c._F)(t,l),E=(0,P.Z)(m);return a.createElement("li",{className:(0,o.Z)(r.k.docs.docSidebarItemLink,r.k.docs.docSidebarItemLinkLevel(i),"menu__list-item",b),key:u},a.createElement(A.Z,(0,C.Z)({className:(0,o.Z)("menu__link",!E&&D.menuExternalLink,{"menu__link--active":h}),autoAddBaseUrl:p,"aria-current":h?"page":void 0,to:m},E&&{onClick:n?()=>n(t):void 0},d),u,!E&&a.createElement(W.Z,null)))}const V={menuHtmlItem:"menuHtmlItem_M9Kj"};function z(e){let{item:t,level:n,index:l}=e;const{value:i,defaultStyle:c,className:s}=t;return a.createElement("li",{className:(0,o.Z)(r.k.docs.docSidebarItemLink,r.k.docs.docSidebarItemLinkLevel(n),c&&[V.menuHtmlItem,"menu__list-item"],s),key:l,dangerouslySetInnerHTML:{__html:i}})}function U(e){let{item:t,...n}=e;switch(t.type){case"category":return a.createElement(F,(0,C.Z)({item:t},n));case"html":return a.createElement(z,(0,C.Z)({item:t},n));default:return a.createElement(R,(0,C.Z)({item:t},n))}}function K(e){let{items:t,...n}=e;return a.createElement(w,null,t.map(((e,t)=>a.createElement(U,(0,C.Z)({key:t,item:e,index:t},n)))))}const j=(0,a.memo)(K),q={menu:"menu_SIkG",menuWithAnnouncementBar:"menuWithAnnouncementBar_GW3s"};function G(e){let{path:t,sidebar:n,className:l}=e;const i=function(){const{isActive:e}=(0,T.nT)(),[t,n]=(0,a.useState)(e);return(0,b.RF)((t=>{let{scrollY:a}=t;e&&n(0===a)}),[e]),e&&t}();return a.createElement("nav",{"aria-label":(0,u.I)({id:"theme.docs.sidebar.navAriaLabel",message:"Docs sidebar",description:"The ARIA label for the sidebar navigation"}),className:(0,o.Z)("menu thin-scrollbar",q.menu,i&&q.menuWithAnnouncementBar,l)},a.createElement("ul",{className:(0,o.Z)(r.k.docs.docSidebarMenu,"menu__list")},a.createElement(j,{items:n,activePath:t,level:1})))}const Y={sidebar:"sidebar_njMd",sidebarWithHideableNavbar:"sidebarWithHideableNavbar_wUlq",sidebarHidden:"sidebarHidden_VK0M",sidebarLogo:"sidebarLogo_isFc"};function O(e){let{path:t,sidebar:n,onCollapse:l,isHidden:r}=e;const{navbar:{hideOnScroll:i},docs:{sidebar:{hideable:c}}}=(0,k.L)();return a.createElement("div",{className:(0,o.Z)(Y.sidebar,i&&Y.sidebarWithHideableNavbar,r&&Y.sidebarHidden)},i&&a.createElement(_.Z,{tabIndex:-1,className:Y.sidebarLogo}),a.createElement(G,{path:t,sidebar:n}),c&&a.createElement(N,{onClick:l}))}const X=a.memo(O);var J=n(3102),Q=n(2961);const $=e=>{let{sidebar:t,path:n}=e;const l=(0,Q.e)();return a.createElement("ul",{className:(0,o.Z)(r.k.docs.docSidebarMenu,"menu__list")},a.createElement(j,{items:t,activePath:n,onItemClick:e=>{"category"===e.type&&e.href&&l.toggle(),"link"===e.type&&l.toggle()},level:1}))};function ee(e){return a.createElement(J.Zo,{component:$,props:e})}const te=a.memo(ee);function ne(e){const t=(0,v.i)(),n="desktop"===t||"ssr"===t,o="mobile"===t;return a.createElement(a.Fragment,null,n&&a.createElement(X,e),o&&a.createElement(te,e))}const ae={expandButton:"expandButton_m80_",expandButtonIcon:"expandButtonIcon_BlDH"};function oe(e){let{toggleSidebar:t}=e;return a.createElement("div",{className:ae.expandButton,title:(0,u.I)({id:"theme.docs.sidebar.expandButtonTitle",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),"aria-label":(0,u.I)({id:"theme.docs.sidebar.expandButtonAriaLabel",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),tabIndex:0,role:"button",onKeyDown:t,onClick:t},a.createElement(S,{className:ae.expandButtonIcon}))}const le={docSidebarContainer:"docSidebarContainer_b6E3",docSidebarContainerHidden:"docSidebarContainerHidden_b3ry",sidebarViewport:"sidebarViewport_Xe31"};function re(e){let{children:t}=e;const n=(0,d.V)();return a.createElement(a.Fragment,{key:n?.name??"noSidebar"},t)}function ie(e){let{sidebar:t,hiddenSidebarContainer:n,setHiddenSidebarContainer:l}=e;const{pathname:i}=(0,g.TH)(),[c,s]=(0,a.useState)(!1),d=(0,a.useCallback)((()=>{c&&s(!1),!c&&(0,f.n)()&&s(!0),l((e=>!e))}),[l,c]);return a.createElement("aside",{className:(0,o.Z)(r.k.docs.docSidebarContainer,le.docSidebarContainer,n&&le.docSidebarContainerHidden),onTransitionEnd:e=>{e.currentTarget.classList.contains(le.docSidebarContainer)&&n&&s(!0)}},a.createElement(re,null,a.createElement("div",{className:(0,o.Z)(le.sidebarViewport,c&&le.sidebarViewportHidden)},a.createElement(ne,{sidebar:t,path:i,onCollapse:d,isHidden:c}),c&&a.createElement(oe,{toggleSidebar:d}))))}const ce={docMainContainer:"docMainContainer_gTbr",docMainContainerEnhanced:"docMainContainerEnhanced_Uz_u",docItemWrapperEnhanced:"docItemWrapperEnhanced_czyv"};function se(e){let{hiddenSidebarContainer:t,children:n}=e;const l=(0,d.V)();return a.createElement("main",{className:(0,o.Z)(ce.docMainContainer,(t||!l)&&ce.docMainContainerEnhanced)},a.createElement("div",{className:(0,o.Z)("container padding-top--md padding-bottom--lg",ce.docItemWrapper,t&&ce.docItemWrapperEnhanced)},n))}const de={docPage:"docPage__5DB",docsWrapper:"docsWrapper_BCFX"};function me(e){let{children:t}=e;const n=(0,d.V)(),[o,l]=(0,a.useState)(!1);return a.createElement(m.Z,{wrapperClassName:de.docsWrapper},a.createElement(E,null),a.createElement("div",{className:de.docPage},n&&a.createElement(ie,{sidebar:n.items,hiddenSidebarContainer:o,setHiddenSidebarContainer:l}),a.createElement(se,{hiddenSidebarContainer:o},t)))}var ue=n(4972),be=n(197);function pe(e){const{versionMetadata:t}=e;return a.createElement(a.Fragment,null,a.createElement(be.Z,{version:t.version,tag:(0,i.os)(t.pluginId,t.version)}),a.createElement(l.d,null,t.noIndex&&a.createElement("meta",{name:"robots",content:"noindex, nofollow"})))}function he(e){const{versionMetadata:t}=e,n=(0,c.hI)(e);if(!n)return a.createElement(ue.default,null);const{docElement:i,sidebarName:m,sidebarItems:u}=n;return a.createElement(a.Fragment,null,a.createElement(pe,e),a.createElement(l.FG,{className:(0,o.Z)(r.k.wrapper.docsPages,r.k.page.docsDocPage,e.versionMetadata.className)},a.createElement(s.q,{version:t},a.createElement(d.b,{name:m,items:u},a.createElement(me,null,i)))))}},4972:(e,t,n)=>{n.r(t),n.d(t,{default:()=>i});var a=n(7294),o=n(5999),l=n(1944),r=n(7961);function i(){return a.createElement(a.Fragment,null,a.createElement(l.d,{title:(0,o.I)({id:"theme.NotFound.title",message:"Page Not Found"})}),a.createElement(r.Z,null,a.createElement("main",{className:"container margin-vert--xl"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col col--6 col--offset-3"},a.createElement("h1",{className:"hero__title"},a.createElement(o.Z,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),a.createElement("p",null,a.createElement(o.Z,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),a.createElement("p",null,a.createElement(o.Z,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.")))))))}},4477:(e,t,n)=>{n.d(t,{E:()=>i,q:()=>r});var a=n(7294),o=n(902);const l=a.createContext(null);function r(e){let{children:t,version:n}=e;return a.createElement(l.Provider,{value:n},t)}function i(){const e=(0,a.useContext)(l);if(null===e)throw new o.i6("DocsVersionProvider");return e}}}]); \ No newline at end of file diff --git a/legacy/assets/js/1ca03be8.5d6bad63.js b/legacy/assets/js/1ca03be8.5d6bad63.js new file mode 100644 index 0000000000..1eeab69868 --- /dev/null +++ b/legacy/assets/js/1ca03be8.5d6bad63.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1043],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function c(e,t){if(null==e)return{};var n,o,r=function(e,t){if(null==e)return{};var n,o,r={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=o.createContext({}),l=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},d=function(e){var t=l(e.components);return o.createElement(s.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=c(e,["components","mdxType","originalType","parentName"]),p=l(n),h=r,m=p["".concat(s,".").concat(h)]||p[h]||u[h]||i;return n?o.createElement(m,a(a({ref:t},d),{},{components:n})):o.createElement(m,a({ref:t},d))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=h;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[p]="string"==typeof e?e:r,a[1]=c;for(var l=2;l<i;l++)a[l]=n[l];return o.createElement.apply(null,a)}return o.createElement.apply(null,n)}h.displayName="MDXCreateElement"},5055:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>u,frontMatter:()=>i,metadata:()=>c,toc:()=>l});var o=n(7462),r=(n(7294),n(3905));const i={sidebar_position:1},a="Overview",c={unversionedId:"introduction/overview",id:"version-v2.4.0-lsm/introduction/overview",title:"Overview",description:"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.",source:"@site/versioned_docs/version-v2.4.0-lsm/introduction/overview.md",sourceDirName:"introduction",slug:"/introduction/overview",permalink:"/interchain-security/legacy/v2.4.0-lsm/introduction/overview",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Docs",permalink:"/interchain-security/legacy/v2.4.0-lsm/"},next:{title:"Terminology",permalink:"/interchain-security/legacy/v2.4.0-lsm/introduction/terminology"}},s={},l=[{value:"Why Replicated Security?",id:"why-replicated-security",level:2},{value:"Core protocol",id:"core-protocol",level:2},{value:"Downtime Slashing",id:"downtime-slashing",level:3},{value:"Tokenomics and Rewards",id:"tokenomics-and-rewards",level:3}],d={toc:l},p="wrapper";function u(e){let{components:t,...n}=e;return(0,r.kt)(p,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"overview"},"Overview"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another."),(0,r.kt)("br",null),'Replicated security allows anyone to launch a "consumer" blockchain using the same validator set as the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit the full security and decentralization of the provider.'),(0,r.kt)("h2",{id:"why-replicated-security"},"Why Replicated Security?"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Full provider security. At launch, consumer chains are secured by the full validator set and market cap of the provider chain."),(0,r.kt)("li",{parentName:"ul"},"Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum."),(0,r.kt)("li",{parentName:"ul"},"Projects keep majority of gas fees. Depending on configuration, these fees either go to the project\u2019s community DAO, or can be used in the protocol in other ways."),(0,r.kt)("li",{parentName:"ul"},"No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. A governance vote will take place for a chain to get adopted by the provider validators which will encourage participation and signal strong buy-in into the project's long-term success."),(0,r.kt)("li",{parentName:"ul"},"Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set.")),(0,r.kt)("h2",{id:"core-protocol"},"Core protocol"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Protocol specification is available as ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md"},"ICS-028")," in the IBC repository.")),(0,r.kt)("p",null,"Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer."),(0,r.kt)("p",null,"To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider."),(0,r.kt)("h3",{id:"downtime-slashing"},"Downtime Slashing"),(0,r.kt)("p",null,"If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period."),(0,r.kt)("h3",{id:"tokenomics-and-rewards"},"Tokenomics and Rewards"),(0,r.kt)("p",null,"Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/1d3f4228.5d264fe1.js b/legacy/assets/js/1d3f4228.5d264fe1.js new file mode 100644 index 0000000000..75f558b78b --- /dev/null +++ b/legacy/assets/js/1d3f4228.5d264fe1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[863],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=c(n),m=a,h=d["".concat(s,".").concat(m)]||d[m]||p[m]||o;return n?r.createElement(h,i(i({ref:t},u),{},{components:n})):r.createElement(h,i({ref:t},u))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,i[1]=l;for(var c=2;c<o;c++)i[c]=n[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},3881:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const o={sidebar_position:2,title:"ADR Template"},i="ADR {ADR-NUMBER}:",l={unversionedId:"adrs/adr-template",id:"version-v2.4.0-lsm/adrs/adr-template",title:"ADR Template",description:"Changelog",source:"@site/versioned_docs/version-v2.4.0-lsm/adrs/adr-template.md",sourceDirName:"adrs",slug:"/adrs/adr-template",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-template",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"ADR Template"},sidebar:"tutorialSidebar",previous:{title:"ADRs",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/intro"},next:{title:"Key Assignment",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-001-key-assignment"}},s={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],u={toc:c},d="wrapper";function p(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-adr-number-title"},"ADR {ADR-NUMBER}: {TITLE}"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"{date}: {changelog}")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},'A decision may be "proposed" if it hasn\'t been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement.')),(0,a.kt)("p",null,"{Deprecated|Proposed|Accepted}"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution. ")),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"This section explains all of the details of the proposed solution, including implementation details.\nIt should also describe affects / corollary items that may need to be changed as a part of this.\nIf the proposed change will be large, please also indicate a way to do the change to maximize ease of review.\n(e.g. the optimal split of things to do between separate PR's)")),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},'This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones.')),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Are there any relevant PR comments, issues that led up to this, or articles referrenced for why we made the given design choice? If so link them here!")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"{reference link}")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/1ec51b74.060236b9.js b/legacy/assets/js/1ec51b74.060236b9.js new file mode 100644 index 0000000000..5cf6551490 --- /dev/null +++ b/legacy/assets/js/1ec51b74.060236b9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8779],{3905:(e,t,o)=>{o.d(t,{Zo:()=>c,kt:()=>m});var n=o(7294);function a(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function r(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,n)}return o}function i(e){for(var t=1;t<arguments.length;t++){var o=null!=arguments[t]?arguments[t]:{};t%2?r(Object(o),!0).forEach((function(t){a(e,t,o[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(o)):r(Object(o)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(o,t))}))}return e}function l(e,t){if(null==e)return{};var o,n,a=function(e,t){if(null==e)return{};var o,n,a={},r=Object.keys(e);for(n=0;n<r.length;n++)o=r[n],t.indexOf(o)>=0||(a[o]=e[o]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n<r.length;n++)o=r[n],t.indexOf(o)>=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(a[o]=e[o])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),o=t;return e&&(o="function"==typeof e?e(t):i(i({},t),e)),o},c=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var o=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=u(o),h=a,m=d["".concat(s,".").concat(h)]||d[h]||p[h]||r;return o?n.createElement(m,i(i({ref:t},c),{},{components:o})):n.createElement(m,i({ref:t},c))}));function m(e,t){var o=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=o.length,i=new Array(r);i[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,i[1]=l;for(var u=2;u<r;u++)i[u]=o[u];return n.createElement.apply(null,i)}return n.createElement.apply(null,o)}h.displayName="MDXCreateElement"},9762:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>p,frontMatter:()=>r,metadata:()=>l,toc:()=>u});var n=o(7462),a=(o(7294),o(3905));const r={sidebar_position:10,title:"Soft Opt-Out"},i=void 0,l={unversionedId:"adrs/adr-009-soft-opt-out",id:"version-v3.3.1-lsm/adrs/adr-009-soft-opt-out",title:"Soft Opt-Out",description:"ADR 009: Soft Opt-Out",source:"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-009-soft-opt-out.md",sourceDirName:"adrs",slug:"/adrs/adr-009-soft-opt-out",permalink:"/interchain-security/legacy/adrs/adr-009-soft-opt-out",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:10,frontMatter:{sidebar_position:10,title:"Soft Opt-Out"},sidebar:"tutorialSidebar",previous:{title:"Throttle with retries",permalink:"/interchain-security/legacy/adrs/adr-008-throttle-retries"},next:{title:"Standalone to Consumer Changeover",permalink:"/interchain-security/legacy/adrs/adr-010-standalone-changeover"}},s={},u=[{value:"ADR 009: Soft Opt-Out",id:"adr-009-soft-opt-out",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],c={toc:u},d="wrapper";function p(e){let{components:t,...o}=e;return(0,a.kt)(d,(0,n.Z)({},c,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"adr-009-soft-opt-out"},"ADR 009: Soft Opt-Out"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"6/13/23: Initial draft of ADR. Feature already implemented and in production.")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"Some small validators may not have the resources needed to validate all consumer chains. Therefore a need exists to allow the bottom ",(0,a.kt)("inlineCode",{parentName:"p"},"x%")," of validators to opt-out of validating a consumer chain. Meaning downtime infractions for these validators are dropped without ever reaching the provider."),(0,a.kt)("p",null,"This document specifies a modification to the ccv protocol which allows the bottom x% of the validator set by power to opt out of validating consumer chains without being jailed or otherwise punished for it. The feature is implemented with entirely consumer-side code."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"A consumer param exists, known as ",(0,a.kt)("inlineCode",{parentName:"p"},"SoftOptOutThreshold"),", which is a string decimal in the range of ","[0, 0.2]",", that determines the portion of validators which are allowed to opt out of validating that specific consumer."),(0,a.kt)("p",null,"In every consumer beginblocker, a function is ran which determines the so called ",(0,a.kt)("em",{parentName:"p"},"smallest non opt-out voting power"),". Validators with voting power greater than or equal to this value must validate the consumer chain, while validators below this value may opt out of validating the consumer chain."),(0,a.kt)("p",null,"The smallest non opt-out voting power is recomputed every beginblocker in ",(0,a.kt)("inlineCode",{parentName:"p"},"UpdateSmallestNonOptOutPower()"),". In a nutshell, the method obtains the total voting power of the consumer, iterates through the full valset (ordered power ascending) keeping track of a power sum, and when ",(0,a.kt)("inlineCode",{parentName:"p"},"powerSum / totalPower > SoftOptOutThreshold"),", the ",(0,a.kt)("inlineCode",{parentName:"p"},"SmallestNonOptOutPower")," is found and persisted."),(0,a.kt)("p",null,"Then, whenever the ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash()")," interface is executed on the consumer, if the voting power of the relevant validator being slashed is less than ",(0,a.kt)("inlineCode",{parentName:"p"},"SmallestNonOptOutPower")," for that block, the slash request is dropped and never sent to the provider."),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Small validators can opt out of validating specific consumers without being punished for it.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"The bottom ",(0,a.kt)("inlineCode",{parentName:"li"},"x%")," is still part of the total voting power of the consumer chain. This means that if the soft opt-out threshold is set to ",(0,a.kt)("inlineCode",{parentName:"li"},"10%")," for example, and every validator in the bottom ",(0,a.kt)("inlineCode",{parentName:"li"},"10%")," opts out from validating the consumer, then a ",(0,a.kt)("inlineCode",{parentName:"li"},"24%")," downtime of the remaining voting power would halt the chain. This may be especially problematic during consumer upgrades."),(0,a.kt)("li",{parentName:"ul"},"In nominal scenarios, consumers with soft opt out enabled will be constructing slash packets for small vals, which may be dropped. This is wasted computation, but necessary to keep implementation simple. Note that the sdk's ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/cosmos-sdk/blob/d3f09c222243bb3da3464969f0366330dcb977a8/x/slashing/keeper/infractions.go#L75"},"full downtime logic")," is always executed on the consumer, which can be computationally expensive and slow down certain blocks.")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Validators in the bottom of the valset who don't have to validate, may receive large delegation(s) which suddenly boost the validator to the subset that has to validate. This may catch the validator off guard.")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Original issue with some napkin math ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/784"},"#784"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/1f0eef20.67ec7875.js b/legacy/assets/js/1f0eef20.67ec7875.js new file mode 100644 index 0000000000..9cbdaa5f47 --- /dev/null +++ b/legacy/assets/js/1f0eef20.67ec7875.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4895],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),c=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),m=a,h=u["".concat(l,".").concat(m)]||u[m]||d[m]||i;return n?o.createElement(h,r(r({ref:t},p),{},{components:n})):o.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,r=new Array(i);r[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,r[1]=s;for(var c=2;c<i;c++)r[c]=n[c];return o.createElement.apply(null,r)}return o.createElement.apply(null,n)}m.displayName="MDXCreateElement"},6313:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var o=n(7462),a=(n(7294),n(3905));const i={sidebar_position:4,title:"Equivocation governance proposal"},r="ADR 003: Equivocation governance proposal",s={unversionedId:"adrs/adr-003-equivocation-gov-proposal",id:"version-v3.2.0/adrs/adr-003-equivocation-gov-proposal",title:"Equivocation governance proposal",description:"Changelog",source:"@site/versioned_docs/version-v3.2.0/adrs/adr-003-equivocation-gov-proposal.md",sourceDirName:"adrs",slug:"/adrs/adr-003-equivocation-gov-proposal",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-003-equivocation-gov-proposal",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Equivocation governance proposal"},sidebar:"tutorialSidebar",previous:{title:"Jail Throttling",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-002-throttle"},next:{title:"Cryptographic verification of equivocation evidence",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-005-cryptographic-equivocation-verification"}},l={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],p={toc:c},u="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-003-equivocation-governance-proposal"},"ADR 003: Equivocation governance proposal"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"2023-02-06: Initial draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain."),(0,a.kt)("p",null,"For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain."),(0,a.kt)("p",null,"A new kind of governance proposal is added to the ",(0,a.kt)("inlineCode",{parentName:"p"},"provider")," module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain."),(0,a.kt)("p",null,"If such proposal passes, the proposal handler delegates to the ",(0,a.kt)("inlineCode",{parentName:"p"},"evidence")," module to process the equivocation. This module ensures the evidence isn\u2019t too old, or else ignores it (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/21021b837882d1d40f1d79bcbc4fad2e79a3fefe/x/evidence/keeper/infraction.go#L54-L62"},"code"),"). ",(0,a.kt)("em",{parentName:"p"},"Too old")," is determined by 2 consensus params : "),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"evidence.max_age_duration")," number of nanoseconds before an evidence is considered too old"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"evidence.max_age_numblocks")," number of blocks before an evidence is considered too old.")),(0,a.kt)("p",null,"On the hub, those parameters are equals to "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682\n(...)\n"evidence": {\n "max_age_num_blocks": "1000000",\n "max_age_duration": "172800000000000",\n (...)\n},\n(...)\n')),(0,a.kt)("p",null,"A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the ",(0,a.kt)("inlineCode",{parentName:"p"},"evidence")," module when the proposal passes and is handled by the hub."),(0,a.kt)("p",null,"For ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks=1M"),", the parameter is big enough if we consider the hub produces 12k blocks per day (",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_year/365 = 436,0000/365"),"). The evidence can be up to 83 days old (",(0,a.kt)("inlineCode",{parentName:"p"},"1,000,000/12,000"),") and not be ignored."),(0,a.kt)("p",null,"For ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_duration=172,800,000,000,000"),", the parameter is too low, because the value is in nanoseconds so it\u2019s 2 days. Fortunately the condition that checks those 2 parameters uses a ",(0,a.kt)("strong",{parentName:"p"},"AND"),", so if ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks")," condition passes, the evidence won\u2019t be ignored."),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Remove the possibility from a malicious consumer chain to \u201cattack\u201d the provider chain by slashing/jailing validators."),(0,a.kt)("li",{parentName:"ul"},"Provide a more acceptable implementation for the validator community.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Punishment action of double-signing isn\u2019t \u201cautomated\u201d, a governance proposal is required which takes more time."),(0,a.kt)("li",{parentName:"ul"},"You need to pay 250ATOM to submit an equivocation evidence.")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"PR that ignores non downtime slash packet : ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/692"},"https://github.com/cosmos/interchain-security/pull/692")),(0,a.kt)("li",{parentName:"ul"},"PR that adds the governance slash proposal: ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/703"},"https://github.com/cosmos/interchain-security/pull/703"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/1f170e32.5eb3a801.js b/legacy/assets/js/1f170e32.5eb3a801.js new file mode 100644 index 0000000000..a36892138b --- /dev/null +++ b/legacy/assets/js/1f170e32.5eb3a801.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[847],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>m});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),d=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=d(e.components);return a.createElement(l.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=d(n),h=i,m=p["".concat(l,".").concat(h)]||p[h]||u[h]||r;return n?a.createElement(m,o(o({ref:t},c),{},{components:n})):a.createElement(m,o({ref:t},c))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:i,o[1]=s;for(var d=2;d<r;d++)o[d]=n[d];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},9206:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>s,toc:()=>d});var a=n(7462),i=(n(7294),n(3905));const r={sidebar_position:4},o="Validator instructions for Changeover Procedure",s={unversionedId:"validators/changeover-procedure",id:"version-v3.3.1-lsm/validators/changeover-procedure",title:"Validator instructions for Changeover Procedure",description:"More details available in Changeover Procedure documentation.",source:"@site/versioned_docs/version-v3.3.1-lsm/validators/changeover-procedure.md",sourceDirName:"validators",slug:"/validators/changeover-procedure",permalink:"/interchain-security/legacy/validators/changeover-procedure",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Withdrawing consumer chain validator rewards",permalink:"/interchain-security/legacy/validators/withdraw_rewards"},next:{title:"Joining Neutron",permalink:"/interchain-security/legacy/validators/joining-neutron"}},l={},d=[{value:"Timeline",id:"timeline",level:2},{value:"1. <code>ConsumerAdditionProposal</code> on provider chain",id:"1-consumeradditionproposal-on-provider-chain",level:3},{value:"2. <code>SoftwareUpgradeProposal</code> on the standalone/consumer chain",id:"2-softwareupgradeproposal-on-the-standaloneconsumer-chain",level:3},{value:"3. Assigning a consumer key",id:"3-assigning-a-consumer-key",level:3},{value:"4. Perform the software ugprade on standalone chain",id:"4-perform-the-software-ugprade-on-standalone-chain",level:3},{value:"FAQ",id:"faq",level:2},{value:"Can I reuse the same validator key for the <code>consumer</code> chain that I am already using on the <code>standalone</code> chain? Will I need to perform a <code>AssignConsumerKey</code> tx with this key before spawn time?",id:"can-i-reuse-the-same-validator-key-for-the-consumer-chain-that-i-am-already-using-on-the-standalone-chain-will-i-need-to-perform-a-assignconsumerkey-tx-with-this-key-before-spawn-time",level:3},{value:"Can I continue using the same node that was validating the <code>standalone</code> chain?",id:"can-i-continue-using-the-same-node-that-was-validating-the-standalone-chain",level:3},{value:"Can I set up a new node to validate the <code>standalone/consumer</code> chain after it transitions to replicated security?",id:"can-i-set-up-a-new-node-to-validate-the-standaloneconsumer-chain-after-it-transitions-to-replicated-security",level:3},{value:"What happens to the <code>standalone</code> validator set after it after it transitions to replicated security?",id:"what-happens-to-the-standalone-validator-set-after-it-after-it-transitions-to-replicated-security",level:3},{value:"Credits",id:"credits",level:2}],c={toc:d},p="wrapper";function u(e){let{components:t,...r}=e;return(0,i.kt)(p,(0,a.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"validator-instructions-for-changeover-procedure"},"Validator instructions for Changeover Procedure"),(0,i.kt)("p",null,"More details available in ",(0,i.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/changeover-procedure"},"Changeover Procedure documentation"),"."),(0,i.kt)("p",null,"A major difference betwen launching a new consumer chain vs. onboarding a standalone chain to ICS is that there is no consumer genesis available for the standalone chain. Since a standalone chain already exists, its state must be preserved once it transitions to being a consumer chain."),(0,i.kt)("h2",{id:"timeline"},"Timeline"),(0,i.kt)("p",null,"Upgrading standalone chains can be best visualised using a timeline, such as the one available ",(0,i.kt)("a",{parentName:"p",href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt"},"Excalidraw graphic by Stride"),"."),(0,i.kt)("p",null,"There is some flexibility with regards to how the changeover procedure is executed, so please make sure to follow the guides provided by the team doing the changeover."),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"Standalone to consumer transition timeline",src:n(4191).Z,width:"5307",height:"2157"})),(0,i.kt)("h3",{id:"1-consumeradditionproposal-on-provider-chain"},"1. ",(0,i.kt)("inlineCode",{parentName:"h3"},"ConsumerAdditionProposal")," on provider chain"),(0,i.kt)("p",null,"This step will add the standalone chain to the list of consumer chains secured by the provider.\nThis step dictates the ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time"),". After ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," the CCV state (initial validator set of the provider) will be available to the consumer."),(0,i.kt)("p",null,"To obtain it from the provider use:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad q provider consumer-genesis stride-1 -o json > ccv-state.json\njq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' genesis.json ccv-state.json > ccv.json\n")),(0,i.kt)("h3",{id:"2-softwareupgradeproposal-on-the-standaloneconsumer-chain"},"2. ",(0,i.kt)("inlineCode",{parentName:"h3"},"SoftwareUpgradeProposal")," on the standalone/consumer chain"),(0,i.kt)("p",null,"This upgrade proposal will introduce ICS to the standalone chain, making it a consumer."),(0,i.kt)("h3",{id:"3-assigning-a-consumer-key"},"3. Assigning a consumer key"),(0,i.kt)("p",null,"After ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time"),", make sure to assign a consumer key if you intend to use one."),(0,i.kt)("p",null,"Instructions are available ",(0,i.kt)("a",{parentName:"p",href:"/interchain-security/legacy/features/key-assignment"},"here")),(0,i.kt)("h3",{id:"4-perform-the-software-ugprade-on-standalone-chain"},"4. Perform the software ugprade on standalone chain"),(0,i.kt)("p",null,"Please use instructions provided by the standalone chain team and make sure to reach out if you are facing issues.\nThe upgrade preparation depends on your setup, so please make sure you prepare ahead of time."),(0,i.kt)("admonition",{type:"danger"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"ccv.json")," from step 1. must be made available on the machine running the standalone/consumer chain at standalone chain ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height"),". This file contains the initial validator set and parameters required for normal ICS operation."),(0,i.kt)("p",{parentName:"admonition"},"Usually, the file is placed in ",(0,i.kt)("inlineCode",{parentName:"p"},"$NODE_HOME/config")," but this is not a strict requirement. The exact details are available in the upgrade code of the standalone/consumer chain.")),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Performing this upgrade will transition the standalone chain to be a consumer chain.")),(0,i.kt)("p",null,'After 3 blocks, the standalone chain will stop using the "old" validator set and begin using the ',(0,i.kt)("inlineCode",{parentName:"p"},"provider")," validator set."),(0,i.kt)("h2",{id:"faq"},"FAQ"),(0,i.kt)("h3",{id:"can-i-reuse-the-same-validator-key-for-the-consumer-chain-that-i-am-already-using-on-the-standalone-chain-will-i-need-to-perform-a-assignconsumerkey-tx-with-this-key-before-spawn-time"},"Can I reuse the same validator key for the ",(0,i.kt)("inlineCode",{parentName:"h3"},"consumer")," chain that I am already using on the ",(0,i.kt)("inlineCode",{parentName:"h3"},"standalone")," chain? Will I need to perform a ",(0,i.kt)("inlineCode",{parentName:"h3"},"AssignConsumerKey")," tx with this key before spawn time?"),(0,i.kt)("p",null,"Validators must either assign a key or use the same key as on the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider"),"."),(0,i.kt)("p",null,"If you are validating both the ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," and the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider"),", you ",(0,i.kt)("strong",{parentName:"p"},"can")," use your current ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," key with some caveats:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"you must submit an ",(0,i.kt)("inlineCode",{parentName:"li"},"AssignConsumerKey")," tx with your current ",(0,i.kt)("inlineCode",{parentName:"li"},"standalone")," validator key"),(0,i.kt)("li",{parentName:"ul"},"it is best to submit ",(0,i.kt)("inlineCode",{parentName:"li"},"AssignConsumerKey")," tx before ",(0,i.kt)("inlineCode",{parentName:"li"},"spawn_time")),(0,i.kt)("li",{parentName:"ul"},"if you do not submit the Tx, it is assumed that you will be re-using your ",(0,i.kt)("inlineCode",{parentName:"li"},"provider")," key to validate the ",(0,i.kt)("inlineCode",{parentName:"li"},"standalone/consumer")," chain")),(0,i.kt)("h3",{id:"can-i-continue-using-the-same-node-that-was-validating-the-standalone-chain"},"Can I continue using the same node that was validating the ",(0,i.kt)("inlineCode",{parentName:"h3"},"standalone")," chain?"),(0,i.kt)("p",null,"Yes."),(0,i.kt)("p",null,"Please assign your consensus key as stated aboce."),(0,i.kt)("h3",{id:"can-i-set-up-a-new-node-to-validate-the-standaloneconsumer-chain-after-it-transitions-to-replicated-security"},"Can I set up a new node to validate the ",(0,i.kt)("inlineCode",{parentName:"h3"},"standalone/consumer")," chain after it transitions to replicated security?"),(0,i.kt)("p",null,"Yes."),(0,i.kt)("p",null,"If you are planning to do this please make sure that the node is synced with ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," network and to submit ",(0,i.kt)("inlineCode",{parentName:"p"},"AssignConsumerKey")," tx before ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time"),"."),(0,i.kt)("h3",{id:"what-happens-to-the-standalone-validator-set-after-it-after-it-transitions-to-replicated-security"},"What happens to the ",(0,i.kt)("inlineCode",{parentName:"h3"},"standalone")," validator set after it after it transitions to replicated security?"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," chain validators will stop being validators after the first 3 blocks are created while using replicated security. The ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," validators will become ",(0,i.kt)("strong",{parentName:"p"},"governors")," and still can receive delegations if the ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer")," chain is using the ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer-democracy")," module."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Governors DO NOT VALIDATE BLOCKS"),"."),(0,i.kt)("p",null,"Instead, they can participate in the governance process and take on other chain-specific roles."),(0,i.kt)("h2",{id:"credits"},"Credits"),(0,i.kt)("p",null,"Thank you Stride team for providing detailed instructions about the changeover procedure."))}u.isMDXComponent=!0},4191:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/ics_changeover_timeline_stride-9bcad1834fef24a0fea7f2c80c9ccd71.png"}}]); \ No newline at end of file diff --git a/legacy/assets/js/20543744.c24270e7.js b/legacy/assets/js/20543744.c24270e7.js new file mode 100644 index 0000000000..520abe9032 --- /dev/null +++ b/legacy/assets/js/20543744.c24270e7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2002],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>g});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),h=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=h(e.components);return o.createElement(l.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),c=h(n),u=a,g=c["".concat(l,".").concat(u)]||c[u]||p[u]||i;return n?o.createElement(g,r(r({ref:t},d),{},{components:n})):o.createElement(g,r({ref:t},d))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,r=new Array(i);r[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:a,r[1]=s;for(var h=2;h<i;h++)r[h]=n[h];return o.createElement.apply(null,r)}return o.createElement.apply(null,n)}u.displayName="MDXCreateElement"},3115:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>h});var o=n(7462),a=(n(7294),n(3905));const i={sidebar_position:14,title:"Slashing on the provider for consumer equivocation"},r="ADR 013: Slashing on the provider for consumer equivocation",s={unversionedId:"adrs/adr-013-equivocation-slashing",id:"version-v3.3.0/adrs/adr-013-equivocation-slashing",title:"Slashing on the provider for consumer equivocation",description:"Changelog",source:"@site/versioned_docs/version-v3.3.0/adrs/adr-013-equivocation-slashing.md",sourceDirName:"adrs",slug:"/adrs/adr-013-equivocation-slashing",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-013-equivocation-slashing",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:14,frontMatter:{sidebar_position:14,title:"Slashing on the provider for consumer equivocation"},sidebar:"tutorialSidebar",previous:{title:"Separate Releasing",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-012-separate-releasing"}},l={},h=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Single-chain slashing",id:"single-chain-slashing",level:3},{value:"Slashing undelegations and redelegations",id:"slashing-undelegations-and-redelegations",level:4},{value:"Slashing delegations",id:"slashing-delegations",level:4},{value:"Old evidence",id:"old-evidence",level:4},{value:"Slashing for equivocation on the consumer",id:"slashing-for-equivocation-on-the-consumer",level:3},{value:"Proposed solution",id:"proposed-solution",level:2},{value:"Implementation",id:"implementation",level:3},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}],d={toc:h},c="wrapper";function p(e){let{components:t,...n}=e;return(0,a.kt)(c,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-013-slashing-on-the-provider-for-consumer-equivocation"},"ADR 013: Slashing on the provider for consumer equivocation"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"1st Sept. 2023: Initial draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Proposed"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"This ADR presents some approaches on how to slash on the provider chain validators that performed equivocations on consumer chains.\nCurrently, the provider chain can ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232"},"receive and verify evidence of equivocation"),", but it cannot slash the misbehaving validator."),(0,a.kt)("p",null,"In the remainder of this section, we explain how slashing is performed on a single chain and show why slashing on the provider for equivocation on the consumer is challenging."),(0,a.kt)("p",null,"Note that future versions of the Cosmos SDK, CometBFT, and ibc-go could modify the way we slash, etc. Therefore, a future reader of this ADR, should note that when we refer to Cosmos SDK, CometBFT, and ibc-go we specifically refer to their ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/intro/overview"},"v0.47"),", ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cometbft.com/v0.37/"},"v0.37")," and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/v7.3.0"},"v7.3.0")," versions respectively."),(0,a.kt)("h3",{id:"single-chain-slashing"},"Single-chain slashing"),(0,a.kt)("p",null,"Slashing is implemented across the ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/slashing"},"slashing"),"\nand ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/staking"},"staking")," modules.\nThe slashing module's keeper calls the staking module's ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash()")," method, passing among others, the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," (i.e., the height when the equivocation occurred), the validator's ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," at the infraction height, and the ",(0,a.kt)("inlineCode",{parentName:"p"},"slashFactor")," (currently set to ",(0,a.kt)("inlineCode",{parentName:"p"},"5%")," in case of equivocation on the Cosmos Hub)."),(0,a.kt)("h4",{id:"slashing-undelegations-and-redelegations"},"Slashing undelegations and redelegations"),(0,a.kt)("p",null,"To slash undelegations, ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash")," goes through all undelegations and checks whether they started before or after the infraction occurred. If an undelegation started before the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight"),", then it is ",(0,a.kt)("strong",{parentName:"p"},"not")," slashed, otherwise it is slashed by ",(0,a.kt)("inlineCode",{parentName:"p"},"slashFactor"),"."),(0,a.kt)("p",null,"The slashing of redelegations happens in a similar way, meaning that ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash")," goes through all redelegations and checks whether the redelegations started before or after the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight"),"."),(0,a.kt)("h4",{id:"slashing-delegations"},"Slashing delegations"),(0,a.kt)("p",null,"Besides undelegations and redelegations, the validator's delegations need to also be slashed.\nThis is performed by deducting the appropriate amount of tokens from the validator. Note that this deduction is computed based on the voting ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," the misbehaving validator had at the height of the equivocation. As a result of the tokens deduction,\nthe ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/staking#delegator-shares"},"tokens per share"),"\nreduce and hence later on, when delegators undelegate or redelegate, the delegators retrieve back less\ntokens, effectively having their tokens slashed. The rationale behind this slashing mechanism, as mentioned in the ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/staking#delegator-shares"},"Cosmos SDK documentation")," "),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"[...]"," is to simplify the accounting around slashing. Rather than iteratively slashing the tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, effectively reducing the value of each issued delegator share.")),(0,a.kt)("p",null,"This approach of slashing delegations does not utilize the\n",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," in any way and hence the following scenario could occur:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"a validator ",(0,a.kt)("inlineCode",{parentName:"li"},"V")," performs an equivocation at a height ",(0,a.kt)("inlineCode",{parentName:"li"},"Hi")),(0,a.kt)("li",{parentName:"ol"},"a new delegator ",(0,a.kt)("inlineCode",{parentName:"li"},"D")," delegates to ",(0,a.kt)("inlineCode",{parentName:"li"},"V")," after height ",(0,a.kt)("inlineCode",{parentName:"li"},"Hi")),(0,a.kt)("li",{parentName:"ol"},"evidence of the equivocation by validator ",(0,a.kt)("inlineCode",{parentName:"li"},"V")," is received"),(0,a.kt)("li",{parentName:"ol"},"the tokens of delegator ",(0,a.kt)("inlineCode",{parentName:"li"},"D")," are slashed")),(0,a.kt)("p",null,"In the above scenario, delegator ",(0,a.kt)("inlineCode",{parentName:"p"},"D")," is slashed, even though ",(0,a.kt)("inlineCode",{parentName:"p"},"D"),"'s voting power did not contribute to the infraction. "),(0,a.kt)("h4",{id:"old-evidence"},"Old evidence"),(0,a.kt)("p",null,"In the single-chain case, old evidence (e.g., from 3 years ago) is ignored. This is achieved through\n",(0,a.kt)("a",{parentName:"p",href:"https://docs.cometbft.com/v0.37/spec/consensus/evidence"},"CometBFT")," that ignores old evidence based on the parameters ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeNumBlocks")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeDuration")," (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.37.0/evidence/pool.go#271"},"here"),").\nAdditionally, note that when the evidence is sent by CometBFT to the application, the evidence is rechecked in the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L54"},"evidence module")," of Cosmos SDK and if it is old, the evidence is ignored.\nIn Cosmos Hub, the ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeNumBlocks")," is set to 1000000 (i.e., ~70 days if we assume we need ~6 sec per block) and ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeDuration")," is set to 172800000000000 ns (i.e., 2 days). Because of this check, we can easily exclude old evidence."),(0,a.kt)("h3",{id:"slashing-for-equivocation-on-the-consumer"},"Slashing for equivocation on the consumer"),(0,a.kt)("p",null,"In the single-chain case, slashing requires both the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and the voting ",(0,a.kt)("inlineCode",{parentName:"p"},"power"),".\nIn order to slash on the provider for an equivocation on a consumer, we need to have both the provider's ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and voting ",(0,a.kt)("inlineCode",{parentName:"p"},"power"),".\nNote that the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," on the consumer chain must be mapped to a height on the provider chain.\nUnless we have a way to find the corresponding ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," on the provider chain, we cannot slash for equivocation on the consumer in the same way as we would slash in the single-chain case."),(0,a.kt)("p",null,"The challenge of figuring out the corresponding ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," values on the provider chain is due to the following trust assumption:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"We trust the consensus layer and validator set of the consumer chains, ",(0,a.kt)("em",{parentName:"li"},"but we do not trust the application layer"),".")),(0,a.kt)("p",null,"As a result, we cannot trust anything that stems from the ",(0,a.kt)("em",{parentName:"p"},"application state")," of a consumer chain."),(0,a.kt)("p",null,"Note that when a relayer or a user sends evidence through a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232"},"MsgSubmitConsumerDoubleVoting")," message, the provider gets access to ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.37.0/types/evidence.go#L35"},"DuplicateVoteEvidence"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-protobuf"},'type DuplicateVoteEvidence struct {\n VoteA *Vote `json:"vote_a"`\n VoteB *Vote `json:"vote_b"`\n\n // abci specific information\n TotalVotingPower int64\n ValidatorPower int64\n Timestamp time.Time\n}\n')),(0,a.kt)("p",null,'The "abci specific information" fields cannot be trusted because they are not signed. Therefore,\nwe can use neither ',(0,a.kt)("inlineCode",{parentName:"p"},"ValidatorPower")," for slashing on the provider chain, nor the ",(0,a.kt)("inlineCode",{parentName:"p"},"Timestamp")," to check the evidence age. We can get the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," from the votes, but this ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," corresponds to the infraction height on the consumer and ",(0,a.kt)("strong",{parentName:"p"},"not")," on the provider chain.\nSimilarly, when a relayer or a user sends evidence through a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/826"},"MsgSubmitConsumerMisbehaviour")," message, the provider gets access to ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/v7.3.0/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79"},"Misbehaviour")," that we cannot use to extract the infraction height, power, or the time on the provider chain."),(0,a.kt)("h2",{id:"proposed-solution"},"Proposed solution"),(0,a.kt)("p",null,"As a first iteration, we propose the following approach. At the moment the provider receives evidence of equivocation on a consumer:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"slash all the undelegations and redelegations using ",(0,a.kt)("inlineCode",{parentName:"li"},"slashFactor"),";"),(0,a.kt)("li",{parentName:"ol"},"slash all delegations using as voting ",(0,a.kt)("inlineCode",{parentName:"li"},"power")," the sum of the voting power of the misbehaving validator and the power of all the ongoing undelegations and redelegations.")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Evidence expiration:")," Additionally, because we cannot infer the actual time of the evidence (i.e., the timestamp of the evidence cannot be trusted), we do not consider ",(0,a.kt)("em",{parentName:"p"},"evidence expiration")," and hence old evidence is never ignored (e.g., the provider would act on 3 year-old evidence of equivocation on a consumer).\nAdditionally, we do not need to store equivocation evidence to avoid slashing a validator more than once, because we ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L94"},"do not slash")," tombstoned validators and we ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L138"},"tombstone")," a validator when slashed."),(0,a.kt)("p",null,"We do not act on evidence that was signed by a validator ",(0,a.kt)("a",{parentName:"p",href:"https://tutorials.cosmos.network/tutorials/9-path-to-prod/3-keys.html#what-validator-keys"},"consensus key")," that is ",(0,a.kt)("em",{parentName:"p"},"pruned")," when we receive the evidence. We prune a validator's consensus key if the validator has assigned a new consumer key (using ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey"),") and an unbonding period on the consumer chain has elapsed (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-001-key-assignment.md"},"key assignment ADR"),"). Note that the provider chain is informed that the unbonding period has elapsed on the consumer when the provider receives a ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCMaturedPacket")," and because of this, if the consumer delays the sending of a ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCMaturedPacket"),", we would delay the pruning of the key as well."),(0,a.kt)("h3",{id:"implementation"},"Implementation"),(0,a.kt)("p",null,"The following logic needs to be added to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232"},"HandleConsumerDoubleVoting")," and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/826"},"HandleConsumerMisbehaviour")," methods:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-go"},"undelegationsInTokens := sdk.NewInt(0)\nfor _, v := range k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validatorAddress) {\n for _, entry := range v.Entries {\n if entry.IsMature(now) && !entry.OnHold() {\n // undelegation no longer eligible for slashing, skip it\n continue\n }\n undelegationsInTokens = undelegationsInTokens.Add(entry.InitialBalance)\n }\n}\n\nredelegationsInTokens := sdk.NewInt(0)\nfor _, v := range k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validatorAddress) {\n for _, entry := range v.Entries {\n if entry.IsMature(now) && !entry.OnHold() {\n // redelegation no longer eligible for slashing, skip it\n continue\n }\n redelegationsInTokens = redelegationsInTokens.Add(entry.InitialBalance)\n }\n}\n\ninfractionHeight := 0\nundelegationsAndRedelegationsInPower = sdk.TokensToConsensusPower(undelegationsInTokens.Add(redelegationsInTokens))\ntotalPower := validator's voting power + undelegationsAndRedelegationsInPower\nslashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)\n\nk.stakingKeeper.Slash(ctx, validatorConsAddress, infractionHeight, totalPower, slashFraction, DoubleSign)\n")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Infraction height:")," We provide a zero ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L33"},"Slash")," method in order to slash all ongoing undelegations and redelegations (see checks in ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L92"},"Slash"),", ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L195"},"SlashUnbondingDelegation"),", and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L249"},"SlashRedelegation"),")."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Power:")," We pass the sum of the voting power of the misbehaving validator when the evidence was received (i.e., at evidence height) and the power of all the ongoing undelegations and redelegations.\nIf we assume that the ",(0,a.kt)("inlineCode",{parentName:"p"},"slashFactor")," is ",(0,a.kt)("inlineCode",{parentName:"p"},"5%"),", then the voting power we pass is ",(0,a.kt)("inlineCode",{parentName:"p"},"power + totalPower(undelegations) + totalPower(redelegations)"),".\nHence, when the ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash")," method slashes all the undelegations and redelegations it would end up with ",(0,a.kt)("inlineCode",{parentName:"p"},"0.05 * power + 0.05 * totalPower(undelegations) + 0.05 * totalPower(redelegations) - 0.05 * totalPower(undelegations) - 0.05 * totalPower(redelegations) = 0.05 * power")," and hence it would slash ",(0,a.kt)("inlineCode",{parentName:"p"},"5%")," of the validator's power when the evidence is received."),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("p",null,"With the proposed approach we can quickly implement slashing functionality on the provider chain for consumer chain equivocations.\nThis approach does not need to change the staking module and therefore does not change in any way how slashing is performed today for a single chain."),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"We ",(0,a.kt)("em",{parentName:"li"},"definitely")," slash more when it comes to undelegations and redelegations because we slash for all of them without considering an ",(0,a.kt)("inlineCode",{parentName:"li"},"infractionHeight"),"."),(0,a.kt)("li",{parentName:"ul"},"We ",(0,a.kt)("em",{parentName:"li"},"potentially")," slash more than what we would have slashed if we knew the voting ",(0,a.kt)("inlineCode",{parentName:"li"},"power")," at the corresponding ",(0,a.kt)("inlineCode",{parentName:"li"},"infractionHeight")," in the provider chain."),(0,a.kt)("li",{parentName:"ul"},"We slash on old evidence of equivocation on a consumer.")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md"},"ADR 005: Cryptographic verification of equivocation evidence")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/732"},"EPIC tracking cryptographic equivocation feature")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://forum.cosmos.network/t/cryptographic-equivocation-slashing-design/11400"},"Cosmos Hub Forum discussion on cryptographic equivocation slashing"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/220c87fe.3606b286.js b/legacy/assets/js/220c87fe.3606b286.js new file mode 100644 index 0000000000..22b505e682 --- /dev/null +++ b/legacy/assets/js/220c87fe.3606b286.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5627],{3905:(e,n,t)=>{t.d(n,{Zo:()=>c,kt:()=>h});var r=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,r,o=function(e,n){if(null==e)return{};var t,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=r.createContext({}),p=function(e){var n=r.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},c=function(e){var n=p(e.components);return r.createElement(l.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=p(t),m=o,h=d["".concat(l,".").concat(m)]||d[m]||u[m]||a;return t?r.createElement(h,i(i({ref:n},c),{},{components:t})):r.createElement(h,i({ref:n},c))}));function h(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=m;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:o,i[1]=s;for(var p=2;p<a;p++)i[p]=t[p];return r.createElement.apply(null,i)}return r.createElement.apply(null,t)}m.displayName="MDXCreateElement"},4616:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>s,toc:()=>p});var r=t(7462),o=(t(7294),t(3905));const a={sidebar_position:3},i="ICS Provider Proposals",s={unversionedId:"features/proposals",id:"version-v3.3.1-lsm/features/proposals",title:"ICS Provider Proposals",description:"Interchain security module introduces 3 new proposal types to the provider.",source:"@site/versioned_docs/version-v3.3.1-lsm/features/proposals.md",sourceDirName:"features",slug:"/features/proposals",permalink:"/interchain-security/legacy/features/proposals",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Reward distribution",permalink:"/interchain-security/legacy/features/reward-distribution"},next:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/legacy/features/slashing"}},l={},p=[{value:"<code>ConsumerAdditionProposal</code>",id:"consumeradditionproposal",level:2},{value:"<code>ConsumerRemovalProposal</code>",id:"consumerremovalproposal",level:2},{value:"ChangeRewardDenomProposal",id:"changerewarddenomproposal",level:2}],c={toc:p},d="wrapper";function u(e){let{components:n,...t}=e;return(0,o.kt)(d,(0,r.Z)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"ics-provider-proposals"},"ICS Provider Proposals"),(0,o.kt)("p",null,"Interchain security module introduces 3 new proposal types to the provider."),(0,o.kt)("p",null,"The proposals are used to propose upcoming interchain security events through governance."),(0,o.kt)("h2",{id:"consumeradditionproposal"},(0,o.kt)("inlineCode",{parentName:"h2"},"ConsumerAdditionProposal")),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"If you are preparing a ",(0,o.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," you can find more information in the ",(0,o.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/onboarding"},"consumer onboarding checklist"),".")),(0,o.kt)("p",null,"Proposal type used to suggest adding a new consumer chain."),(0,o.kt)("p",null,"When proposals of this type are passed and the ",(0,o.kt)("inlineCode",{parentName:"p"},"spawn_time")," specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain."),(0,o.kt)("p",null,"Minimal example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'{\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n "title": "Add consumer chain",\n "description": ".md description of your chain and all other relevant information",\n "chain_id": "newchain-1",\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Unbonding period for the consumer chain.\n // It should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n "transfer_timeout_period": 1800000000000,\n "consumer_redistribution_fraction": "0.75",\n "blocks_per_distribution_transmission": 1000,\n "historical_entries": 10000,\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1"\n // relevant for chains performing a sovereign to consumer changeover\n // in order to maintain the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123"\n}\n')),(0,o.kt)("p",null,"More examples can be found in the replicated security testnet repository ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/stopped/baryon-1/proposal-baryon-1.json"},"here")," and ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/stopped/noble-1/start-proposal-noble-1.json"},"here"),"."),(0,o.kt)("h2",{id:"consumerremovalproposal"},(0,o.kt)("inlineCode",{parentName:"h2"},"ConsumerRemovalProposal")),(0,o.kt)("p",null,"Proposal type used to suggest removing an existing consumer chain."),(0,o.kt)("p",null,"When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain.\nAfter the consumer chain removal, the chain in question will no longer be secured by the provider's validator set."),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain.\nAdditional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set.\nMore information will be made available in the ",(0,o.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/offboarding"},"Consumer Offboarding Checklist"),".")),(0,o.kt)("p",null,"Minimal example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'{\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details"\n}\n')),(0,o.kt)("h2",{id:"changerewarddenomproposal"},"ChangeRewardDenomProposal"),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"ChangeRewardDenomProposal")," will only be accepted on the provider chain if at least one of the denomsToAdd or denomsToRemove fields is populated with at least one denom. Also, a denom cannot be repeated in both sets.")),(0,o.kt)("p",null,"Proposal type used to mutate the set of denoms accepted by the provider as rewards."),(0,o.kt)("p",null,"Minimal example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'{\n "title": "Add untrn as a reward denom",\n "description": "Here is more information about the proposal",\n "denomsToAdd": ["untrn"],\n "denomsToRemove": []\n}\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/22c24bfe.f284dc6c.js b/legacy/assets/js/22c24bfe.f284dc6c.js new file mode 100644 index 0000000000..5d3ad31c40 --- /dev/null +++ b/legacy/assets/js/22c24bfe.f284dc6c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2813],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function c(e,t){if(null==e)return{};var n,o,r=function(e,t){if(null==e)return{};var n,o,r={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=o.createContext({}),l=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},d=function(e){var t=l(e.components);return o.createElement(s.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=c(e,["components","mdxType","originalType","parentName"]),p=l(n),h=r,m=p["".concat(s,".").concat(h)]||p[h]||u[h]||i;return n?o.createElement(m,a(a({ref:t},d),{},{components:n})):o.createElement(m,a({ref:t},d))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=h;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[p]="string"==typeof e?e:r,a[1]=c;for(var l=2;l<i;l++)a[l]=n[l];return o.createElement.apply(null,a)}return o.createElement.apply(null,n)}h.displayName="MDXCreateElement"},1658:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>u,frontMatter:()=>i,metadata:()=>c,toc:()=>l});var o=n(7462),r=(n(7294),n(3905));const i={sidebar_position:1},a="Overview",c={unversionedId:"introduction/overview",id:"version-v3.3.0/introduction/overview",title:"Overview",description:"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.",source:"@site/versioned_docs/version-v3.3.0/introduction/overview.md",sourceDirName:"introduction",slug:"/introduction/overview",permalink:"/interchain-security/legacy/v3.3.0/introduction/overview",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Docs",permalink:"/interchain-security/legacy/v3.3.0/"},next:{title:"Terminology",permalink:"/interchain-security/legacy/v3.3.0/introduction/terminology"}},s={},l=[{value:"Why Replicated Security?",id:"why-replicated-security",level:2},{value:"Core protocol",id:"core-protocol",level:2},{value:"Downtime Slashing",id:"downtime-slashing",level:3},{value:"Tokenomics and Rewards",id:"tokenomics-and-rewards",level:3}],d={toc:l},p="wrapper";function u(e){let{components:t,...n}=e;return(0,r.kt)(p,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"overview"},"Overview"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another."),(0,r.kt)("br",null),'Replicated security allows anyone to launch a "consumer" blockchain using the same validator set as the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit the full security and decentralization of the provider.'),(0,r.kt)("h2",{id:"why-replicated-security"},"Why Replicated Security?"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Full provider security. At launch, consumer chains are secured by the full validator set and market cap of the provider chain."),(0,r.kt)("li",{parentName:"ul"},"Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum."),(0,r.kt)("li",{parentName:"ul"},"Projects keep majority of gas fees. Depending on configuration, these fees either go to the project\u2019s community DAO, or can be used in the protocol in other ways."),(0,r.kt)("li",{parentName:"ul"},"No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. A governance vote will take place for a chain to get adopted by the provider validators which will encourage participation and signal strong buy-in into the project's long-term success."),(0,r.kt)("li",{parentName:"ul"},"Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set.")),(0,r.kt)("h2",{id:"core-protocol"},"Core protocol"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Protocol specification is available as ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md"},"ICS-028")," in the IBC repository.")),(0,r.kt)("p",null,"Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer."),(0,r.kt)("p",null,"To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider."),(0,r.kt)("h3",{id:"downtime-slashing"},"Downtime Slashing"),(0,r.kt)("p",null,"If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period."),(0,r.kt)("h3",{id:"tokenomics-and-rewards"},"Tokenomics and Rewards"),(0,r.kt)("p",null,"Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/25dc14a6.52fe37dc.js b/legacy/assets/js/25dc14a6.52fe37dc.js new file mode 100644 index 0000000000..294aac7349 --- /dev/null +++ b/legacy/assets/js/25dc14a6.52fe37dc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7646],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>m});var i=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,i,r=function(e,t){if(null==e)return{};var n,i,r={},a=Object.keys(e);for(i=0;i<a.length;i++)n=a[i],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i<a.length;i++)n=a[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=i.createContext({}),l=function(e){var t=i.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=l(e.components);return i.createElement(c.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},h=i.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=l(n),h=r,m=d["".concat(c,".").concat(h)]||d[h]||p[h]||a;return n?i.createElement(m,o(o({ref:t},u),{},{components:n})):i.createElement(m,o({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,o=new Array(a);o[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var l=2;l<a;l++)o[l]=n[l];return i.createElement.apply(null,o)}return i.createElement.apply(null,n)}h.displayName="MDXCreateElement"},3315:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>p,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var i=n(7462),r=(n(7294),n(3905));const a={sidebar_position:4},o="Consumer Initiated Slashing",s={unversionedId:"features/slashing",id:"version-v2.4.0-lsm/features/slashing",title:"Consumer Initiated Slashing",description:"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.",source:"@site/versioned_docs/version-v2.4.0-lsm/features/slashing.md",sourceDirName:"features",slug:"/features/slashing",permalink:"/interchain-security/legacy/v2.4.0-lsm/features/slashing",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"ICS Provider Proposals",permalink:"/interchain-security/legacy/v2.4.0-lsm/features/proposals"},next:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/app-integration"}},c={},l=[{value:"Downtime infractions",id:"downtime-infractions",level:2}],u={toc:l},d="wrapper";function p(e){let{components:t,...n}=e;return(0,r.kt)(d,(0,i.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"consumer-initiated-slashing"},"Consumer Initiated Slashing"),(0,r.kt)("p",null,"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.\nIn essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake)."),(0,r.kt)("p",null,"To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized.\nAny infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains."),(0,r.kt)("p",null,"In the current implementation there are 2 important changes brought by the interchain security module:"),(0,r.kt)("h2",{id:"downtime-infractions"},"Downtime infractions"),(0,r.kt)("p",null,"reported by consumer chains are acted upon on the provider as soon as the provider receives the infraction evidence."),(0,r.kt)("p",null,"Instead of slashing, the provider will only jail offending validator for the duration of time established in the chain parameters."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Slash throttling (sometimes called jail throttling) mechanism ensures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider.")),(0,r.kt)("h1",{id:"cryptographic-verification-of-equivocation-and-slashing"},"Cryptographic verification of equivocation and slashing"),(0,r.kt)("p",null,"The Cryptographic verification of equivocation allows external agents to submit evidences of light client and double signing attack observed on a consumer chain. When a valid evidence is received, the malicious validators will be slashed, jailed, and tombstoned on the provider."),(0,r.kt)("p",null,"The feature is outlined in ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verification"},"ADR-005")," and ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-013-equivocation-slashing"},"ADR-013"),"."),(0,r.kt)("p",null,"By sending a ",(0,r.kt)("inlineCode",{parentName:"p"},"MsgSubmitConsumerMisbehaviour")," or a ",(0,r.kt)("inlineCode",{parentName:"p"},"MsgSubmitConsumerDoubleVoting")," transaction, the provider will\nverify the reported equivocation and, if successful, slash, jail, and tombstone the malicious validator."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/27d4dd38.4cac5e7f.js b/legacy/assets/js/27d4dd38.4cac5e7f.js new file mode 100644 index 0000000000..e5f427b7ee --- /dev/null +++ b/legacy/assets/js/27d4dd38.4cac5e7f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7209],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>m});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?c(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):c(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function a(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},c=Object.keys(e);for(r=0;r<c.length;r++)n=c[r],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(r=0;r<c.length;r++)n=c[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},l=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,c=e.originalType,s=e.parentName,l=a(e,["components","mdxType","originalType","parentName"]),u=p(n),d=i,m=u["".concat(s,".").concat(d)]||u[d]||f[d]||c;return n?r.createElement(m,o(o({ref:t},l),{},{components:n})):r.createElement(m,o({ref:t},l))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var c=n.length,o=new Array(c);o[0]=d;var a={};for(var s in t)hasOwnProperty.call(t,s)&&(a[s]=t[s]);a.originalType=e,a[u]="string"==typeof e?e:i,o[1]=a;for(var p=2;p<c;p++)o[p]=n[p];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},4396:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>f,frontMatter:()=>c,metadata:()=>a,toc:()=>p});var r=n(7462),i=(n(7294),n(3905));const c={sidebar_position:4},o="Technical Specification",a={unversionedId:"introduction/technical-specification",id:"version-v3.3.1-lsm/introduction/technical-specification",title:"Technical Specification",description:"For a technical deep dive into the replicated security protocol, see the specification.",source:"@site/versioned_docs/version-v3.3.1-lsm/introduction/technical-specification.md",sourceDirName:"introduction",slug:"/introduction/technical-specification",permalink:"/interchain-security/legacy/introduction/technical-specification",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Parameters",permalink:"/interchain-security/legacy/introduction/params"},next:{title:"Key Assignment",permalink:"/interchain-security/legacy/features/key-assignment"}},s={},p=[],l={toc:p},u="wrapper";function f(e){let{components:t,...n}=e;return(0,i.kt)(u,(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"technical-specification"},"Technical Specification"),(0,i.kt)("p",null,"For a technical deep dive into the replicated security protocol, see the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/README.md"},"specification"),"."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/29f8b3e7.1d3ce1e7.js b/legacy/assets/js/29f8b3e7.1d3ce1e7.js new file mode 100644 index 0000000000..a8919bee13 --- /dev/null +++ b/legacy/assets/js/29f8b3e7.1d3ce1e7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3986],{3905:(e,r,t)=>{t.d(r,{Zo:()=>c,kt:()=>w});var n=t(7294);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function o(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?i(Object(t),!0).forEach((function(r){a(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function s(e,r){if(null==e)return{};var t,n,a=function(e,r){if(null==e)return{};var t,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=n.createContext({}),d=function(e){var r=n.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):o(o({},r),e)),t},c=function(e){var r=d(e.components);return n.createElement(l.Provider,{value:r},e.children)},m="mdxType",p={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},u=n.forwardRef((function(e,r){var t=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),m=d(t),u=a,w=m["".concat(l,".").concat(u)]||m[u]||p[u]||i;return t?n.createElement(w,o(o({ref:r},c),{},{components:t})):n.createElement(w,o({ref:r},c))}));function w(e,r){var t=arguments,a=r&&r.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=u;var s={};for(var l in r)hasOwnProperty.call(r,l)&&(s[l]=r[l]);s.originalType=e,s[m]="string"==typeof e?e:a,o[1]=s;for(var d=2;d<i;d++)o[d]=t[d];return n.createElement.apply(null,o)}return n.createElement.apply(null,t)}u.displayName="MDXCreateElement"},9896:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>d});var n=t(7462),a=(t(7294),t(3905));const i={},o="Withdrawing consumer chain validator rewards",s={unversionedId:"validators/withdraw_rewards",id:"version-v2.4.0-lsm/validators/withdraw_rewards",title:"Withdrawing consumer chain validator rewards",description:"Here are example steps for withdrawing rewards from consumer chains in the provider chain",source:"@site/versioned_docs/version-v2.4.0-lsm/validators/withdraw_rewards.md",sourceDirName:"validators",slug:"/validators/withdraw_rewards",permalink:"/interchain-security/legacy/v2.4.0-lsm/validators/withdraw_rewards",draft:!1,tags:[],version:"v2.4.0-lsm",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Joining Replicated Security testnet",permalink:"/interchain-security/legacy/v2.4.0-lsm/validators/joining-testnet"},next:{title:"Frequently Asked Questions",permalink:"/interchain-security/legacy/v2.4.0-lsm/faq"}},l={},d=[{value:"Querying validator rewards",id:"querying-validator-rewards",level:2},{value:"Withdrawing rewards and commission",id:"withdrawing-rewards-and-commission",level:2},{value:"1. Withdraw rewards",id:"1-withdraw-rewards",level:3},{value:"2. Confirm withdrawal",id:"2-confirm-withdrawal",level:3}],c={toc:d},m="wrapper";function p(e){let{components:r,...t}=e;return(0,a.kt)(m,(0,n.Z)({},c,t,{components:r,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"withdrawing-consumer-chain-validator-rewards"},"Withdrawing consumer chain validator rewards"),(0,a.kt)("p",null,"Here are example steps for withdrawing rewards from consumer chains in the provider chain"),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The examples used are from ",(0,a.kt)("inlineCode",{parentName:"p"},"rs-testnet"),", the replicated security persistent testnet."),(0,a.kt)("p",{parentName:"admonition"},"Validator operator address: ",(0,a.kt)("inlineCode",{parentName:"p"},"cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6"),"\nSelf-delegation address: ",(0,a.kt)("inlineCode",{parentName:"p"},"cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf"))),(0,a.kt)("p",null,"Prior to withdrawing rewards, query balances for self-delegation address:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "1000000000000"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n')),(0,a.kt)("h2",{id:"querying-validator-rewards"},"Querying validator rewards"),(0,a.kt)("p",null,"Query rewards for the validator address:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6\n\nrewards:\n- amount: "158.069895000000000000"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "841842390516.072526500000000000"\n denom: uatom\n')),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD")," denom represents rewards from a consumer chain."),(0,a.kt)("h2",{id:"withdrawing-rewards-and-commission"},"Withdrawing rewards and commission"),(0,a.kt)("h3",{id:"1-withdraw-rewards"},"1. Withdraw rewards"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y\n\ntxhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A\n")),(0,a.kt)("h3",{id:"2-confirm-withdrawal"},"2. Confirm withdrawal"),(0,a.kt)("p",null,"After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "216"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "2233766225342"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n')))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/2b87464d.2ca9d156.js b/legacy/assets/js/2b87464d.2ca9d156.js new file mode 100644 index 0000000000..3e672e9db9 --- /dev/null +++ b/legacy/assets/js/2b87464d.2ca9d156.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4868],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function c(e,t){if(null==e)return{};var n,o,r=function(e,t){if(null==e)return{};var n,o,r={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=o.createContext({}),l=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},d=function(e){var t=l(e.components);return o.createElement(s.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=c(e,["components","mdxType","originalType","parentName"]),p=l(n),h=r,m=p["".concat(s,".").concat(h)]||p[h]||u[h]||i;return n?o.createElement(m,a(a({ref:t},d),{},{components:n})):o.createElement(m,a({ref:t},d))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=h;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[p]="string"==typeof e?e:r,a[1]=c;for(var l=2;l<i;l++)a[l]=n[l];return o.createElement.apply(null,a)}return o.createElement.apply(null,n)}h.displayName="MDXCreateElement"},2175:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>u,frontMatter:()=>i,metadata:()=>c,toc:()=>l});var o=n(7462),r=(n(7294),n(3905));const i={sidebar_position:1},a="Overview",c={unversionedId:"introduction/overview",id:"version-v3.3.1-lsm/introduction/overview",title:"Overview",description:"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.",source:"@site/versioned_docs/version-v3.3.1-lsm/introduction/overview.md",sourceDirName:"introduction",slug:"/introduction/overview",permalink:"/interchain-security/legacy/introduction/overview",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Docs",permalink:"/interchain-security/legacy/"},next:{title:"Terminology",permalink:"/interchain-security/legacy/introduction/terminology"}},s={},l=[{value:"Why Replicated Security?",id:"why-replicated-security",level:2},{value:"Core protocol",id:"core-protocol",level:2},{value:"Downtime Slashing",id:"downtime-slashing",level:3},{value:"Tokenomics and Rewards",id:"tokenomics-and-rewards",level:3}],d={toc:l},p="wrapper";function u(e){let{components:t,...n}=e;return(0,r.kt)(p,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"overview"},"Overview"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another."),(0,r.kt)("br",null),'Replicated security allows anyone to launch a "consumer" blockchain using the same validator set as the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit the full security and decentralization of the provider.'),(0,r.kt)("h2",{id:"why-replicated-security"},"Why Replicated Security?"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Full provider security. At launch, consumer chains are secured by the full validator set and market cap of the provider chain."),(0,r.kt)("li",{parentName:"ul"},"Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum."),(0,r.kt)("li",{parentName:"ul"},"Projects keep majority of gas fees. Depending on configuration, these fees either go to the project\u2019s community DAO, or can be used in the protocol in other ways."),(0,r.kt)("li",{parentName:"ul"},"No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. A governance vote will take place for a chain to get adopted by the provider validators which will encourage participation and signal strong buy-in into the project's long-term success."),(0,r.kt)("li",{parentName:"ul"},"Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set.")),(0,r.kt)("h2",{id:"core-protocol"},"Core protocol"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Protocol specification is available as ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md"},"ICS-028")," in the IBC repository.")),(0,r.kt)("p",null,"Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer."),(0,r.kt)("p",null,"To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider."),(0,r.kt)("h3",{id:"downtime-slashing"},"Downtime Slashing"),(0,r.kt)("p",null,"If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period."),(0,r.kt)("h3",{id:"tokenomics-and-rewards"},"Tokenomics and Rewards"),(0,r.kt)("p",null,"Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/2c7ea566.795b742d.js b/legacy/assets/js/2c7ea566.795b742d.js new file mode 100644 index 0000000000..1a93c7d696 --- /dev/null +++ b/legacy/assets/js/2c7ea566.795b742d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9124],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var i=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,i,r=function(e,t){if(null==e)return{};var n,i,r={},o=Object.keys(e);for(i=0;i<o.length;i++)n=o[i],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i<o.length;i++)n=o[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=i.createContext({}),d=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=d(e.components);return i.createElement(l.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},u=i.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),c=d(n),u=r,h=c["".concat(l,".").concat(u)]||c[u]||m[u]||o;return n?i.createElement(h,a(a({ref:t},p),{},{components:n})):i.createElement(h,a({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,a=new Array(o);a[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:r,a[1]=s;for(var d=2;d<o;d++)a[d]=n[d];return i.createElement.apply(null,a)}return i.createElement.apply(null,n)}u.displayName="MDXCreateElement"},9374:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>m,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var i=n(7462),r=(n(7294),n(3905));const o={sidebar_position:3},a="Interchain Security Parameters",s={unversionedId:"introduction/params",id:"version-v3.3.1-lsm/introduction/params",title:"Interchain Security Parameters",description:"The parameters necessary for Interchain Security (ICS) are defined in",source:"@site/versioned_docs/version-v3.3.1-lsm/introduction/params.md",sourceDirName:"introduction",slug:"/introduction/params",permalink:"/interchain-security/legacy/introduction/params",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Terminology",permalink:"/interchain-security/legacy/introduction/terminology"},next:{title:"Technical Specification",permalink:"/interchain-security/legacy/introduction/technical-specification"}},l={},d=[{value:"Time-based parameters",id:"time-based-parameters",level:2},{value:"ProviderUnbondingPeriod",id:"providerunbondingperiod",level:3},{value:"ConsumerUnbondingPeriod",id:"consumerunbondingperiod",level:3},{value:"TrustingPeriodFraction",id:"trustingperiodfraction",level:3},{value:"CCVTimeoutPeriod",id:"ccvtimeoutperiod",level:3},{value:"InitTimeoutPeriod",id:"inittimeoutperiod",level:3},{value:"VscTimeoutPeriod",id:"vsctimeoutperiod",level:3},{value:"BlocksPerDistributionTransmission",id:"blocksperdistributiontransmission",level:3},{value:"TransferPeriodTimeout",id:"transferperiodtimeout",level:3},{value:"Slash Throttle Parameters",id:"slash-throttle-parameters",level:2},{value:"SlashMeterReplenishPeriod",id:"slashmeterreplenishperiod",level:3},{value:"SlashMeterReplenishFraction",id:"slashmeterreplenishfraction",level:3},{value:"MaxThrottledPackets",id:"maxthrottledpackets",level:3},{value:"RetryDelayPeriod",id:"retrydelayperiod",level:3}],p={toc:d},c="wrapper";function m(e){let{components:t,...n}=e;return(0,r.kt)(c,(0,i.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"interchain-security-parameters"},"Interchain Security Parameters"),(0,r.kt)("p",null,"The parameters necessary for Interchain Security (ICS) are defined in "),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"the ",(0,r.kt)("inlineCode",{parentName:"li"},"Params")," structure in ",(0,r.kt)("inlineCode",{parentName:"li"},"proto/interchain_security/ccv/provider/v1/provider.proto")," for the provider;"),(0,r.kt)("li",{parentName:"ul"},"the ",(0,r.kt)("inlineCode",{parentName:"li"},"Params")," structure in ",(0,r.kt)("inlineCode",{parentName:"li"},"proto/interchain_security/ccv/consumer/v1/consumer.proto")," for the consumer.")),(0,r.kt)("h2",{id:"time-based-parameters"},"Time-based parameters"),(0,r.kt)("p",null,"ICS relies on the following time-based parameters."),(0,r.kt)("h3",{id:"providerunbondingperiod"},"ProviderUnbondingPeriod"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"ProviderUnbondingPeriod")," is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance."),(0,r.kt)("h3",{id:"consumerunbondingperiod"},"ConsumerUnbondingPeriod"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerUnbondingPeriod")," is the unbonding period on the consumer chain."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerUnbondingPeriod")," is set via the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," governance proposal to add a new consumer chain.\nIt is recommended that every consumer chain set and unbonding period shorter than ",(0,r.kt)("inlineCode",{parentName:"p"},"ProviderUnbondingPeriod")),(0,r.kt)("br",null),(0,r.kt)("p",{parentName:"admonition"},"Example:"),(0,r.kt)("pre",{parentName:"admonition"},(0,r.kt)("code",{parentName:"pre"},"ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day\n"))),(0,r.kt)("p",null,"Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer."),(0,r.kt)("h3",{id:"trustingperiodfraction"},"TrustingPeriodFraction"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriodFraction")," is used to calculate the ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriod")," of created IBC clients on both provider and consumer chains. "),(0,r.kt)("p",null,"Setting ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriodFraction")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"0.5")," would result in the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"TrustingPeriodFraction = 0.5\nProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5\nConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5\n")),(0,r.kt)("p",null,"Note that a light clients must be updated within the ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriod")," in order to avoid being frozen."),(0,r.kt)("p",null,"For more details, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/client/ics-007-tendermint-client/README.md"},"IBC specification of Tendermint clients"),"."),(0,r.kt)("h3",{id:"ccvtimeoutperiod"},"CCVTimeoutPeriod"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"CCVTimeoutPeriod")," is the period used to compute the timeout timestamp when sending IBC packets. "),(0,r.kt)("p",null,"For more details, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/core/ics-004-channel-and-packet-semantics/README.md#sending-packets"},"IBC specification of Channel & Packet Semantics"),"."),(0,r.kt)("admonition",{type:"warning"},(0,r.kt)("p",{parentName:"admonition"},"If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed.")),(0,r.kt)("p",null,"CCVTimeoutPeriod may have different values on the provider and consumer chains."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"CCVTimeoutPeriod")," on the provider ",(0,r.kt)("strong",{parentName:"li"},"must")," be larger than ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerUnbondingPeriod")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"CCVTimeoutPeriod")," on the consumer is initial set via the ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal"))),(0,r.kt)("h3",{id:"inittimeoutperiod"},"InitTimeoutPeriod"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"InitTimeoutPeriod")," is the maximum allowed duration for CCV channel initialization to execute."),(0,r.kt)("p",null,"For any consumer chain, if the CCV channel is not established within ",(0,r.kt)("inlineCode",{parentName:"p"},"InitTimeoutPeriod")," then the consumer chain will be removed and therefore will not be secured by the provider chain."),(0,r.kt)("p",null,"The countdown starts when the ",(0,r.kt)("inlineCode",{parentName:"p"},"spawn_time")," specified in the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," is reached."),(0,r.kt)("h3",{id:"vsctimeoutperiod"},"VscTimeoutPeriod"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"VscTimeoutPeriod")," is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live.\nIf the ",(0,r.kt)("inlineCode",{parentName:"p"},"VscTimeoutPeriod")," is ever reached for a consumer chain that chain will be considered not live and removed from interchain security."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"VscTimeoutPeriod")," MUST be larger than the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerUnbondingPeriod"),".")),(0,r.kt)("h3",{id:"blocksperdistributiontransmission"},"BlocksPerDistributionTransmission"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"BlocksPerDistributionTransmission")," is the number of blocks between rewards transfers from the consumer to the provider."),(0,r.kt)("h3",{id:"transferperiodtimeout"},"TransferPeriodTimeout"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"TransferPeriodTimeout")," is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider."),(0,r.kt)("p",null,"If this timeout expires, then the transfer is attempted again after ",(0,r.kt)("inlineCode",{parentName:"p"},"BlocksPerDistributionTransmission")," blocks."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"TransferPeriodTimeout")," on the consumer is initial set via the ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal")," gov proposal to add the consumer"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"TransferPeriodTimeout")," should be smaller than ",(0,r.kt)("inlineCode",{parentName:"li"},"BlocksPerDistributionTransmission x avg_block_time"))),(0,r.kt)("h2",{id:"slash-throttle-parameters"},"Slash Throttle Parameters"),(0,r.kt)("h3",{id:"slashmeterreplenishperiod"},"SlashMeterReplenishPeriod"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishPeriod")," exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed."),(0,r.kt)("p",null,"The meter is replenished to an amount equal to the slash meter allowance for that block, or ",(0,r.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction * CurrentTotalVotingPower"),"."),(0,r.kt)("h3",{id:"slashmeterreplenishfraction"},"SlashMeterReplenishFraction"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction")," exists on the provider as the portion (in range ","[0, 1]",") of total voting power that is replenished to the slash meter when a replenishment occurs."),(0,r.kt)("p",null,"This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a ",(0,r.kt)("inlineCode",{parentName:"p"},"sdk.Dec")," when used."),(0,r.kt)("h3",{id:"maxthrottledpackets"},"MaxThrottledPackets"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"MaxThrottledPackets")," exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value."),(0,r.kt)("p",null,"This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"MaxThrottledPackets")," was deprecated in ICS versions >= v3.2.0 due to the implementation of ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/adrs/adr-008-throttle-retries"},"ADR-008"),".")),(0,r.kt)("h3",{id:"retrydelayperiod"},"RetryDelayPeriod"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"RetryDelayPeriod")," exists on the consumer for ",(0,r.kt)("strong",{parentName:"p"},"ICS versions >= v3.2.0")," (introduced by the implementation of ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/adrs/adr-008-throttle-retries"},"ADR-008"),") and is the period at which the consumer retries to send a ",(0,r.kt)("inlineCode",{parentName:"p"},"SlashPacket")," that was rejected by the provider."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/2ce37f2a.dfc4924c.js b/legacy/assets/js/2ce37f2a.dfc4924c.js new file mode 100644 index 0000000000..d1f3c31fb4 --- /dev/null +++ b/legacy/assets/js/2ce37f2a.dfc4924c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2979],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>m});var i=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?r(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):r(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,i,a=function(e,n){if(null==e)return{};var t,i,a={},r=Object.keys(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=i.createContext({}),c=function(e){var n=i.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},p=function(e){var n=c(e.components);return i.createElement(l.Provider,{value:n},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},u=i.forwardRef((function(e,n){var t=e.components,a=e.mdxType,r=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(t),u=a,m=d["".concat(l,".").concat(u)]||d[u]||h[u]||r;return t?i.createElement(m,o(o({ref:n},p),{},{components:t})):i.createElement(m,o({ref:n},p))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var r=t.length,o=new Array(r);o[0]=u;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:a,o[1]=s;for(var c=2;c<r;c++)o[c]=t[c];return i.createElement.apply(null,o)}return i.createElement.apply(null,t)}u.displayName="MDXCreateElement"},5094:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>c});var i=t(7462),a=(t(7294),t(3905));const r={sidebar_position:1},o="Overview",s={unversionedId:"validators/overview",id:"version-v3.3.0/validators/overview",title:"Overview",description:"We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.",source:"@site/versioned_docs/version-v3.3.0/validators/overview.md",sourceDirName:"validators",slug:"/validators/overview",permalink:"/interchain-security/legacy/v3.3.0/validators/overview",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Consumer Genesis Transformation",permalink:"/interchain-security/legacy/v3.3.0/consumer-development/consumer-genesis-transformation"},next:{title:"Joining Replicated Security testnet",permalink:"/interchain-security/legacy/v3.3.0/validators/joining-testnet"}},l={},c=[{value:"Startup sequence overview",id:"startup-sequence-overview",level:2},{value:"1. Consumer Chain init + 2. Genesis generation",id:"1-consumer-chain-init--2-genesis-generation",level:3},{value:"3. Submit Proposal",id:"3-submit-proposal",level:3},{value:"4. CCV Genesis state generation",id:"4-ccv-genesis-state-generation",level:3},{value:"5. Updating the genesis file",id:"5-updating-the-genesis-file",level:3},{value:"6. Chain start",id:"6-chain-start",level:3},{value:"7. Creating IBC connections",id:"7-creating-ibc-connections",level:3},{value:"Downtime Infractions",id:"downtime-infractions",level:2},{value:"Double-signing Infractions",id:"double-signing-infractions",level:2},{value:"Key assignment",id:"key-assignment",level:2},{value:"References:",id:"references",level:2}],p={toc:c},d="wrapper";function h(e){let{components:n,...r}=e;return(0,a.kt)(d,(0,i.Z)({},p,r,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"overview"},"Overview"),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"We advise that you join the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security"},"Replicated Security testnet")," to gain hands-on experience with running consumer chains.")),(0,a.kt)("p",null,"At present, replicated security requires all validators of the provider chain (ie. Cosmos Hub) to run validator nodes for all governance-approved consumer chains."),(0,a.kt)("p",null,"Once a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," passes, validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains."),(0,a.kt)("p",null,"Provider chain and consumer chains represent standalone chains that only share the validator set ie. the same validator operators are tasked with running all chains."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 180 validators for Cosmos Hub).")),(0,a.kt)("h2",{id:"startup-sequence-overview"},"Startup sequence overview"),(0,a.kt)("p",null,"Consumer chains cannot start and be secured by the validator set of the provider unless a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," is passed.\nEach proposal contains defines a ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider."),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"Validators are required to run consumer chain binaries only after ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," has passed.")),(0,a.kt)("p",null,"Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains."),(0,a.kt)("p",null,"The image below illustrates the startup sequence\n",(0,a.kt)("img",{alt:"startup",src:t(7728).Z,width:"942",height:"632"})),(0,a.kt)("h3",{id:"1-consumer-chain-init--2-genesis-generation"},"1. Consumer Chain init + 2. Genesis generation"),(0,a.kt)("p",null,"Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")),(0,a.kt)("h3",{id:"3-submit-proposal"},"3. Submit Proposal"),(0,a.kt)("p",null,"Consumer chain team (or their advocates) submits a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal"),".\nThe most important parameters for validators are:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"spawn_time")," - the time after which the consumer chain must be started"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"genesis_hash")," - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and ",(0,a.kt)("inlineCode",{parentName:"li"},"spawn_time")," is reached"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"binary_hash")," - hash of the consumer chain binary used to validate the software builds")),(0,a.kt)("h3",{id:"4-ccv-genesis-state-generation"},"4. CCV Genesis state generation"),(0,a.kt)("p",null,"After reaching ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json"),". The CCV validator set consists of the validator set on the provider at ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time"),"."),(0,a.kt)("p",null,"The state can be queried on the provider chain (in this case the Cosmos Hub):"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json\n")),(0,a.kt)("p",null,"This is used by the launch coordinator to create the final ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," that will be distributed to validators in step 5."),(0,a.kt)("h3",{id:"5-updating-the-genesis-file"},"5. Updating the genesis file"),(0,a.kt)("p",null,"Upon reaching the ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," the initial validator set state will become available on the provider chain. The initial validator set is included in the ",(0,a.kt)("strong",{parentName:"p"},"final genesis.json")," of the consumer chain."),(0,a.kt)("h3",{id:"6-chain-start"},"6. Chain start"),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences.")),(0,a.kt)("p",null,"The new ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," to start their consumer chain node."),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"Please pay attention to any onboarding repositories provided by the consumer chain teams.\nRecommendations are available in ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/consumer-development/onboarding"},"Consumer Onboarding Checklist"),".\nAnother comprehensive guide is available in the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md"},"Replicated Security testnet repo"),".")),(0,a.kt)("h3",{id:"7-creating-ibc-connections"},"7. Creating IBC connections"),(0,a.kt)("p",null,"Finally, to fully establish replicated security an IBC relayer is used to establish connections and create the required channels."),(0,a.kt)("admonition",{type:"warning"},(0,a.kt)("p",{parentName:"admonition"},"The relayer can establish the connection only after the consumer chain starts producing blocks.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> \nhermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1\nhermes start\n")),(0,a.kt)("h2",{id:"downtime-infractions"},"Downtime Infractions"),(0,a.kt)("p",null,"At present, the consumer chain can report evidence about downtime infractions to the provider chain. The ",(0,a.kt)("inlineCode",{parentName:"p"},"min_signed_per_window")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"signed_blocks_window")," can be different on each consumer chain and are subject to changes via consumer chain governance."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains."),(0,a.kt)("p",{parentName:"admonition"},"To unjail, the validator must wait for the jailing period to elapse on the provider chain and ",(0,a.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html#unjail-validator"},"submit an unjail transaction")," on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains."),(0,a.kt)("p",{parentName:"admonition"},"More information is available in ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/features/slashing#downtime-infractions"},"Downtime Slashing documentation"))),(0,a.kt)("h2",{id:"double-signing-infractions"},"Double-signing Infractions"),(0,a.kt)("p",null,"To learn more about equivocation handling in replicated security check out the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/features/slashing"},"Slashing")," documentation section."),(0,a.kt)("h2",{id:"key-assignment"},"Key assignment"),(0,a.kt)("p",null,"Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use."),(0,a.kt)("p",null,"For more information check our the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/features/key-assignment"},"Key assignment overview and guide")),(0,a.kt)("h2",{id:"references"},"References:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-faq.html"},"Cosmos Hub Validators FAQ")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-setup.html"},"Cosmos Hub Running a validator")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md#chain-launch"},"Startup Sequence")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-setup.html#unjail-validator"},"Submit Unjailing Transaction"))))}h.isMDXComponent=!0},7728:(e,n,t)=>{t.d(n,{Z:()=>i});const i=t.p+"assets/images/hypha-consumer-start-process-2141109f76c584706dd994d7965fd692.svg"}}]); \ No newline at end of file diff --git a/legacy/assets/js/2cf1b2f2.5323a352.js b/legacy/assets/js/2cf1b2f2.5323a352.js new file mode 100644 index 0000000000..d77cbde870 --- /dev/null +++ b/legacy/assets/js/2cf1b2f2.5323a352.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9242],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>u});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(n),m=i,u=d["".concat(l,".").concat(m)]||d[m]||h[m]||o;return n?a.createElement(u,r(r({ref:t},p),{},{components:n})):a.createElement(u,r({ref:t},p))}));function u(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:i,r[1]=s;for(var c=2;c<o;c++)r[c]=n[c];return a.createElement.apply(null,r)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},8429:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var a=n(7462),i=(n(7294),n(3905));const o={sidebar_position:5},r="Changeover Procedure",s={unversionedId:"consumer-development/changeover-procedure",id:"version-v3.3.0/consumer-development/changeover-procedure",title:"Changeover Procedure",description:"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.",source:"@site/versioned_docs/version-v3.3.0/consumer-development/changeover-procedure.md",sourceDirName:"consumer-development",slug:"/consumer-development/changeover-procedure",permalink:"/interchain-security/legacy/v3.3.0/consumer-development/changeover-procedure",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Offboarding Checklist",permalink:"/interchain-security/legacy/v3.3.0/consumer-development/offboarding"},next:{title:"Consumer Genesis Transformation",permalink:"/interchain-security/legacy/v3.3.0/consumer-development/consumer-genesis-transformation"}},l={},c=[{value:"Overview",id:"overview",level:2},{value:"1. ConsumerAddition proposal submitted to the <code>provider</code> chain",id:"1-consumeraddition-proposal-submitted-to-the-provider-chain",level:3},{value:"2. upgrade proposal on standalone chain",id:"2-upgrade-proposal-on-standalone-chain",level:3},{value:"3. spawn time is reached",id:"3-spawn-time-is-reached",level:3},{value:"4. standalone chain upgrade",id:"4-standalone-chain-upgrade",level:3},{value:"Notes",id:"notes",level:4},{value:"Onboarding Checklist",id:"onboarding-checklist",level:2},{value:"1. Complete testing & integration",id:"1-complete-testing--integration",level:2},{value:"2. Create an Onboarding Repository",id:"2-create-an-onboarding-repository",level:2},{value:"3. Submit a ConsumerChainAddition Governance Proposal to the provider",id:"3-submit-a-consumerchainaddition-governance-proposal-to-the-provider",level:2},{value:"3. Submit an Upgrade Proposal & Prepare for Changeover",id:"3-submit-an-upgrade-proposal--prepare-for-changeover",level:2},{value:"4. Upgrade time \ud83d\ude80",id:"4-upgrade-time-",level:2}],p={toc:c},d="wrapper";function h(e){let{components:t,...n}=e;return(0,i.kt)(d,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"changeover-procedure"},"Changeover Procedure"),(0,i.kt)("p",null,"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the ",(0,i.kt)("strong",{parentName:"p"},"changeover procedure")," and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain."),(0,i.kt)("p",null,"The relevant protocol specifications are available below:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md#channel-initialization-existing-chains"},"ICS-28 with existing chains"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/interchain-security/legacy/v3.3.0/adrs/adr-010-standalone-changeover"},"ADR in ICS repo"))),(0,i.kt)("h2",{id:"overview"},"Overview"),(0,i.kt)("p",null,"Standalone to consumer changeover procedure can rougly be separated into 4 parts:"),(0,i.kt)("h3",{id:"1-consumeraddition-proposal-submitted-to-the-provider-chain"},"1. ConsumerAddition proposal submitted to the ",(0,i.kt)("inlineCode",{parentName:"h3"},"provider")," chain"),(0,i.kt)("p",null,'The proposal is equivalent to the "normal" ConsumerAddition proposal submitted by new consumer chains.'),(0,i.kt)("p",null,"However, here are the most important notes and differences between a new consumer chain and a standalone chain performing a changeover:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"chain_id")," must be equal to the standalone chain id"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"initial_height")," field has additional rules to abide by:")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre"},'{\n...\n "initial_height" : {\n // must correspond to current revision number of standalone chain\n // e.g. stride-1 => "revision_number": 1\n "revision_number": 1,\n\n // must correspond to a height that is at least 1 block after the upgrade\n // that will add the `consumer` module to the standalone chain\n // e.g. "upgrade_height": 100 => "revision_height": 101\n "revision_height": 1,\n },\n...\n}\n')),(0,i.kt)("p",{parentName:"admonition"},"RevisionNumber: 0, RevisionHeight: 111")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"genesis_hash")," can be safely ignored because the chain is already running. A hash of the standalone chain's initial genesis may be used")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"binary_hash")," may not be available ahead of time. All chains performing the changeover go through rigorous testing - if bugs are caught and fixed the hash listed in the proposal may not be the most recent one.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," listed in the proposal MUST be before the ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height")," listed in the the upgrade proposal on the standalone chain."),(0,i.kt)("admonition",{parentName:"li",type:"caution"},(0,i.kt)("p",{parentName:"admonition"},(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," must occur before the ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height")," on the standalone chain is reached because the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider")," chain must generate the ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerGenesis")," that contains the ",(0,i.kt)("strong",{parentName:"p"},"validator set")," that will be used after the changeover."))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"unbonding_period")," must correspond to the value used on the standalone chain. Otherwise, the clients used for the ccv protocol may be incorrectly initialized.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"distribution_transmission_channel")," ",(0,i.kt)("strong",{parentName:"p"},"should be set"),"."))),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"Populating ",(0,i.kt)("inlineCode",{parentName:"p"},"distribution_transmission_channel")," will enable the standalone chain to re-use one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ",(0,i.kt)("inlineCode",{parentName:"p"},"ibc denom")," that may already be in use."),(0,i.kt)("p",{parentName:"admonition"},"If the parameter is not set, a new channel will be created.")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"ccv_timeout_period")," has no important notes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"transfer_timeout_period")," has no important notes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction")," has no important notes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission")," has no important notes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"historical_entries")," has no important notes"))),(0,i.kt)("h3",{id:"2-upgrade-proposal-on-standalone-chain"},"2. upgrade proposal on standalone chain"),(0,i.kt)("p",null,"The standalone chain creates an upgrade proposal to include the ",(0,i.kt)("inlineCode",{parentName:"p"},"interchain-security/x/ccv/consumer")," module."),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"The upgrade height in the proposal should correspond to a height that is after the ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," in the consumer addition proposal submitted to the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider")," chain.")),(0,i.kt)("p",null,"Otherwise, the upgrade is indistinguishable from a regular on-chain upgrade proposal."),(0,i.kt)("h3",{id:"3-spawn-time-is-reached"},"3. spawn time is reached"),(0,i.kt)("p",null,"When the ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," is reached on the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider")," it will generate a ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerGenesis")," that contains the validator set that will supercede the ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," validator set."),(0,i.kt)("p",null,"This ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerGenesis")," must be available on the standalone chain during the on-chain upgrade."),(0,i.kt)("h3",{id:"4-standalone-chain-upgrade"},"4. standalone chain upgrade"),(0,i.kt)("p",null,"Performing the on-chain upgrade on the standalone chain will add the ",(0,i.kt)("inlineCode",{parentName:"p"},"ccv/consumer")," module and allow the chain to become a ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer")," of replicated security."),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerGenesis")," must be exported to a file and placed in the correct folder on the standalone chain before the upgade."),(0,i.kt)("p",{parentName:"admonition"},"The file must be placed at the exact specified location, otherwise the upgrade will not be executed correctly."),(0,i.kt)("p",{parentName:"admonition"},"Usually the file is placed in ",(0,i.kt)("inlineCode",{parentName:"p"},"$NODE_HOME/config"),", but the file name and the exact directory is dictated by the upgrade code on the ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," chain."),(0,i.kt)("ul",{parentName:"admonition"},(0,i.kt)("li",{parentName:"ul"},"please check exact instructions provided by the ",(0,i.kt)("inlineCode",{parentName:"li"},"standalone")," chain team"))),(0,i.kt)("p",null,"After the ",(0,i.kt)("inlineCode",{parentName:"p"},"genesis.json")," file has been made available, the process is equivalent to a normal on-chain upgrade. The standalone validator set will sign the next couple of blocks before transferring control to ",(0,i.kt)("inlineCode",{parentName:"p"},"provider")," validator set."),(0,i.kt)("p",null,"The standalone validator set can still be slashed for any infractions if evidence is submitted within the ",(0,i.kt)("inlineCode",{parentName:"p"},"unboding_period"),"."),(0,i.kt)("h4",{id:"notes"},"Notes"),(0,i.kt)("p",null,"The changeover procedure may be updated in the future to create a seamless way of providing the validator set information to the standalone chain."),(0,i.kt)("h2",{id:"onboarding-checklist"},"Onboarding Checklist"),(0,i.kt)("p",null,"This onboarding checklist is slightly different from the one under ",(0,i.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/consumer-development/onboarding"},"Onboarding")),(0,i.kt)("p",null,"Additionally, you can check the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md"},"testnet repo")," for a comprehensive guide on preparing and launching consumer chains."),(0,i.kt)("h2",{id:"1-complete-testing--integration"},"1. Complete testing & integration"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test integration with gaia"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test your protocol with supported relayer versions (minimum hermes 1.4.1)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test the changeover procedure"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","reach out to the ICS team if you are facing issues")),(0,i.kt)("h2",{id:"2-create-an-onboarding-repository"},"2. Create an Onboarding Repository"),(0,i.kt)("p",null,"To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain."),(0,i.kt)("p",null,"This should include (at minimum):"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see ",(0,i.kt)("a",{parentName:"li",href:"/interchain-security/legacy/v3.3.0/consumer-development/consumer-genesis-transformation"},"Transform Consumer Genesis"),")"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","information about relevant seed/peer nodes you are running"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","relayer information (compatible versions)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","copy of your governance proposal (as JSON)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","a script showing how to start your chain and connect to peers (optional)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable")),(0,i.kt)("p",null,"Example of such a repository can be found ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyphacoop/ics-testnets/tree/main/game-of-chains-2022/sputnik"},"here"),"."),(0,i.kt)("h2",{id:"3-submit-a-consumerchainaddition-governance-proposal-to-the-provider"},"3. Submit a ConsumerChainAddition Governance Proposal to the provider"),(0,i.kt)("p",null,"Before you submit a ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerChainAddition")," proposal, please provide a ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," that is ",(0,i.kt)("strong",{parentName:"p"},"before")," the the ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height")," of the upgrade that will introduce the ",(0,i.kt)("inlineCode",{parentName:"p"},"ccv module")," to your chain."),(0,i.kt)("admonition",{type:"danger"},(0,i.kt)("p",{parentName:"admonition"},"If the ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," happens after your ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height")," the provider will not be able to communicate the new validator set to be used after the changeover.")),(0,i.kt)("p",null,"Additionally, reach out to the community via the ",(0,i.kt)("a",{parentName:"p",href:"https://forum.cosmos.network/"},"forum")," to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine your chain's spawn time"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine consumer chain parameters to be put in the proposal"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take note to include a link to your onboarding repository")),(0,i.kt)("p",null,"Example of a consumer chain addition proposal."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},'// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain or add a standalone chain.\n// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.\n// It is recommended that spawn time occurs after the proposal end time and that it is scheduled to happen before the standalone chain upgrade\n// that sill introduce the ccv module.\n{\n // Title of the proposal\n "title": "Changeover Standalone chain",\n // Description of the proposal\n // format the text as a .md file and include the file in your onboarding repository\n "description": ".md description of your chain and all other relevant information",\n // Proposed chain-id of the new consumer chain.\n // Must be unique from all other consumer chain ids of the executing provider chain.\n "chain_id": "standalone-1",\n // Initial height of new consumer chain.\n // For a completely new chain, this will be {0,1}.\n "initial_height" : {\n // must correspond to current revision number of standalone chain\n // e.g. standalone-1 => "revision_number": 1\n "revision_number": 1,\n\n // must correspond to a height that is at least 1 block after the upgrade\n // that will add the `consumer` module to the standalone chain\n // e.g. "upgrade_height": 100 => "revision_height": 101\n "revision_number": 1,\n },\n // Hash of the consumer chain genesis state without the consumer CCV module genesis params.\n // => not relevant for changeover procedure\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n // Hash of the consumer chain binary that should be run by validators on standalone chain upgrade\n // => not relevant for changeover procedure as it may become stale\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n // Unbonding period for the consumer chain.\n // It should should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n // IBC transfer packets will timeout after this interval elapses.\n "transfer_timeout_period": 1800000000000,\n // The fraction of tokens allocated to the consumer redistribution address during distribution events.\n // The fraction is a string representing a decimal number. For example "0.75" would represent 75%.\n // The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.\n "consumer_redistribution_fraction": "0.75",\n // BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.\n // eg. send rewards to the provider every 1000 blocks\n "blocks_per_distribution_transmission": 1000,\n // The number of historical info entries to persist in store.\n // This param is a part of the cosmos sdk staking module. In the case of\n // a ccv enabled consumer chain, the ccv module acts as the staking module.\n "historical_entries": 10000,\n // The ID of a token transfer channel used for the Reward Distribution\n // sub-protocol. If DistributionTransmissionChannel == "", a new transfer\n // channel is created on top of the same connection as the CCV channel.\n // Note that transfer_channel_id is the ID of the channel end on the consumer chain.\n // it is most relevant for chains performing a standalone to consumer changeover\n // in order to maintan the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123" // NOTE: use existing transfer channel if available\n}\n')),(0,i.kt)("h2",{id:"3-submit-an-upgrade-proposal--prepare-for-changeover"},"3. Submit an Upgrade Proposal & Prepare for Changeover"),(0,i.kt)("p",null,"This proposal should add the ccv ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer")," module to your chain."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","proposal ",(0,i.kt)("inlineCode",{parentName:"li"},"upgrade_height")," must happen after ",(0,i.kt)("inlineCode",{parentName:"li"},"spawn_time")," in the ",(0,i.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal")),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","advise validators about the exact procedure for your chain and point them to your onboarding repository")),(0,i.kt)("h2",{id:"4-upgrade-time-"},"4. Upgrade time \ud83d\ude80"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","after ",(0,i.kt)("inlineCode",{parentName:"li"},"spawn_time"),", request ",(0,i.kt)("inlineCode",{parentName:"li"},"ConsumerGenesis")," from the ",(0,i.kt)("inlineCode",{parentName:"li"},"provider")," and place it in ",(0,i.kt)("inlineCode",{parentName:"li"},"<CURRENT_USER_HOME_DIR>/.sovereign/config/genesis.json")),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","upgrade the binary to the one listed in your ",(0,i.kt)("inlineCode",{parentName:"li"},"UpgradeProposal"))),(0,i.kt)("p",null,'The chain starts after at least 66.67% of standalone voting power comes online. The consumer chain is considered interchain secured once the "old" validator set signs a couple of blocks and transfers control to the ',(0,i.kt)("inlineCode",{parentName:"p"},"provider")," validator set."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","provide a repo with onboarding instructions for validators (it should already be listed in the proposal)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json after ",(0,i.kt)("inlineCode",{parentName:"li"},"spawn_time")," obtained from ",(0,i.kt)("inlineCode",{parentName:"li"},"provider")," (MUST contain the initial validator set)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/2d2c570d.19d0db57.js b/legacy/assets/js/2d2c570d.19d0db57.js new file mode 100644 index 0000000000..5c3acd0450 --- /dev/null +++ b/legacy/assets/js/2d2c570d.19d0db57.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4520],{3905:(e,r,t)=>{t.d(r,{Zo:()=>c,kt:()=>w});var a=t(7294);function n(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);r&&(a=a.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?i(Object(t),!0).forEach((function(r){n(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function s(e,r){if(null==e)return{};var t,a,n=function(e,r){if(null==e)return{};var t,a,n={},i=Object.keys(e);for(a=0;a<i.length;a++)t=i[a],r.indexOf(t)>=0||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)t=i[a],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(n[t]=e[t])}return n}var l=a.createContext({}),d=function(e){var r=a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):o(o({},r),e)),t},c=function(e){var r=d(e.components);return a.createElement(l.Provider,{value:r},e.children)},m="mdxType",p={inlineCode:"code",wrapper:function(e){var r=e.children;return a.createElement(a.Fragment,{},r)}},u=a.forwardRef((function(e,r){var t=e.components,n=e.mdxType,i=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),m=d(t),u=n,w=m["".concat(l,".").concat(u)]||m[u]||p[u]||i;return t?a.createElement(w,o(o({ref:r},c),{},{components:t})):a.createElement(w,o({ref:r},c))}));function w(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var i=t.length,o=new Array(i);o[0]=u;var s={};for(var l in r)hasOwnProperty.call(r,l)&&(s[l]=r[l]);s.originalType=e,s[m]="string"==typeof e?e:n,o[1]=s;for(var d=2;d<i;d++)o[d]=t[d];return a.createElement.apply(null,o)}return a.createElement.apply(null,t)}u.displayName="MDXCreateElement"},2348:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>d});var a=t(7462),n=(t(7294),t(3905));const i={sidebar_position:3},o="Withdrawing consumer chain validator rewards",s={unversionedId:"validators/withdraw_rewards",id:"version-v3.3.1-lsm/validators/withdraw_rewards",title:"Withdrawing consumer chain validator rewards",description:"Here are example steps for withdrawing rewards from consumer chains in the provider chain",source:"@site/versioned_docs/version-v3.3.1-lsm/validators/withdraw_rewards.md",sourceDirName:"validators",slug:"/validators/withdraw_rewards",permalink:"/interchain-security/legacy/validators/withdraw_rewards",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Joining Replicated Security testnet",permalink:"/interchain-security/legacy/validators/joining-testnet"},next:{title:"Validator instructions for Changeover Procedure",permalink:"/interchain-security/legacy/validators/changeover-procedure"}},l={},d=[{value:"Querying validator rewards",id:"querying-validator-rewards",level:2},{value:"Withdrawing rewards and commission",id:"withdrawing-rewards-and-commission",level:2},{value:"1. Withdraw rewards",id:"1-withdraw-rewards",level:3},{value:"2. Confirm withdrawal",id:"2-confirm-withdrawal",level:3}],c={toc:d},m="wrapper";function p(e){let{components:r,...t}=e;return(0,n.kt)(m,(0,a.Z)({},c,t,{components:r,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"withdrawing-consumer-chain-validator-rewards"},"Withdrawing consumer chain validator rewards"),(0,n.kt)("p",null,"Here are example steps for withdrawing rewards from consumer chains in the provider chain"),(0,n.kt)("admonition",{type:"info"},(0,n.kt)("p",{parentName:"admonition"},"The examples used are from ",(0,n.kt)("inlineCode",{parentName:"p"},"rs-testnet"),", the replicated security persistent testnet."),(0,n.kt)("p",{parentName:"admonition"},"Validator operator address: ",(0,n.kt)("inlineCode",{parentName:"p"},"cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6"),"\nSelf-delegation address: ",(0,n.kt)("inlineCode",{parentName:"p"},"cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf"))),(0,n.kt)("p",null,"Prior to withdrawing rewards, query balances for self-delegation address:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "1000000000000"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n')),(0,n.kt)("h2",{id:"querying-validator-rewards"},"Querying validator rewards"),(0,n.kt)("p",null,"Query rewards for the validator address:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6\n\nrewards:\n- amount: "158.069895000000000000"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "841842390516.072526500000000000"\n denom: uatom\n')),(0,n.kt)("p",null,"The ",(0,n.kt)("inlineCode",{parentName:"p"},"ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD")," denom represents rewards from a consumer chain."),(0,n.kt)("h2",{id:"withdrawing-rewards-and-commission"},"Withdrawing rewards and commission"),(0,n.kt)("h3",{id:"1-withdraw-rewards"},"1. Withdraw rewards"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y\n\ntxhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A\n")),(0,n.kt)("h3",{id:"2-confirm-withdrawal"},"2. Confirm withdrawal"),(0,n.kt)("p",null,"After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "216"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "2233766225342"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n')))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/2ddaef92.9ebd2053.js b/legacy/assets/js/2ddaef92.9ebd2053.js new file mode 100644 index 0000000000..4c6799dd4b --- /dev/null +++ b/legacy/assets/js/2ddaef92.9ebd2053.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2454],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},d=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},h="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},p=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),h=c(n),p=r,m=h["".concat(l,".").concat(p)]||h[p]||u[p]||o;return n?a.createElement(m,s(s({ref:t},d),{},{components:n})):a.createElement(m,s({ref:t},d))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,s=new Array(o);s[0]=p;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[h]="string"==typeof e?e:r,s[1]=i;for(var c=2;c<o;c++)s[c]=n[c];return a.createElement.apply(null,s)}return a.createElement.apply(null,n)}p.displayName="MDXCreateElement"},8282:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>c});var a=n(7462),r=(n(7294),n(3905));const o={sidebar_position:11,title:"Standalone to Consumer Changeover"},s=void 0,i={unversionedId:"adrs/adr-010-standalone-changeover",id:"version-v3.2.0/adrs/adr-010-standalone-changeover",title:"Standalone to Consumer Changeover",description:"ADR 010: Standalone to Consumer Changeover",source:"@site/versioned_docs/version-v3.2.0/adrs/adr-010-standalone-changeover.md",sourceDirName:"adrs",slug:"/adrs/adr-010-standalone-changeover",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-010-standalone-changeover",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:11,frontMatter:{sidebar_position:11,title:"Standalone to Consumer Changeover"},sidebar:"tutorialSidebar",previous:{title:"Soft Opt-Out",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-009-soft-opt-out"},next:{title:"Improving testing and increasing confidence",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-011-improving-test-confidence"}},l={},c=[{value:"ADR 010: Standalone to Consumer Changeover",id:"adr-010-standalone-to-consumer-changeover",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Process",id:"process",level:3},{value:"Changes to CCV Protocol",id:"changes-to-ccv-protocol",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}],d={toc:c},h="wrapper";function u(e){let{components:t,...n}=e;return(0,r.kt)(h,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"adr-010-standalone-to-consumer-changeover"},"ADR 010: Standalone to Consumer Changeover"),(0,r.kt)("h2",{id:"changelog"},"Changelog"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"6/30/23: Feature completed, first draft of ADR.")),(0,r.kt)("h2",{id:"status"},"Status"),(0,r.kt)("p",null,"Implemented"),(0,r.kt)("h2",{id:"context"},"Context"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/Stride-Labs/stride"},"Stride"),' will be the first consumer to "changeover" from a standalone cosmos blockchain, to a consumer chain secured by the Cosmos Hub. This document will outline the changes made to the replicated security protocol to support this changeover process.'),(0,r.kt)("h2",{id:"decision"},"Decision"),(0,r.kt)("h3",{id:"process"},"Process"),(0,r.kt)("p",null,'Prior to the changeover, the consumer chain will have an existing staking keeper and validator set, these may be referred to as the "standalone staking keeper" and "standalone validator set" respectively. '),(0,r.kt)("p",null,"The first step in the changeover process is to submit a ConsumerAdditionProposal. If the proposal passes, the provider will create a new IBC client for the consumer at spawn time, with the provider's validator set. A consumer genesis will also be constructed by the provider for validators to query. Within this consumer genesis contains the initial validator set for the consumer to apply after the changeover."),(0,r.kt)("p",null,"Next, the standalone consumer chain runs an upgrade which adds the CCV module, and is properly setup to execute changeover logic."),(0,r.kt)("p",null,"The consumer upgrade height must be reached after the provider has created the new IBC client. Any replicated security validators who will run the consumer, but are not a part of the sovereign validator set, must sync up a full node before the consumer upgrade height is reached. The disc state of said full node will be used to run the consumer chain after the changeover has completed."),(0,r.kt)("p",null,"The meat of the changeover logic is that the consumer chain validator set is updated to that which was specified by the provider via the queried consumer genesis. Validators which were a part of the old set, but not the new set, are given zero voting power. Once these validator updates are given to Comet, the set is committed, and in effect 2 blocks later (see ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/x/ccv/consumer/keeper/changeover.go#L19"},"FirstConsumerHeight"),")."),(0,r.kt)("p",null,"A relayer then establishes the new IBC connection between the provider and consumer. The CCV channel handshake is started on top of this connection. Once the CCV channel is established and VSC packets are being relayed, the consumer chain is secured by the provider."),(0,r.kt)("h3",{id:"changes-to-ccv-protocol"},"Changes to CCV Protocol"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Consumer Genesis state is updated to include a ",(0,r.kt)("inlineCode",{parentName:"li"},"PreCCV")," boolean. When this boolean is set true in the consumer genesis JSON, ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/x/ccv/consumer/keeper/changeover.go"},"special logic")," is executed on InitGenesis to trigger the changeover process on the consumer's first endblocker after the upgrade which adds the CCV module. Note that InitGenesis is not automatically called during chain upgrades, so the consumer must manually call the consumer's InitGenesis method in an upgrade handler."),(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal")," type is updated to include a ",(0,r.kt)("inlineCode",{parentName:"li"},"DistributionTransmissionChannel")," field. This field allows the consumer to use an existing IBC transfer channel to send rewards as a part of the CCV protocol. Consumers that're not changing over from a standalone chain will leave this field blank, indicating that a new transfer channel should be created on top of the same connection as the CCV channel."),(0,r.kt)("li",{parentName:"ul"},"The CCV consumer keeper is updated to contain an optional reference to the standalone staking keeper. The standalone staking keeper is used to slash for infractions that happened before the changeover was completed. Ie. any infraction from a block height before the changeover, that is submitted after the changeover, will call the standalone staking keeper's slash method. Note that a changeover consumer's standalone staking keeper becomes a democracy module keeper, so it is possible for a governance token to be slashed.")),(0,r.kt)("h2",{id:"consequences"},"Consequences"),(0,r.kt)("h3",{id:"positive"},"Positive"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Existing cosmos chains are now able to onboard over to a consumer chain secured by a provider."),(0,r.kt)("li",{parentName:"ul"},"The previous staking keepers for such chains can be transitioned to democracy staking module keepers.")),(0,r.kt)("h3",{id:"negative"},"Negative"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"The delineation between different types of consumers in this repo becomes less clear. Ie. there is code in the ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/app/consumer-democracy/app.go"},"democracy consumer's app.go")," that only applies to a previously standalone chain, but that file also serves as the base for a normal democracy consumer launched with RS from genesis.")),(0,r.kt)("h2",{id:"references"},"References"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"EPIC: Standalone to Consumer Changeover ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/756"},"#756")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt"},"Changeover diagram from Stride"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/2e2fcf7b.b6f4a559.js b/legacy/assets/js/2e2fcf7b.b6f4a559.js new file mode 100644 index 0000000000..17fece59a3 --- /dev/null +++ b/legacy/assets/js/2e2fcf7b.b6f4a559.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[918],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),c=p(n),m=a,h=c["".concat(s,".").concat(m)]||c[m]||d[m]||i;return n?r.createElement(h,o(o({ref:t},u),{},{components:n})):r.createElement(h,o({ref:t},u))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:a,o[1]=l;for(var p=2;p<i;p++)o[p]=n[p];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},3372:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var r=n(7462),a=(n(7294),n(3905));const i={sidebar_position:13,title:"Separate Releasing"},o="ADR 012: Separate Releasing",l={unversionedId:"adrs/adr-012-separate-releasing",id:"version-v3.2.0/adrs/adr-012-separate-releasing",title:"Separate Releasing",description:"Changelog",source:"@site/versioned_docs/version-v3.2.0/adrs/adr-012-separate-releasing.md",sourceDirName:"adrs",slug:"/adrs/adr-012-separate-releasing",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-012-separate-releasing",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:13,frontMatter:{sidebar_position:13,title:"Separate Releasing"},sidebar:"tutorialSidebar",previous:{title:"Improving testing and increasing confidence",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-011-improving-test-confidence"},next:{title:"Slashing on the provider for consumer equivocation",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-013-equivocation-slashing"}},s={},p=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Spike results",id:"spike-results",level:3},{value:"Why go.mod split is not the way to go",id:"why-gomod-split-is-not-the-way-to-go",level:3},{value:"Why separate repos is cool but also not the way to go",id:"why-separate-repos-is-cool-but-also-not-the-way-to-go",level:3},{value:"Decision",id:"decision",level:2},{value:"Example release flow",id:"example-release-flow",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],u={toc:p},c="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(c,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-012-separate-releasing"},"ADR 012: Separate Releasing"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"{8/18/22}: Initial draft of idea in ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/801"},"#801")),(0,a.kt)("li",{parentName:"ul"},"{8/22/22}: Put idea in this ADR")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("h3",{id:"spike-results"},"Spike results"),(0,a.kt)("p",null,"I explored the idea of ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/issues/801"},"#801")," with this ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/shawn%2Fgo-mod-split-aug-spike"},"spike branch"),". Here's my conclusions:"),(0,a.kt)("p",null,"Splitting this repo to have multiple go.mods is possible. However there are various intricacies involved in decoupling the package hierarchy to have ",(0,a.kt)("inlineCode",{parentName:"p"},"x/ccv/types")," as the lowest level dep, with ",(0,a.kt)("inlineCode",{parentName:"p"},"x/ccv/consumer")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"x/ccv/provider")," being one dep layer above, with high-level tests depending on all three of the mentioned packages. I'd estimate this decoupling would take 2-5 workdays to finish, and require significant review effort."),(0,a.kt)("h3",{id:"why-gomod-split-is-not-the-way-to-go"},"Why go.mod split is not the way to go"),(0,a.kt)("p",null,"Let's take a step back and remember the issue we're trying to solve - ",(0,a.kt)("strong",{parentName:"p"},"We need a clean way to decouple semver/releasing for the consumer and provider modules"),". After more consideration, splitting up go.mods gives us little benefit in achieving this. Reasons:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"The ",(0,a.kt)("inlineCode",{parentName:"li"},"go.mod")," dependency system is tied to git tags for the entire repo (ex: ",(0,a.kt)("inlineCode",{parentName:"li"},"require github.com/cometbft/cometbft v0.37.2")," refers to a historical tag for the entire cometbft repo)."),(0,a.kt)("li",{parentName:"ul"},"It'd be an odd dev experience to allow modules to reference past releases of other modules in the same repo. When would we ever want the consumer module to reference a past release of the types module for example?"),(0,a.kt)("li",{parentName:"ul"},"If we allow for ",(0,a.kt)("inlineCode",{parentName:"li"},"go.mod")," replace statements to build from local source code, why split up the package deps at all?"),(0,a.kt)("li",{parentName:"ul"},"Splitting go.mods adds a bunch of complexity with ",(0,a.kt)("inlineCode",{parentName:"li"},"go.work")," files and all that shiz. VSCode does not play well with multiple module repos either.")),(0,a.kt)("h3",{id:"why-separate-repos-is-cool-but-also-not-the-way-to-go"},"Why separate repos is cool but also not the way to go"),(0,a.kt)("p",null,"All this considered, the cleanest solution to decoupling semver/releasing for the consumer and provider modules would be to have multiple repos, each with their own go.mod (3-4 repos total including high level tests). With this scheme we could separately tag each repo as changes are merged, they could share some code from ",(0,a.kt)("inlineCode",{parentName:"p"},"types")," being an external dep, etc."),(0,a.kt)("p",null,"I don't think any of us want to split up the monorepo, that's a lot of work and seems like bikeshedding. There's another solution that's very simple.. "),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"Slightly adapting ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/cca008d856e3ffc60ec1a486871d0faa702abe26/CONTRIBUTING.md#semantic-versioning"},"the current semver ruleset"),":"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"A library API breaking change to EITHER the provider or consumer module will result in an increase of the MAJOR version number for BOTH modules (X.y.z-provider AND X.y.z-consumer)."),(0,a.kt)("li",{parentName:"ul"},"A state breaking change (change requiring coordinated upgrade and/or state migration) will result in an increase of the MINOR version number for the AFFECTED module(s) (x.Y.z-provider AND/OR x.Y.z-consumer)."),(0,a.kt)("li",{parentName:"ul"},"Any other changes (including node API breaking changes) will result in an increase of the PATCH version number for the AFFECTED module(s) (x.y.Z-provider AND/OR x.y.Z-consumer).")),(0,a.kt)("h3",{id:"example-release-flow"},"Example release flow"),(0,a.kt)("p",null,"We upgrade ",(0,a.kt)("inlineCode",{parentName:"p"},"main")," to use a new version of SDK. This is a major version bump, triggering a new release for both the provider and consumer modules, ",(0,a.kt)("inlineCode",{parentName:"p"},"v5.0.0-provider")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"v5.0.0-consumer"),"."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"A state breaking change is merged to ",(0,a.kt)("inlineCode",{parentName:"li"},"main")," for the provider module. We release only a ",(0,a.kt)("inlineCode",{parentName:"li"},"v5.1.0-provider")," off main."),(0,a.kt)("li",{parentName:"ul"},"Another state breaking change is merged to ",(0,a.kt)("inlineCode",{parentName:"li"},"main")," for the provider module. We release only a ",(0,a.kt)("inlineCode",{parentName:"li"},"v5.2.0-provider")," off main."),(0,a.kt)("li",{parentName:"ul"},"At this point, the latest consumer version is still ",(0,a.kt)("inlineCode",{parentName:"li"},"v5.0.0-consumer"),". We now merge a state breaking change for the consumer module to ",(0,a.kt)("inlineCode",{parentName:"li"},"main"),", and consequently release ",(0,a.kt)("inlineCode",{parentName:"li"},"v5.1.0-consumer"),". Note that ",(0,a.kt)("inlineCode",{parentName:"li"},"v5.1.0-consumer")," is tagged off a LATER commit from main than ",(0,a.kt)("inlineCode",{parentName:"li"},"v5.2.0-provider"),". This is fine, as the consumer module should not be affected by the provider module's state breaking changes."),(0,a.kt)("li",{parentName:"ul"},"Once either module sees a library API breaking change, we bump the major version for both modules. For example, we merge a library API breaking change to ",(0,a.kt)("inlineCode",{parentName:"li"},"main")," for the provider module. We release ",(0,a.kt)("inlineCode",{parentName:"li"},"v6.0.0-provider")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"v6.0.0-consumer")," off main. Note that most often, a library API breaking change will affect both modules simultaneously (example being bumping sdk version).")),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Consumer repos have clear communication of what tagged versions are relevant to them. Consumer devs should know to never reference an ICS version that starts with ",(0,a.kt)("inlineCode",{parentName:"li"},"provider"),", even if it'd technically build."),(0,a.kt)("li",{parentName:"ul"},"Consumer and provider modules do not deviate as long as we continually release off a shared main branch. Backporting remains relatively unchanged besides being explicit about what module(s) your changes should affect."),(0,a.kt)("li",{parentName:"ul"},"No code changes, just changes in process. Very simple.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Slightly more complexity."),(0,a.kt)("li",{parentName:"ul"},"This solution does not allow having provider and consumer on separate versions of e.g. the Cosmos SDK")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/801"},"#801")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/801#issuecomment-1683349298"},"#801 comment"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/2ee035c9.06127535.js b/legacy/assets/js/2ee035c9.06127535.js new file mode 100644 index 0000000000..d363a22c31 --- /dev/null +++ b/legacy/assets/js/2ee035c9.06127535.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9029],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>p});var i=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,i)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){n(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,i,n=function(e,t){if(null==e)return{};var r,i,n={},o=Object.keys(e);for(i=0;i<o.length;i++)r=o[i],t.indexOf(r)>=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i<o.length;i++)r=o[i],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=i.createContext({}),l=function(e){var t=i.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},u=function(e){var t=l(e.components);return i.createElement(s.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},y=i.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),d=l(r),y=n,p=d["".concat(s,".").concat(y)]||d[y]||h[y]||o;return r?i.createElement(p,a(a({ref:t},u),{},{components:r})):i.createElement(p,a({ref:t},u))}));function p(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,a=new Array(o);a[0]=y;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[d]="string"==typeof e?e:n,a[1]=c;for(var l=2;l<o;l++)a[l]=r[l];return i.createElement.apply(null,a)}return i.createElement.apply(null,r)}y.displayName="MDXCreateElement"},900:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>c,toc:()=>l});var i=r(7462),n=(r(7294),r(3905));const o={sidebar_position:2},a="Terminology",c={unversionedId:"introduction/terminology",id:"version-v2.4.0-lsm/introduction/terminology",title:"Terminology",description:"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.",source:"@site/versioned_docs/version-v2.4.0-lsm/introduction/terminology.md",sourceDirName:"introduction",slug:"/introduction/terminology",permalink:"/interchain-security/legacy/v2.4.0-lsm/introduction/terminology",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/legacy/v2.4.0-lsm/introduction/overview"},next:{title:"Interchain Security Parameters",permalink:"/interchain-security/legacy/v2.4.0-lsm/introduction/params"}},s={},l=[{value:"Shared Security",id:"shared-security",level:2},{value:"Interchain Security",id:"interchain-security",level:2},{value:"Replicated Security",id:"replicated-security",level:2},{value:"Mesh security",id:"mesh-security",level:2}],u={toc:l},d="wrapper";function h(e){let{components:t,...r}=e;return(0,n.kt)(d,(0,i.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"terminology"},"Terminology"),(0,n.kt)("p",null,"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions."),(0,n.kt)("h2",{id:"shared-security"},"Shared Security"),(0,n.kt)("p",null,"Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share it's proof-of-stake security with another blockchain or off-chain process."),(0,n.kt)("h2",{id:"interchain-security"},"Interchain Security"),(0,n.kt)("p",null,"Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC."),(0,n.kt)("h2",{id:"replicated-security"},"Replicated Security"),(0,n.kt)("p",null,'A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC. Note this documentation is focused on explaining the concepts from replicated security.'),(0,n.kt)("h2",{id:"mesh-security"},"Mesh security"),(0,n.kt)("p",null,"A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see ",(0,n.kt)("a",{parentName:"p",href:"https://informal.systems/blog/replicated-vs-mesh-security"},"Replicated vs. Mesh Security on the Informal Blog"),"."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/2eef71dd.68939c94.js b/legacy/assets/js/2eef71dd.68939c94.js new file mode 100644 index 0000000000..cf60564328 --- /dev/null +++ b/legacy/assets/js/2eef71dd.68939c94.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5464],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,m=u["".concat(c,".").concat(h)]||u[h]||d[h]||i;return n?a.createElement(m,o(o({ref:t},p),{},{components:n})):a.createElement(m,o({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:r,o[1]=s;for(var l=2;l<i;l++)o[l]=n[l];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},6914:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var a=n(7462),r=(n(7294),n(3905));const i={sidebar_position:2,title:"Joining Replicated Security testnet"},o=void 0,s={unversionedId:"validators/joining-testnet",id:"version-v3.1.0/validators/joining-testnet",title:"Joining Replicated Security testnet",description:"Introduction",source:"@site/versioned_docs/version-v3.1.0/validators/joining-testnet.md",sourceDirName:"validators",slug:"/validators/joining-testnet",permalink:"/interchain-security/legacy/v3.1.0/validators/joining-testnet",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"Joining Replicated Security testnet"},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/legacy/v3.1.0/validators/overview"},next:{title:"Withdrawing consumer chain validator rewards",permalink:"/interchain-security/legacy/v3.1.0/validators/withdraw_rewards"}},c={},l=[{value:"Introduction",id:"introduction",level:2},{value:"Joining the provider chain",id:"joining-the-provider-chain",level:2},{value:"Initialization",id:"initialization",level:2},{value:"Joining consumer chains",id:"joining-consumer-chains",level:2},{value:"Re-using consensus key",id:"re-using-consensus-key",level:2},{value:"Assigning consensus keys",id:"assigning-consensus-keys",level:2},{value:"Baryon",id:"baryon",level:2},{value:"Noble",id:"noble",level:2}],p={toc:l},u="wrapper";function d(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"This short guide will teach you how to join the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security"},"Replicated Security testnet"),"."),(0,r.kt)("p",null,"The experience gained in the testnet will prepare you for validating interchain secured chains."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set."),(0,r.kt)("p",{parentName:"admonition"},"For general information about running cosmos-sdk based chains check out the ",(0,r.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html"},"validator basics")," and ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/main/run-node/run-node"},"Running a Node section")," of Cosmos SDK docs")),(0,r.kt)("h2",{id:"joining-the-provider-chain"},"Joining the provider chain"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain.")),(0,r.kt)("p",null,"A comprehensive guide is available ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security/provider"},"here"),"."),(0,r.kt)("h2",{id:"initialization"},"Initialization"),(0,r.kt)("p",null,"First, initialize your ",(0,r.kt)("inlineCode",{parentName:"p"},"$NODE_HOME")," using the ",(0,r.kt)("inlineCode",{parentName:"p"},"provider")," chain binary."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"NODE_MONIKER=<your_node>\nCHAIN_ID=provider\nNODE_HOME=<path_to_your_home>\n\ngaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME\n")),(0,r.kt)("p",null,"Add your key to the keyring - more details available ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/main/run-node/keyring"},"here"),"."),(0,r.kt)("p",null,"In this example we will use the ",(0,r.kt)("inlineCode",{parentName:"p"},"test")," keyring-backend. This option is not safe to use in production."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad keys add <key_moniker> --keyring-backend test\n\n# save the address as variable for later use\nMY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)\n")),(0,r.kt)("p",null,"Before issuing any transactions, use the ",(0,r.kt)("inlineCode",{parentName:"p"},"provider")," testnet faucet to add funds to your address."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider\n\n# example output:\n{\n "address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",\n "amount": "10000000uatom",\n "chain": "provider",\n "hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",\n "status": "success"\n}\n')),(0,r.kt)("p",null,"Then, use the account associated with the keyring to issue a ",(0,r.kt)("inlineCode",{parentName:"p"},"create-validator")," transaction which will register your validator on chain."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad tx staking create-validator \\\n --amount=1000000uatom \\\n --pubkey=$(gaiad tendermint show-validator) \\\n --moniker="choose a moniker" \\\n --chain-id=$CHAIN_ID" \\\n --commission-rate="0.10" \\\n --commission-max-rate="0.20" \\\n --commission-max-change-rate="0.01" \\\n --min-self-delegation="1000000" \\\n --gas="auto" \\\n --gas-prices="0.0025uatom" \\\n --from=<key_moniker>\n')),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Check this ",(0,r.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html#edit-validator-description"},"guide")," to edit your validator.")),(0,r.kt)("p",null,"After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use ",(0,r.kt)("inlineCode",{parentName:"p"},"statesync")," to catch up to the rest of the network."),(0,r.kt)("p",null,"You can use this script to modify your ",(0,r.kt)("inlineCode",{parentName:"p"},"config.toml")," with the required statesync parameters."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"# create the statesync script\n$: cd $NODE_HOME\n$: touch statesync.sh\n$ chmod 700 statesync.sh # make executable\n")),(0,r.kt)("p",null,"Paste the following instructions into the ",(0,r.kt)("inlineCode",{parentName:"p"},"statesync.sh"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'#!/bin/bash\n\nSNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"\n\nLATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \\\nBLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \\\nTRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)\n\nsed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\\1true| ; \\\ns|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\\1\\"$SNAP_RPC,$SNAP_RPC\\"| ; \\\ns|^(trust_height[[:space:]]+=[[:space:]]+).*$|\\1$BLOCK_HEIGHT| ; \\\ns|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\\1\\"$TRUST_HASH\\"|" $NODE_HOME/config/config.toml\n')),(0,r.kt)("p",null,"Then, you can execute the script:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"$: ./statesync.sh # setup config.toml for statesync\n")),(0,r.kt)("p",null,"Finally, copy the provider genesis and start your node:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/replicated-security/provider/provider-genesis.json\n$: wget $GENESIS_URL -O genesis.json\n$: genesis.json $NODE_HOME/config/genesis.json\n# start the service\n$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"\n')),(0,r.kt)("p",null,"Additional scripts to setup your nodes are available ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/provider/join-rs-provider.sh"},"here")," and ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/provider/join-rs-provider-cv.sh"},"here"),". The scripts will configure your node and create the required services - the scripts only work in linux environments."),(0,r.kt)("h2",{id:"joining-consumer-chains"},"Joining consumer chains"),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Once you reach the active set on the provider chain, you will be required to validate all available consumer chains."),(0,r.kt)("p",{parentName:"admonition"},"You can use the same consensus key on all consumer chains, or opt to use a different key on each consumer chain.\nCheck out this ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.1.0/features/key-assignment"},"guide")," to learn more about key assignment in replicated security.")),(0,r.kt)("p",null,"To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"When running the provider chain and consumers on the same machine please update the ",(0,r.kt)("inlineCode",{parentName:"p"},"PORT")," numbers for each of them and make sure they do not overlap (otherwise the binaries will not start)."),(0,r.kt)("p",{parentName:"admonition"},"Important ports to re-configure:"),(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--rpc.laddr")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--p2p.laddr")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--api.address")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--grpc.address")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--grpc-web.address")))),(0,r.kt)("h2",{id:"re-using-consensus-key"},"Re-using consensus key"),(0,r.kt)("p",null,"To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the ",(0,r.kt)("inlineCode",{parentName:"p"},"priv_validator_key.json")," into the home directory of your consumer chain (",(0,r.kt)("inlineCode",{parentName:"p"},"<consumer_home>/config/priv_validator_key.json"),")."),(0,r.kt)("p",null,"When you start the chain, the consensus key will be the same on the provider and the consumer chain."),(0,r.kt)("h2",{id:"assigning-consensus-keys"},"Assigning consensus keys"),(0,r.kt)("p",null,"Whenever you initialize a new node, it will be configured with a consensus key you can use."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'# machine running consumer chain\nconsumerd init <node_moniker> --home <home_path> --chain-id consumer-1\n\n# use the output of this command to get the consumer chain consensus key\nconsumerd tendermint show-validator\n# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}\n')),(0,r.kt)("p",null,"Then, let the provider know which key you will be using for the consumer chain:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"# machine running the provider chain\ngaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b sync -y -o json\n")),(0,r.kt)("p",null,"After this step, you are ready to copy the consumer genesis into your nodes's ",(0,r.kt)("inlineCode",{parentName:"p"},"/config")," folder, start your consumer chain node and catch up to the network."),(0,r.kt)("h2",{id:"baryon"},"Baryon"),(0,r.kt)("p",null,"You can find the onboarding repo instructions for the Baryon chain ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/baryon-1/README.md"},"here")),(0,r.kt)("h2",{id:"noble"},"Noble"),(0,r.kt)("p",null,"You can find the onboarding repo instructions for the Noble chain ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/noble-1/README.md"},"here")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/306f1d5d.74edbf3e.js b/legacy/assets/js/306f1d5d.74edbf3e.js new file mode 100644 index 0000000000..a0e42a444a --- /dev/null +++ b/legacy/assets/js/306f1d5d.74edbf3e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8130],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,m=u["".concat(c,".").concat(h)]||u[h]||d[h]||i;return n?a.createElement(m,o(o({ref:t},p),{},{components:n})):a.createElement(m,o({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:r,o[1]=s;for(var l=2;l<i;l++)o[l]=n[l];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},6944:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var a=n(7462),r=(n(7294),n(3905));const i={sidebar_position:2,title:"Joining Replicated Security testnet"},o=void 0,s={unversionedId:"validators/joining-testnet",id:"version-v3.3.0/validators/joining-testnet",title:"Joining Replicated Security testnet",description:"Introduction",source:"@site/versioned_docs/version-v3.3.0/validators/joining-testnet.md",sourceDirName:"validators",slug:"/validators/joining-testnet",permalink:"/interchain-security/legacy/v3.3.0/validators/joining-testnet",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"Joining Replicated Security testnet"},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/legacy/v3.3.0/validators/overview"},next:{title:"Withdrawing consumer chain validator rewards",permalink:"/interchain-security/legacy/v3.3.0/validators/withdraw_rewards"}},c={},l=[{value:"Introduction",id:"introduction",level:2},{value:"Joining the provider chain",id:"joining-the-provider-chain",level:2},{value:"Initialization",id:"initialization",level:2},{value:"Joining consumer chains",id:"joining-consumer-chains",level:2},{value:"Re-using consensus key",id:"re-using-consensus-key",level:2},{value:"Assigning consensus keys",id:"assigning-consensus-keys",level:2}],p={toc:l},u="wrapper";function d(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"This short guide will teach you how to join the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security"},"Replicated Security testnet"),"."),(0,r.kt)("p",null,"The experience gained in the testnet will prepare you for validating interchain secured chains."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set."),(0,r.kt)("p",{parentName:"admonition"},"For general information about running cosmos-sdk based chains check out the ",(0,r.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html"},"validator basics")," and ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/main/run-node/run-node"},"Running a Node section")," of Cosmos SDK docs")),(0,r.kt)("h2",{id:"joining-the-provider-chain"},"Joining the provider chain"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain.")),(0,r.kt)("p",null,"A comprehensive guide is available ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security/provider"},"here"),"."),(0,r.kt)("h2",{id:"initialization"},"Initialization"),(0,r.kt)("p",null,"First, initialize your ",(0,r.kt)("inlineCode",{parentName:"p"},"$NODE_HOME")," using the ",(0,r.kt)("inlineCode",{parentName:"p"},"provider")," chain binary."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"NODE_MONIKER=<your_node>\nCHAIN_ID=provider\nNODE_HOME=<path_to_your_home>\n\ngaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME\n")),(0,r.kt)("p",null,"Add your key to the keyring - more details available ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/main/run-node/keyring"},"here"),"."),(0,r.kt)("p",null,"In this example we will use the ",(0,r.kt)("inlineCode",{parentName:"p"},"test")," keyring-backend. This option is not safe to use in production."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad keys add <key_moniker> --keyring-backend test\n\n# save the address as variable for later use\nMY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)\n")),(0,r.kt)("p",null,"Before issuing any transactions, use the ",(0,r.kt)("inlineCode",{parentName:"p"},"provider")," testnet faucet to add funds to your address."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider\n\n# example output:\n{\n "address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",\n "amount": "10000000uatom",\n "chain": "provider",\n "hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",\n "status": "success"\n}\n')),(0,r.kt)("p",null,"Then, use the account associated with the keyring to issue a ",(0,r.kt)("inlineCode",{parentName:"p"},"create-validator")," transaction which will register your validator on chain."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad tx staking create-validator \\\n --amount=1000000uatom \\\n --pubkey=$(gaiad tendermint show-validator) \\\n --moniker="choose a moniker" \\\n --chain-id=$CHAIN_ID" \\\n --commission-rate="0.10" \\\n --commission-max-rate="0.20" \\\n --commission-max-change-rate="0.01" \\\n --min-self-delegation="1000000" \\\n --gas="auto" \\\n --gas-prices="0.0025uatom" \\\n --from=<key_moniker>\n')),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Check this ",(0,r.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html#edit-validator-description"},"guide")," to edit your validator.")),(0,r.kt)("p",null,"After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use ",(0,r.kt)("inlineCode",{parentName:"p"},"statesync")," to catch up to the rest of the network."),(0,r.kt)("p",null,"You can use this script to modify your ",(0,r.kt)("inlineCode",{parentName:"p"},"config.toml")," with the required statesync parameters."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"# create the statesync script\n$: cd $NODE_HOME\n$: touch statesync.sh\n$ chmod 700 statesync.sh # make executable\n")),(0,r.kt)("p",null,"Paste the following instructions into the ",(0,r.kt)("inlineCode",{parentName:"p"},"statesync.sh"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'#!/bin/bash\n\nSNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"\n\nLATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \\\nBLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \\\nTRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)\n\nsed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\\1true| ; \\\ns|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\\1\\"$SNAP_RPC,$SNAP_RPC\\"| ; \\\ns|^(trust_height[[:space:]]+=[[:space:]]+).*$|\\1$BLOCK_HEIGHT| ; \\\ns|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\\1\\"$TRUST_HASH\\"|" $NODE_HOME/config/config.toml\n')),(0,r.kt)("p",null,"Then, you can execute the script:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"$: ./statesync.sh # setup config.toml for statesync\n")),(0,r.kt)("p",null,"Finally, copy the provider genesis and start your node:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/replicated-security/provider/provider-genesis.json\n$: wget $GENESIS_URL -O genesis.json\n$: genesis.json $NODE_HOME/config/genesis.json\n# start the service\n$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"\n')),(0,r.kt)("p",null,"Additional scripts to setup your nodes are available ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/provider/join-rs-provider.sh"},"here")," and ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/provider/join-rs-provider-cv.sh"},"here"),". The scripts will configure your node and create the required services - the scripts only work in linux environments."),(0,r.kt)("h2",{id:"joining-consumer-chains"},"Joining consumer chains"),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Once you reach the active set on the provider chain, you will be required to validate all available consumer chains."),(0,r.kt)("p",{parentName:"admonition"},"You can use the same consensus key on all consumer chains, or opt to use a different key on each consumer chain.\nCheck out this ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/features/key-assignment"},"guide")," to learn more about key assignment in replicated security.")),(0,r.kt)("p",null,"To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"When running the provider chain and consumers on the same machine please update the ",(0,r.kt)("inlineCode",{parentName:"p"},"PORT")," numbers for each of them and make sure they do not overlap (otherwise the binaries will not start)."),(0,r.kt)("p",{parentName:"admonition"},"Important ports to re-configure:"),(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--rpc.laddr")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--p2p.laddr")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--api.address")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--grpc.address")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--grpc-web.address")))),(0,r.kt)("h2",{id:"re-using-consensus-key"},"Re-using consensus key"),(0,r.kt)("p",null,"To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the ",(0,r.kt)("inlineCode",{parentName:"p"},"priv_validator_key.json")," into the home directory of your consumer chain (",(0,r.kt)("inlineCode",{parentName:"p"},"<consumer_home>/config/priv_validator_key.json"),")."),(0,r.kt)("p",null,"When you start the chain, the consensus key will be the same on the provider and the consumer chain."),(0,r.kt)("h2",{id:"assigning-consensus-keys"},"Assigning consensus keys"),(0,r.kt)("p",null,"Whenever you initialize a new node, it will be configured with a consensus key you can use."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'# machine running consumer chain\nconsumerd init <node_moniker> --home <home_path> --chain-id consumer-1\n\n# use the output of this command to get the consumer chain consensus key\nconsumerd tendermint show-validator\n# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}\n')),(0,r.kt)("p",null,"Then, let the provider know which key you will be using for the consumer chain:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"# machine running the provider chain\ngaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b sync -y -o json\n")),(0,r.kt)("p",null,"After this step, you are ready to copy the consumer genesis into your nodes's ",(0,r.kt)("inlineCode",{parentName:"p"},"/config")," folder, start your consumer chain node and catch up to the network."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/32783f50.071d53c7.js b/legacy/assets/js/32783f50.071d53c7.js new file mode 100644 index 0000000000..86c87e7a31 --- /dev/null +++ b/legacy/assets/js/32783f50.071d53c7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2361],{3769:e=>{e.exports=JSON.parse('{"name":"docusaurus-plugin-content-docs","id":"default"}')}}]); \ No newline at end of file diff --git a/legacy/assets/js/3299f073.cf4a49c3.js b/legacy/assets/js/3299f073.cf4a49c3.js new file mode 100644 index 0000000000..b37279dbea --- /dev/null +++ b/legacy/assets/js/3299f073.cf4a49c3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8756],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),c=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),m=a,h=u["".concat(l,".").concat(m)]||u[m]||d[m]||i;return n?o.createElement(h,r(r({ref:t},p),{},{components:n})):o.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,r=new Array(i);r[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,r[1]=s;for(var c=2;c<i;c++)r[c]=n[c];return o.createElement.apply(null,r)}return o.createElement.apply(null,n)}m.displayName="MDXCreateElement"},5142:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var o=n(7462),a=(n(7294),n(3905));const i={sidebar_position:4,title:"Equivocation governance proposal"},r="ADR 003: Equivocation governance proposal",s={unversionedId:"adrs/adr-003-equivocation-gov-proposal",id:"version-v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposal",title:"Equivocation governance proposal",description:"Changelog",source:"@site/versioned_docs/version-v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposal.md",sourceDirName:"adrs",slug:"/adrs/adr-003-equivocation-gov-proposal",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposal",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Equivocation governance proposal"},sidebar:"tutorialSidebar",previous:{title:"Jail Throttling",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-002-throttle"},next:{title:"Cryptographic verification of equivocation evidence",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verification"}},l={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],p={toc:c},u="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-003-equivocation-governance-proposal"},"ADR 003: Equivocation governance proposal"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"2023-02-06: Initial draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain."),(0,a.kt)("p",null,"For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain."),(0,a.kt)("p",null,"A new kind of governance proposal is added to the ",(0,a.kt)("inlineCode",{parentName:"p"},"provider")," module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain."),(0,a.kt)("p",null,"If such proposal passes, the proposal handler delegates to the ",(0,a.kt)("inlineCode",{parentName:"p"},"evidence")," module to process the equivocation. This module ensures the evidence isn\u2019t too old, or else ignores it (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/21021b837882d1d40f1d79bcbc4fad2e79a3fefe/x/evidence/keeper/infraction.go#L54-L62"},"code"),"). ",(0,a.kt)("em",{parentName:"p"},"Too old")," is determined by 2 consensus params : "),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"evidence.max_age_duration")," number of nanoseconds before an evidence is considered too old"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"evidence.max_age_numblocks")," number of blocks before an evidence is considered too old.")),(0,a.kt)("p",null,"On the hub, those parameters are equals to "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682\n(...)\n"evidence": {\n "max_age_num_blocks": "1000000",\n "max_age_duration": "172800000000000",\n (...)\n},\n(...)\n')),(0,a.kt)("p",null,"A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the ",(0,a.kt)("inlineCode",{parentName:"p"},"evidence")," module when the proposal passes and is handled by the hub."),(0,a.kt)("p",null,"For ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks=1M"),", the parameter is big enough if we consider the hub produces 12k blocks per day (",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_year/365 = 436,0000/365"),"). The evidence can be up to 83 days old (",(0,a.kt)("inlineCode",{parentName:"p"},"1,000,000/12,000"),") and not be ignored."),(0,a.kt)("p",null,"For ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_duration=172,800,000,000,000"),", the parameter is too low, because the value is in nanoseconds so it\u2019s 2 days. Fortunately the condition that checks those 2 parameters uses a ",(0,a.kt)("strong",{parentName:"p"},"AND"),", so if ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks")," condition passes, the evidence won\u2019t be ignored."),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Remove the possibility from a malicious consumer chain to \u201cattack\u201d the provider chain by slashing/jailing validators."),(0,a.kt)("li",{parentName:"ul"},"Provide a more acceptable implementation for the validator community.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Punishment action of double-signing isn\u2019t \u201cautomated\u201d, a governance proposal is required which takes more time."),(0,a.kt)("li",{parentName:"ul"},"You need to pay 250ATOM to submit an equivocation evidence.")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"PR that ignores non downtime slash packet : ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/692"},"https://github.com/cosmos/interchain-security/pull/692")),(0,a.kt)("li",{parentName:"ul"},"PR that adds the governance slash proposal: ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/703"},"https://github.com/cosmos/interchain-security/pull/703"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/358d35ce.dadf7286.js b/legacy/assets/js/358d35ce.dadf7286.js new file mode 100644 index 0000000000..0a6f71f2a0 --- /dev/null +++ b/legacy/assets/js/358d35ce.dadf7286.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4343],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>m});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?i(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,a,r=function(e,n){if(null==e)return{};var t,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=a.createContext({}),c=function(e){var n=a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=c(e.components);return a.createElement(l.Provider,{value:n},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},y=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=c(t),y=r,m=d["".concat(l,".").concat(y)]||d[y]||p[y]||i;return t?a.createElement(m,o(o({ref:n},u),{},{components:t})):a.createElement(m,o({ref:n},u))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,o=new Array(i);o[0]=y;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var c=2;c<i;c++)o[c]=t[c];return a.createElement.apply(null,o)}return a.createElement.apply(null,t)}y.displayName="MDXCreateElement"},235:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var a=t(7462),r=(t(7294),t(3905));const i={sidebar_position:1},o="Key Assignment",s={unversionedId:"features/key-assignment",id:"version-v3.3.1-lsm/features/key-assignment",title:"Key Assignment",description:"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.",source:"@site/versioned_docs/version-v3.3.1-lsm/features/key-assignment.md",sourceDirName:"features",slug:"/features/key-assignment",permalink:"/interchain-security/legacy/features/key-assignment",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Technical Specification",permalink:"/interchain-security/legacy/introduction/technical-specification"},next:{title:"Reward distribution",permalink:"/interchain-security/legacy/features/reward-distribution"}},l={},c=[{value:"Rules",id:"rules",level:2},{value:"Adding a key",id:"adding-a-key",level:2},{value:"Changing a key",id:"changing-a-key",level:2},{value:"Removing a key",id:"removing-a-key",level:2}],u={toc:c},d="wrapper";function p(e){let{components:n,...t}=e;return(0,r.kt)(d,(0,a.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"key-assignment"},"Key Assignment"),(0,r.kt)("p",null,"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.\nThere are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains."),(0,r.kt)("p",null,"The feature is outlined in this ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/adrs/adr-001-key-assignment"},"ADR-001")),(0,r.kt)("p",null,"By sending an ",(0,r.kt)("inlineCode",{parentName:"p"},"AssignConsumerKey")," transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity.")),(0,r.kt)("h2",{id:"rules"},"Rules"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"a key can be assigned before the consumer addition proposal passes on the provider"),(0,r.kt)("li",{parentName:"ul"},"validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider"),(0,r.kt)("li",{parentName:"ul"},"validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X"),(0,r.kt)("li",{parentName:"ul"},"a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Validators can use a different key for each consumer chain.")),(0,r.kt)("h2",{id:"adding-a-key"},"Adding a key"),(0,r.kt)("p",null,"First, create a new node on the consumer chain using the equivalent:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"consumerd init <moniker>\n")),(0,r.kt)("p",null,"Then query your node for the consensus key."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}\n')),(0,r.kt)("p",null,"Then, make an ",(0,r.kt)("inlineCode",{parentName:"p"},"assign-consensus-key")," transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad tx provider assign-consensus-key <consumer-chain-id> '<pubkey>' --from <tx-signer> --home <home_dir> --gas 900000 -b sync -y -o json\n")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"consumer-chain-id")," is the string identifier of the consumer chain, as assigned on the provider chain"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"consumer-pub-key")," has the following format ",(0,r.kt)("inlineCode",{parentName:"li"},'{"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}'))),(0,r.kt)("p",null,"Check that the key was assigned correctly by querying the provider:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad query provider validator-consumer-key <consumer-chain-id> cosmosvalcons1e....3xsj3ayzf4uv6\n")),(0,r.kt)("p",null,"You must use a ",(0,r.kt)("inlineCode",{parentName:"p"},"valcons")," address. You can obtain it by querying your node on the provider ",(0,r.kt)("inlineCode",{parentName:"p"},"gaiad tendermint show-address")),(0,r.kt)("p",null,"OR"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad query provider validator-provider-key <consumer-chain-id> consumervalcons1e....123asdnoaisdao\n")),(0,r.kt)("p",null,"You must use a ",(0,r.kt)("inlineCode",{parentName:"p"},"valcons")," address. You can obtain it by querying your node on the consumer ",(0,r.kt)("inlineCode",{parentName:"p"},"consumerd tendermint show-address")),(0,r.kt)("p",null,"OR"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad query provider all-pairs-valconsensus-address <consumer-chain-id>\n")),(0,r.kt)("p",null,"You just need to use the ",(0,r.kt)("inlineCode",{parentName:"p"},"chainId")," of consumer to query all pairs valconsensus address with ",(0,r.kt)("inlineCode",{parentName:"p"},"consumer-pub-key")," for each of pair"),(0,r.kt)("h2",{id:"changing-a-key"},"Changing a key"),(0,r.kt)("p",null,"To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied"),(0,r.kt)("h2",{id:"removing-a-key"},"Removing a key"),(0,r.kt)("p",null,"To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the ",(0,r.kt)("inlineCode",{parentName:"p"},"Adding a key")," section and using your provider consensus key."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/3672b5b7.3b15d5c8.js b/legacy/assets/js/3672b5b7.3b15d5c8.js new file mode 100644 index 0000000000..8d877d085a --- /dev/null +++ b/legacy/assets/js/3672b5b7.3b15d5c8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[320],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var i=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,i,r=function(e,t){if(null==e)return{};var n,i,r={},o=Object.keys(e);for(i=0;i<o.length;i++)n=o[i],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i<o.length;i++)n=o[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=i.createContext({}),d=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=d(e.components);return i.createElement(l.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},m=i.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),c=d(n),m=r,h=c["".concat(l,".").concat(m)]||c[m]||u[m]||o;return n?i.createElement(h,a(a({ref:t},p),{},{components:n})):i.createElement(h,a({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,a=new Array(o);a[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:r,a[1]=s;for(var d=2;d<o;d++)a[d]=n[d];return i.createElement.apply(null,a)}return i.createElement.apply(null,n)}m.displayName="MDXCreateElement"},6239:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var i=n(7462),r=(n(7294),n(3905));const o={sidebar_position:3},a="Interchain Security Parameters",s={unversionedId:"introduction/params",id:"introduction/params",title:"Interchain Security Parameters",description:"The parameters necessary for Interchain Security (ICS) are defined in",source:"@site/docs/introduction/params.md",sourceDirName:"introduction",slug:"/introduction/params",permalink:"/interchain-security/legacy/introduction/params",draft:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Terminology",permalink:"/interchain-security/legacy/introduction/terminology"},next:{title:"Technical Specification",permalink:"/interchain-security/legacy/introduction/technical-specification"}},l={},d=[{value:"Time-based parameters",id:"time-based-parameters",level:2},{value:"ProviderUnbondingPeriod",id:"providerunbondingperiod",level:3},{value:"ConsumerUnbondingPeriod",id:"consumerunbondingperiod",level:3},{value:"TrustingPeriodFraction",id:"trustingperiodfraction",level:3},{value:"CCVTimeoutPeriod",id:"ccvtimeoutperiod",level:3},{value:"InitTimeoutPeriod",id:"inittimeoutperiod",level:3},{value:"<code>VscTimeoutPeriod</code>",id:"vsctimeoutperiod",level:3},{value:"BlocksPerDistributionTransmission",id:"blocksperdistributiontransmission",level:3},{value:"TransferPeriodTimeout",id:"transferperiodtimeout",level:3},{value:"Slash Throttle Parameters",id:"slash-throttle-parameters",level:2},{value:"SlashMeterReplenishPeriod",id:"slashmeterreplenishperiod",level:3},{value:"SlashMeterReplenishFraction",id:"slashmeterreplenishfraction",level:3},{value:"MaxThrottledPackets",id:"maxthrottledpackets",level:3}],p={toc:d},c="wrapper";function u(e){let{components:t,...n}=e;return(0,r.kt)(c,(0,i.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"interchain-security-parameters"},"Interchain Security Parameters"),(0,r.kt)("p",null,"The parameters necessary for Interchain Security (ICS) are defined in "),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"the ",(0,r.kt)("inlineCode",{parentName:"li"},"Params")," structure in ",(0,r.kt)("inlineCode",{parentName:"li"},"proto/interchain_security/ccv/provider/v1/provider.proto")," for the provider;"),(0,r.kt)("li",{parentName:"ul"},"the ",(0,r.kt)("inlineCode",{parentName:"li"},"Params")," structure in ",(0,r.kt)("inlineCode",{parentName:"li"},"proto/interchain_security/ccv/consumer/v1/consumer.proto")," for the consumer.")),(0,r.kt)("h2",{id:"time-based-parameters"},"Time-based parameters"),(0,r.kt)("p",null,"ICS relies on the following time-based parameters."),(0,r.kt)("h3",{id:"providerunbondingperiod"},"ProviderUnbondingPeriod"),(0,r.kt)("p",null,"is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance."),(0,r.kt)("h3",{id:"consumerunbondingperiod"},"ConsumerUnbondingPeriod"),(0,r.kt)("p",null,"is the unbonding period on the consumer chain."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerUnbondingPeriod")," is set via the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," governance proposal to add a new consumer chain.\nIt is recommended that every consumer chain set and unbonding period shorter than ",(0,r.kt)("inlineCode",{parentName:"p"},"ProviderUnbondingPeriod")),(0,r.kt)("br",null),(0,r.kt)("p",{parentName:"admonition"},"Example:"),(0,r.kt)("pre",{parentName:"admonition"},(0,r.kt)("code",{parentName:"pre"},"ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day\n"))),(0,r.kt)("p",null,"Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer."),(0,r.kt)("h3",{id:"trustingperiodfraction"},"TrustingPeriodFraction"),(0,r.kt)("p",null,"is used to calculate the ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriod")," of created IBC clients on both provider and consumer chains. "),(0,r.kt)("p",null,"Setting ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriodFraction")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"0.5")," would result in the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"TrustingPeriodFraction = 0.5\nProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5\nConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5\n")),(0,r.kt)("p",null,"Note that a light clients must be updated within the ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriod")," in order to avoid being frozen."),(0,r.kt)("p",null,"For more details, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/client/ics-007-tendermint-client/README.md"},"IBC specification of Tendermint clients"),"."),(0,r.kt)("h3",{id:"ccvtimeoutperiod"},"CCVTimeoutPeriod"),(0,r.kt)("p",null,"is the period used to compute the timeout timestamp when sending IBC packets. "),(0,r.kt)("p",null,"For more details, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/core/ics-004-channel-and-packet-semantics/README.md#sending-packets"},"IBC specification of Channel & Packet Semantics"),"."),(0,r.kt)("admonition",{type:"warning"},(0,r.kt)("p",{parentName:"admonition"},"If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed.")),(0,r.kt)("p",null,"CCVTimeoutPeriod may have different values on the provider and consumer chains."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"CCVTimeoutPeriod")," on the provider ",(0,r.kt)("strong",{parentName:"li"},"must")," be larger than ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerUnbondingPeriod")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"CCVTimeoutPeriod")," on the consumer is initial set via the ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal"))),(0,r.kt)("h3",{id:"inittimeoutperiod"},"InitTimeoutPeriod"),(0,r.kt)("p",null,"is the maximum allowed duration for CCV channel initialization to execute."),(0,r.kt)("p",null,"For any consumer chain, if the CCV channel is not established within ",(0,r.kt)("inlineCode",{parentName:"p"},"InitTimeoutPeriod")," then the consumer chain will be removed and therefore will not be secured by the provider chain."),(0,r.kt)("p",null,"The countdown starts when the ",(0,r.kt)("inlineCode",{parentName:"p"},"spawn_time")," specified in the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," is reached."),(0,r.kt)("h3",{id:"vsctimeoutperiod"},(0,r.kt)("inlineCode",{parentName:"h3"},"VscTimeoutPeriod")),(0,r.kt)("p",null,"is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live.\nIf the ",(0,r.kt)("inlineCode",{parentName:"p"},"VscTimeoutPeriod")," is ever reached for a consumer chain that chain will be considered not live and removed from interchain security."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"VscTimeoutPeriod")," MUST be larger than the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerUnbondingPeriod"),".")),(0,r.kt)("h3",{id:"blocksperdistributiontransmission"},"BlocksPerDistributionTransmission"),(0,r.kt)("p",null,"is the number of blocks between rewards transfers from the consumer to the provider."),(0,r.kt)("h3",{id:"transferperiodtimeout"},"TransferPeriodTimeout"),(0,r.kt)("p",null,"is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider."),(0,r.kt)("p",null,"If this timeout expires, then the transfer is attempted again after ",(0,r.kt)("inlineCode",{parentName:"p"},"BlocksPerDistributionTransmission")," blocks."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"TransferPeriodTimeout")," on the consumer is initial set via the ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal")," gov proposal to add the consumer"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"TransferPeriodTimeout")," should be smaller than ",(0,r.kt)("inlineCode",{parentName:"li"},"BlocksPerDistributionTransmission x avg_block_time"))),(0,r.kt)("h2",{id:"slash-throttle-parameters"},"Slash Throttle Parameters"),(0,r.kt)("h3",{id:"slashmeterreplenishperiod"},"SlashMeterReplenishPeriod"),(0,r.kt)("p",null,"exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed."),(0,r.kt)("p",null,"The meter is replenished to an amount equal to the slash meter allowance for that block, or ",(0,r.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction * CurrentTotalVotingPower"),"."),(0,r.kt)("h3",{id:"slashmeterreplenishfraction"},"SlashMeterReplenishFraction"),(0,r.kt)("p",null,"exists on the provider as the portion (in range ","[0, 1]",") of total voting power that is replenished to the slash meter when a replenishment occurs."),(0,r.kt)("p",null,"This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a ",(0,r.kt)("inlineCode",{parentName:"p"},"sdk.Dec")," when used."),(0,r.kt)("h3",{id:"maxthrottledpackets"},"MaxThrottledPackets"),(0,r.kt)("p",null,"exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value."),(0,r.kt)("p",null,"This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/3739a4c2.c9f8167e.js b/legacy/assets/js/3739a4c2.c9f8167e.js new file mode 100644 index 0000000000..10fc6f1e96 --- /dev/null +++ b/legacy/assets/js/3739a4c2.c9f8167e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8935],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>m});var i=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,i)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?r(Object(a),!0).forEach((function(t){n(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):r(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function l(e,t){if(null==e)return{};var a,i,n=function(e,t){if(null==e)return{};var a,i,n={},r=Object.keys(e);for(i=0;i<r.length;i++)a=r[i],t.indexOf(a)>=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)a=r[i],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var s=i.createContext({}),h=function(e){var t=i.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},d=function(e){var t=h(e.components);return i.createElement(s.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},u=i.forwardRef((function(e,t){var a=e.components,n=e.mdxType,r=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=h(a),u=n,m=c["".concat(s,".").concat(u)]||c[u]||p[u]||r;return a?i.createElement(m,o(o({ref:t},d),{},{components:a})):i.createElement(m,o({ref:t},d))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=a.length,o=new Array(r);o[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:n,o[1]=l;for(var h=2;h<r;h++)o[h]=a[h];return i.createElement.apply(null,o)}return i.createElement.apply(null,a)}u.displayName="MDXCreateElement"},9187:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>p,frontMatter:()=>r,metadata:()=>l,toc:()=>h});var i=a(7462),n=(a(7294),a(3905));const r={sidebar_position:3,title:"Jail Throttling"},o="ADR 002: Jail Throttling",l={unversionedId:"adrs/adr-002-throttle",id:"version-v3.2.0/adrs/adr-002-throttle",title:"Jail Throttling",description:"Changelog",source:"@site/versioned_docs/version-v3.2.0/adrs/adr-002-throttle.md",sourceDirName:"adrs",slug:"/adrs/adr-002-throttle",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-002-throttle",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Jail Throttling"},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-001-key-assignment"},next:{title:"Equivocation governance proposal",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-003-equivocation-gov-proposal"}},s={},h=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"State Required - Slash Meter",id:"state-required---slash-meter",level:3},{value:"State Required - Global entry queue",id:"state-required---global-entry-queue",level:3},{value:"State Required - Per-chain data queue",id:"state-required---per-chain-data-queue",level:3},{value:"Reasoning - Multiple queues",id:"reasoning---multiple-queues",level:3},{value:"Protocol Overview - OnRecvSlashPacket",id:"protocol-overview---onrecvslashpacket",level:3},{value:"Protocol Overview - OnRecvVSCMaturedPacket",id:"protocol-overview---onrecvvscmaturedpacket",level:3},{value:"Endblocker Step 1 - Slash Meter Replenishment",id:"endblocker-step-1---slash-meter-replenishment",level:3},{value:"Endblocker Step 2 - HandleLeadingVSCMaturedPackets",id:"endblocker-step-2---handleleadingvscmaturedpackets",level:3},{value:"Endblocker Step 3 - HandleThrottleQueues",id:"endblocker-step-3---handlethrottlequeues",level:3},{value:"System Properties",id:"system-properties",level:3},{value:"Main Throttling Property",id:"main-throttling-property",level:3},{value:"How Unjailing Affects the Main Throttling Property",id:"how-unjailing-affects-the-main-throttling-property",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],d={toc:h},c="wrapper";function p(e){let{components:t,...a}=e;return(0,n.kt)(c,(0,i.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"adr-002-jail-throttling"},"ADR 002: Jail Throttling"),(0,n.kt)("h2",{id:"changelog"},"Changelog"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"2023-01-26: Initial Draft"),(0,n.kt)("li",{parentName:"ul"},"2023-02-07: Property refined, ADR ready to review/merge")),(0,n.kt)("h2",{id:"status"},"Status"),(0,n.kt)("p",null,"Accepted"),(0,n.kt)("h2",{id:"context"},"Context"),(0,n.kt)("p",null,"The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols. In practice, this assumption may not hold. A malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider."),(0,n.kt)("p",null,"Before the throttling feature was implemented, the following attack was possible. Attacker(s) would create provider validators just below the provider's active set. Using a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once. Control of the provider would then pass over to the attackers' validators. This enables the attacker(s) to halt the provider. Or even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC."),(0,n.kt)("h2",{id:"decision"},"Decision"),(0,n.kt)("p",null,"The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack. Ie. this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time."),(0,n.kt)("h3",{id:"state-required---slash-meter"},"State Required - Slash Meter"),(0,n.kt)("p",null,"There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time. This meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params."),(0,n.kt)("h3",{id:"state-required---global-entry-queue"},"State Required - Global entry queue"),(0,n.kt)("p",null,'There exists a single queue which stores "global slash entries". These entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering. This queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.'),(0,n.kt)("h3",{id:"state-required---per-chain-data-queue"},"State Required - Per-chain data queue"),(0,n.kt)("p",null,'For each established consumer, there exists a queue which stores "throttled packet data". Ie. pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering. Order is enforced by IBC sequence number. These "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.'),(0,n.kt)("h3",{id:"reasoning---multiple-queues"},"Reasoning - Multiple queues"),(0,n.kt)("p",null,"For reasoning on why this feature was implemented with multiple queues, see ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"spec"),". Specifically the section on ",(0,n.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order"),". There are other ways to ensure such a property (like a queue of linked lists, etc.), but the implemented protocol seemed to be the most understandable and easiest to implement with a KV store."),(0,n.kt)("h3",{id:"protocol-overview---onrecvslashpacket"},"Protocol Overview - OnRecvSlashPacket"),(0,n.kt)("p",null,"Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"A global slash entry is queued."),(0,n.kt)("li",{parentName:"ol"},"The data of such a packet is added to the per-chain queue.")),(0,n.kt)("h3",{id:"protocol-overview---onrecvvscmaturedpacket"},"Protocol Overview - OnRecvVSCMaturedPacket"),(0,n.kt)("p",null,"Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue."),(0,n.kt)("h3",{id:"endblocker-step-1---slash-meter-replenishment"},"Endblocker Step 1 - Slash Meter Replenishment"),(0,n.kt)("p",null,"Once the slash meter becomes not full, it'll be replenished after ",(0,n.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishPeriod (param)")," by incrementing the meter with its allowance for the replenishment block, where ",(0,n.kt)("inlineCode",{parentName:"p"},"allowance")," = ",(0,n.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction (param)")," * ",(0,n.kt)("inlineCode",{parentName:"p"},"currentTotalVotingPower"),". The slash meter will never exceed its current allowance (fn of the total voting power for the block) in value. Note a few things:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power. In such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods."),(0,n.kt)("li",{parentName:"ol"},"Total voting power of a chain changes over time, especially as validators are jailed. As validators are jailed, total voting power decreases, and so does the jailing allowance. See below for more detailed throttling property discussion."),(0,n.kt)("li",{parentName:"ol"},"The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1. If the ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction (param)")," is set too low, integer rounding will put this minimum value into effect. That is, if ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," * ",(0,n.kt)("inlineCode",{parentName:"li"},"currentTotalVotingPower")," < 1, then the effective allowance would be 1. This min value of allowance ensures that there's some packets handled over time, even if that is a very long time. It's a crude solution to an edge case caused by too small of a replenishment fraction.")),(0,n.kt)("p",null,"The behavior described above is achieved by executing ",(0,n.kt)("inlineCode",{parentName:"p"},"CheckForSlashMeterReplenishment()")," every endblock, BEFORE ",(0,n.kt)("inlineCode",{parentName:"p"},"HandleThrottleQueues()")," is executed."),(0,n.kt)("h3",{id:"endblocker-step-2---handleleadingvscmaturedpackets"},"Endblocker Step 2 - HandleLeadingVSCMaturedPackets"),(0,n.kt)("p",null,'Every block it is possible that VSCMatured packet data was queued before any slash packet data. Since this "leading" VSCMatured packet data does not have to be throttled (see ',(0,n.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order"),"), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes."),(0,n.kt)("h3",{id:"endblocker-step-3---handlethrottlequeues"},"Endblocker Step 3 - HandleThrottleQueues"),(0,n.kt)("p",null,"Every endblocker the following pseudo-code is executed to handle data from the throttle queues."),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-typescript"},"meter := getSlashMeter()\n\n// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist \nwhile meter.IsPositiveOrZero() && entriesExist() {\n // Get next entry in queue\n entry := getNextGlobalSlashEntry()\n // Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet\n valPower := entry.getValPower()\n meter = meter - valPower\n // Using the per-chain queue, handle the single slash packet using its queued data,\n // then handle all trailing VSCMatured packets for this consumer\n handleSlashPacketAndTrailingVSCMaturedPackets(entry)\n // Delete entry in global queue, delete handled data\n entry.Delete()\n deleteThrottledSlashPacketData()\n deleteTrailingVSCMaturedPacketData()\n}\n")),(0,n.kt)("h3",{id:"system-properties"},"System Properties"),(0,n.kt)("p",null,"All CCV system properties should be maintained by implementing this feature, see: ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"CCV spec - Consumer Initiated Slashing"),"."),(0,n.kt)("p",null,"One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than ",(0,n.kt)("inlineCode",{parentName:"p"},"MaxThrottledPackets (param)"),", then the provider binary will panic, and the provider chain will halt. Therefore this param should be set carefully. See ",(0,n.kt)("inlineCode",{parentName:"p"},"SetThrottledPacketDataSize"),". This behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators."),(0,n.kt)("h3",{id:"main-throttling-property"},"Main Throttling Property"),(0,n.kt)("p",null,"Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions."),(0,n.kt)("p",null,"First, we define the following:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},'A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.'),(0,n.kt)("li",{parentName:"ul"},'The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.'),(0,n.kt)("li",{parentName:"ul"},"There is a list of honest validators s.t if they are jailed, ",(0,n.kt)("inlineCode",{parentName:"li"},"X"),"% of the initial validator set will be jailed.")),(0,n.kt)("p",null,"For the following property to hold, these assumptions must be true:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack."),(0,n.kt)("li",{parentName:"ol"},"No validator has more than ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," of total voting power on the provider."),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," is large enough that ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," * ",(0,n.kt)("inlineCode",{parentName:"li"},"currentTotalVotingPower")," > 1. Ie. the replenish fraction is set high enough that we can ignore the effects of rounding."),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishPeriod")," is sufficiently longer than the time it takes to produce a block.")),(0,n.kt)("p",null,(0,n.kt)("em",{parentName:"p"},"Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined.")),(0,n.kt)("p",null,"Property:"),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"The time it takes to jail/tombstone ",(0,n.kt)("inlineCode",{parentName:"p"},"X"),"% of the initial validator set will be greater than or equal to ",(0,n.kt)("inlineCode",{parentName:"p"},"(X * SlashMeterReplenishPeriod / SlashMeterReplenishFraction) - 2 * SlashMeterReplenishPeriod"))),(0,n.kt)("p",null,"Intuition:"),(0,n.kt)("p",null,"Let's use the following notation:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"$C$: Number of replenishment cycles"),(0,n.kt)("li",{parentName:"ul"},"$P$: $\\text{SlashMeterReplenishPeriod}$"),(0,n.kt)("li",{parentName:"ul"},"$F$: $\\text{SlashMeterReplenishFraction}$"),(0,n.kt)("li",{parentName:"ul"},"$V_{\\mathit{max}}$: Max power of a validator as a fraction of total voting power")),(0,n.kt)("p",null,"In $C$ number of replenishment cycles, the fraction of total voting power that can be removed, $a$, is $a \\leq F \\cdot C + V",(0,n.kt)("em",{parentName:"p"},"{\\mathit{max}}$ (where $V"),"{\\mathit{max}}$ is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value)."),(0,n.kt)("p",null,"So, we need at least $C \\geq \\frac{a - V_{\\mathit{max}}}{F}$ cycles to remove $a$ fraction of the total voting power."),(0,n.kt)("p",null,"Since we defined the start of the attack to be the moment when the first slash request arrives, then $F$ fraction of the initial validator set can be jailed immediately. For the remaining $X - F$ fraction of the initial validator set to be jailed, it takes at least $C \\geq \\frac{(X - F) - V",(0,n.kt)("em",{parentName:"p"},"{\\mathit{max}}}{F}$ cycles. Using the assumption that $V"),"{\\mathit{max}} \\leq F$ (assumption 2), we get $C \\geq \\frac{X - 2F}{F}$ cycles."),(0,n.kt)("p",null,"In order to execute $C$ cycles, we need $C \\cdot P$ time."),(0,n.kt)("p",null,"Thus, jailing the remaining $X - F$ fraction of the initial validator set corresponds to $\\frac{P \\cdot (X - 2F)}{F}$ time."),(0,n.kt)("p",null,"In other words, the attack must take at least $\\frac{P \\cdot X}{F} - 2P$ time (in the units of replenish period $P$)."),(0,n.kt)("p",null,"This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests. For example, if ",(0,n.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction")," is set to 0.06, then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub. Note that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power."),(0,n.kt)("p",null,"Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings."),(0,n.kt)("h3",{id:"how-unjailing-affects-the-main-throttling-property"},"How Unjailing Affects the Main Throttling Property"),(0,n.kt)("p",null,"Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained."),(0,n.kt)("p",null,"If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider."),(0,n.kt)("p",null,"In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack."),(0,n.kt)("h2",{id:"consequences"},"Consequences"),(0,n.kt)("h3",{id:"positive"},"Positive"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"The described attack is slowed down in seemingly all cases."),(0,n.kt)("li",{parentName:"ul"},"If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded.")),(0,n.kt)("h3",{id:"negative"},"Negative"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below. However, this is sacrificing liveness in a edge case scenario for the sake of security. As an improvement, ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/713"},"using retries")," would fully prevent this attack vector.")),(0,n.kt)("h3",{id:"neutral"},"Neutral"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Additional state is introduced to the provider chain."),(0,n.kt)("li",{parentName:"ul"},"VSCMatured and slash packet data is not always handled in the same block that it is received.")),(0,n.kt)("h2",{id:"references"},"References"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/404"},"Original issue inspiring throttling feature")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/594"},"Issue on DOS vector")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/685"},"Consideration of another attack vector"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/37744218.00a8a74e.js b/legacy/assets/js/37744218.00a8a74e.js new file mode 100644 index 0000000000..2d6d2ee705 --- /dev/null +++ b/legacy/assets/js/37744218.00a8a74e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7116],{3905:(e,t,r)=>{r.d(t,{Zo:()=>l,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},l=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),p=u(r),f=o,m=p["".concat(s,".").concat(f)]||p[f]||d[f]||i;return r?n.createElement(m,a(a({ref:t},l),{},{components:r})):n.createElement(m,a({ref:t},l))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[p]="string"==typeof e?e:o,a[1]=c;for(var u=2;u<i;u++)a[u]=r[u];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},4251:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>d,frontMatter:()=>i,metadata:()=>c,toc:()=>u});var n=r(7462),o=(r(7294),r(3905));const i={sidebar_position:5},a="Joining Neutron",c={unversionedId:"validators/joining-neutron",id:"version-v3.3.1-lsm/validators/joining-neutron",title:"Joining Neutron",description:"Neutron is the first consumer chain to implement ICS.",source:"@site/versioned_docs/version-v3.3.1-lsm/validators/joining-neutron.md",sourceDirName:"validators",slug:"/validators/joining-neutron",permalink:"/interchain-security/legacy/validators/joining-neutron",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Validator instructions for Changeover Procedure",permalink:"/interchain-security/legacy/validators/changeover-procedure"},next:{title:"Joining Stride",permalink:"/interchain-security/legacy/validators/joining-stride"}},s={},u=[{value:"Resources",id:"resources",level:2}],l={toc:u},p="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(p,(0,n.Z)({},l,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"joining-neutron"},"Joining Neutron"),(0,o.kt)("p",null,"Neutron is the first consumer chain to implement ICS."),(0,o.kt)("p",null,"You can find instructions on joining the mainnet ",(0,o.kt)("a",{parentName:"p",href:"https://docs.neutron.org/neutron/consumer-chain-launch"},"here"),"."),(0,o.kt)("p",null,"To join Neutron chain on the replicated security testnet check ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security/pion-1"},"here")),(0,o.kt)("h2",{id:"resources"},"Resources"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.neutron.org"},"Neutron docs"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/3a65a150.9e3ed84d.js b/legacy/assets/js/3a65a150.9e3ed84d.js new file mode 100644 index 0000000000..ef6c9df9a8 --- /dev/null +++ b/legacy/assets/js/3a65a150.9e3ed84d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2181],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>m});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),h=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=h(e.components);return r.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),d=h(n),p=a,m=d["".concat(c,".").concat(p)]||d[p]||u[p]||o;return n?r.createElement(m,i(i({ref:t},l),{},{components:n})):r.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=p;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:a,i[1]=s;for(var h=2;h<o;h++)i[h]=n[h];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}p.displayName="MDXCreateElement"},8014:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>h});var r=n(7462),a=(n(7294),n(3905));const o={sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},i=void 0,s={unversionedId:"frequently-asked-questions",id:"version-v3.1.0/frequently-asked-questions",title:"Frequently Asked Questions",description:"What is the meaning of Validator Set Replication?",source:"@site/versioned_docs/version-v3.1.0/frequently-asked-questions.md",sourceDirName:".",slug:"/faq",permalink:"/interchain-security/legacy/v3.1.0/faq",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:5,frontMatter:{sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},sidebar:"tutorialSidebar",previous:{title:"Withdrawing consumer chain validator rewards",permalink:"/interchain-security/legacy/v3.1.0/validators/withdraw_rewards"},next:{title:"ADRs",permalink:"/interchain-security/legacy/v3.1.0/adrs/intro"}},c={},h=[{value:"What is the meaning of Validator Set Replication?",id:"what-is-the-meaning-of-validator-set-replication",level:2},{value:"What even is a consumer chain?",id:"what-even-is-a-consumer-chain",level:2},{value:"What happens to consumer if provider is down?",id:"what-happens-to-consumer-if-provider-is-down",level:2},{value:"What happens to provider if consumer is down?",id:"what-happens-to-provider-if-consumer-is-down",level:2},{value:"Can I run the provider and consumer chains on the same machine?",id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine",level:2},{value:"Can the consumer chain have its own token?",id:"can-the-consumer-chain-have-its-own-token",level:2},{value:"How are Tx fees paid on consumer?",id:"how-are-tx-fees-paid-on-consumer",level:2},{value:"Are there any restrictions the consumer chains need to abide by?",id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by",level:2},{value:"What's in it for the validators and stakers?",id:"whats-in-it-for-the-validators-and-stakers",level:2},{value:"Can the consumer chain have its own governance?",id:"can-the-consumer-chain-have-its-own-governance",level:2},{value:"Can validators opt-out of replicated security?",id:"can-validators-opt-out-of-replicated-security",level:2},{value:"How does Equivocation Governance Slashing work?",id:"how-does-equivocation-governance-slashing-work",level:2},{value:"Can Consumer Chains perform Software Upgrades?",id:"can-consumer-chains-perform-software-upgrades",level:2},{value:"How can I connect to the testnets?",id:"how-can-i-connect-to-the-testnets",level:2},{value:"How do I start using ICS?",id:"how-do-i-start-using-ics",level:2},{value:"Which relayers are supported?",id:"which-relayers-are-supported",level:2},{value:"How does key delegation work in ICS?",id:"how-does-key-delegation-work-in-ics",level:2}],l={toc:h},d="wrapper";function u(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"what-is-the-meaning-of-validator-set-replication"},"What is the meaning of Validator Set Replication?"),(0,a.kt)("p",null,"VSR simply means that the same validator set is used to secure both the provider and consumer chains. VSR is ensured through ICS protocol which keeps consumers up to date with the validator set of the provider."),(0,a.kt)("h2",{id:"what-even-is-a-consumer-chain"},"What even is a consumer chain?"),(0,a.kt)("p",null,"Consumer chain is blockchain operated by the same validator operators as the provider chain. The ICS protocol ensures the validator set replication properties (informs consumer chain about the current state of the validator set on the provider)"),(0,a.kt)("p",null,"Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements."),(0,a.kt)("h2",{id:"what-happens-to-consumer-if-provider-is-down"},"What happens to consumer if provider is down?"),(0,a.kt)("p",null,"In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set."),(0,a.kt)("p",null,"The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness."),(0,a.kt)("p",null,"However, if the ",(0,a.kt)("inlineCode",{parentName:"p"},"trusting_period")," (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain.\nThis means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about."),(0,a.kt)("p",null,'Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point.\nAt the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.'),(0,a.kt)("h2",{id:"what-happens-to-provider-if-consumer-is-down"},"What happens to provider if consumer is down?"),(0,a.kt)("p",null,"Consumer chains do not impact the provider chain.\nThe ICS protocol is concerned only with validator set replication and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events)."),(0,a.kt)("h2",{id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine"},"Can I run the provider and consumer chains on the same machine?"),(0,a.kt)("p",null,"Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation."),(0,a.kt)("h2",{id:"can-the-consumer-chain-have-its-own-token"},"Can the consumer chain have its own token?"),(0,a.kt)("p",null,"As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees."),(0,a.kt)("h2",{id:"how-are-tx-fees-paid-on-consumer"},"How are Tx fees paid on consumer?"),(0,a.kt)("p",null,"The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations."),(0,a.kt)("h2",{id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by"},"Are there any restrictions the consumer chains need to abide by?"),(0,a.kt)("p",null,"No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way.\nThe only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain."),(0,a.kt)("h2",{id:"whats-in-it-for-the-validators-and-stakers"},"What's in it for the validators and stakers?"),(0,a.kt)("p",null,"The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by ",(0,a.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction"),". The rewards are distributed (sent to the provider) every ",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission"),"."),(0,a.kt)("admonition",{type:"note"},(0,a.kt)("p",{parentName:"admonition"}," ",(0,a.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission")," are parameters defined in the ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," used to create the consumer chain. These parameters can be changed via consumer chain governance.")),(0,a.kt)("h2",{id:"can-the-consumer-chain-have-its-own-governance"},"Can the consumer chain have its own governance?"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Yes.")),(0,a.kt)("p",null,'In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.'),(0,a.kt)("p",null,"Validators can also be representatives but representatives are not required to run validator nodes."),(0,a.kt)("p",null,"This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance."),(0,a.kt)("h2",{id:"can-validators-opt-out-of-replicated-security"},"Can validators opt-out of replicated security?"),(0,a.kt)("p",null,"At present, the validators cannot opt-out of validating consumer chains."),(0,a.kt)("p",null,"There are multiple opt-out mechanisms under active research."),(0,a.kt)("h2",{id:"how-does-equivocation-governance-slashing-work"},"How does Equivocation Governance Slashing work?"),(0,a.kt)("p",null,"To avoid potential attacks directed at provider chain validators, a new mechanism was introduced:"),(0,a.kt)("p",null,"When a validator double-signs on the consumer chain, a special type of slash packet is relayed to the provider chain. The provider will store information about the double signing validator and allow a governance proposal to be submitted.\nIf the double-signing proposal passes, the offending validator will be slashed on the provider chain and tombstoned. Tombstoning will permanently exclude the validator from the active set of the provider."),(0,a.kt)("admonition",{type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"An equivocation proposal cannot be submitted for a validator that did not double sign on any of the consumer chains.")),(0,a.kt)("h2",{id:"can-consumer-chains-perform-software-upgrades"},"Can Consumer Chains perform Software Upgrades?"),(0,a.kt)("p",null,"Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM)."),(0,a.kt)("p",null,"Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module."),(0,a.kt)("h2",{id:"how-can-i-connect-to-the-testnets"},"How can I connect to the testnets?"),(0,a.kt)("p",null,"Check out the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.1.0/validators/joining-testnet"},"Joining Replicated Security testnet")," section."),(0,a.kt)("h2",{id:"how-do-i-start-using-ics"},"How do I start using ICS?"),(0,a.kt)("p",null,"To become a consumer chain use this ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.1.0/consumer-development/onboarding"},"checklist")," and check the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.1.0/consumer-development/app-integration"},"App integration section")),(0,a.kt)("h2",{id:"which-relayers-are-supported"},"Which relayers are supported?"),(0,a.kt)("p",null,"Currently supported versions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Hermes 1.4.1")),(0,a.kt)("h2",{id:"how-does-key-delegation-work-in-ics"},"How does key delegation work in ICS?"),(0,a.kt)("p",null,"You can check the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.1.0/features/key-assignment"},"Key Assignment Guide")," for specific instructions."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/3be89897.d5956040.js b/legacy/assets/js/3be89897.d5956040.js new file mode 100644 index 0000000000..f68e9fa94b --- /dev/null +++ b/legacy/assets/js/3be89897.d5956040.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8763],{3905:(e,t,r)=>{r.d(t,{Zo:()=>l,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},l=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),p=u(r),f=o,m=p["".concat(s,".").concat(f)]||p[f]||d[f]||i;return r?n.createElement(m,a(a({ref:t},l),{},{components:r})):n.createElement(m,a({ref:t},l))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[p]="string"==typeof e?e:o,a[1]=c;for(var u=2;u<i;u++)a[u]=r[u];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},1597:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>d,frontMatter:()=>i,metadata:()=>c,toc:()=>u});var n=r(7462),o=(r(7294),r(3905));const i={sidebar_position:5},a="Joining Neutron",c={unversionedId:"validators/joining-neutron",id:"version-v3.3.0/validators/joining-neutron",title:"Joining Neutron",description:"Neutron is the first consumer chain to implement ICS.",source:"@site/versioned_docs/version-v3.3.0/validators/joining-neutron.md",sourceDirName:"validators",slug:"/validators/joining-neutron",permalink:"/interchain-security/legacy/v3.3.0/validators/joining-neutron",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Validator instructions for Changeover Procedure",permalink:"/interchain-security/legacy/v3.3.0/validators/changeover-procedure"},next:{title:"Joining Stride",permalink:"/interchain-security/legacy/v3.3.0/validators/joining-stride"}},s={},u=[{value:"Resources",id:"resources",level:2}],l={toc:u},p="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(p,(0,n.Z)({},l,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"joining-neutron"},"Joining Neutron"),(0,o.kt)("p",null,"Neutron is the first consumer chain to implement ICS."),(0,o.kt)("p",null,"You can find instructions on joining the mainnet ",(0,o.kt)("a",{parentName:"p",href:"https://docs.neutron.org/neutron/consumer-chain-launch"},"here"),"."),(0,o.kt)("p",null,"To join Neutron chain on the replicated security testnet check ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security/pion-1"},"here")),(0,o.kt)("h2",{id:"resources"},"Resources"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.neutron.org"},"Neutron docs"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/3d02a384.3955deea.js b/legacy/assets/js/3d02a384.3955deea.js new file mode 100644 index 0000000000..699582fae6 --- /dev/null +++ b/legacy/assets/js/3d02a384.3955deea.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2584],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>g});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),h=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=h(e.components);return o.createElement(l.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),c=h(n),u=a,g=c["".concat(l,".").concat(u)]||c[u]||p[u]||i;return n?o.createElement(g,r(r({ref:t},d),{},{components:n})):o.createElement(g,r({ref:t},d))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,r=new Array(i);r[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:a,r[1]=s;for(var h=2;h<i;h++)r[h]=n[h];return o.createElement.apply(null,r)}return o.createElement.apply(null,n)}u.displayName="MDXCreateElement"},4718:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>h});var o=n(7462),a=(n(7294),n(3905));const i={sidebar_position:14,title:"Slashing on the provider for consumer equivocation"},r="ADR 013: Slashing on the provider for consumer equivocation",s={unversionedId:"adrs/adr-013-equivocation-slashing",id:"version-v3.2.0/adrs/adr-013-equivocation-slashing",title:"Slashing on the provider for consumer equivocation",description:"Changelog",source:"@site/versioned_docs/version-v3.2.0/adrs/adr-013-equivocation-slashing.md",sourceDirName:"adrs",slug:"/adrs/adr-013-equivocation-slashing",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-013-equivocation-slashing",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:14,frontMatter:{sidebar_position:14,title:"Slashing on the provider for consumer equivocation"},sidebar:"tutorialSidebar",previous:{title:"Separate Releasing",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-012-separate-releasing"}},l={},h=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Single-chain slashing",id:"single-chain-slashing",level:3},{value:"Slashing undelegations and redelegations",id:"slashing-undelegations-and-redelegations",level:4},{value:"Slashing delegations",id:"slashing-delegations",level:4},{value:"Old evidence",id:"old-evidence",level:4},{value:"Slashing for equivocation on the consumer",id:"slashing-for-equivocation-on-the-consumer",level:3},{value:"Proposed solution",id:"proposed-solution",level:2},{value:"Implementation",id:"implementation",level:3},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}],d={toc:h},c="wrapper";function p(e){let{components:t,...n}=e;return(0,a.kt)(c,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-013-slashing-on-the-provider-for-consumer-equivocation"},"ADR 013: Slashing on the provider for consumer equivocation"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"1st Sept. 2023: Initial draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Proposed"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"This ADR presents some approaches on how to slash on the provider chain validators that performed equivocations on consumer chains.\nCurrently, the provider chain can ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232"},"receive and verify evidence of equivocation"),", but it cannot slash the misbehaving validator."),(0,a.kt)("p",null,"In the remainder of this section, we explain how slashing is performed on a single chain and show why slashing on the provider for equivocation on the consumer is challenging."),(0,a.kt)("p",null,"Note that future versions of the Cosmos SDK, CometBFT, and ibc-go could modify the way we slash, etc. Therefore, a future reader of this ADR, should note that when we refer to Cosmos SDK, CometBFT, and ibc-go we specifically refer to their ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/intro/overview"},"v0.47"),", ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cometbft.com/v0.37/"},"v0.37")," and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/v7.3.0"},"v7.3.0")," versions respectively."),(0,a.kt)("h3",{id:"single-chain-slashing"},"Single-chain slashing"),(0,a.kt)("p",null,"Slashing is implemented across the ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/slashing"},"slashing"),"\nand ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/staking"},"staking")," modules.\nThe slashing module's keeper calls the staking module's ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash()")," method, passing among others, the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," (i.e., the height when the equivocation occurred), the validator's ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," at the infraction height, and the ",(0,a.kt)("inlineCode",{parentName:"p"},"slashFactor")," (currently set to ",(0,a.kt)("inlineCode",{parentName:"p"},"5%")," in case of equivocation on the Cosmos Hub)."),(0,a.kt)("h4",{id:"slashing-undelegations-and-redelegations"},"Slashing undelegations and redelegations"),(0,a.kt)("p",null,"To slash undelegations, ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash")," goes through all undelegations and checks whether they started before or after the infraction occurred. If an undelegation started before the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight"),", then it is ",(0,a.kt)("strong",{parentName:"p"},"not")," slashed, otherwise it is slashed by ",(0,a.kt)("inlineCode",{parentName:"p"},"slashFactor"),"."),(0,a.kt)("p",null,"The slashing of redelegations happens in a similar way, meaning that ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash")," goes through all redelegations and checks whether the redelegations started before or after the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight"),"."),(0,a.kt)("h4",{id:"slashing-delegations"},"Slashing delegations"),(0,a.kt)("p",null,"Besides undelegations and redelegations, the validator's delegations need to also be slashed.\nThis is performed by deducting the appropriate amount of tokens from the validator. Note that this deduction is computed based on the voting ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," the misbehaving validator had at the height of the equivocation. As a result of the tokens deduction,\nthe ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/staking#delegator-shares"},"tokens per share"),"\nreduce and hence later on, when delegators undelegate or redelegate, the delegators retrieve back less\ntokens, effectively having their tokens slashed. The rationale behind this slashing mechanism, as mentioned in the ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/staking#delegator-shares"},"Cosmos SDK documentation")," "),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"[...]"," is to simplify the accounting around slashing. Rather than iteratively slashing the tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, effectively reducing the value of each issued delegator share.")),(0,a.kt)("p",null,"This approach of slashing delegations does not utilize the\n",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," in any way and hence the following scenario could occur:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"a validator ",(0,a.kt)("inlineCode",{parentName:"li"},"V")," performs an equivocation at a height ",(0,a.kt)("inlineCode",{parentName:"li"},"Hi")),(0,a.kt)("li",{parentName:"ol"},"a new delegator ",(0,a.kt)("inlineCode",{parentName:"li"},"D")," delegates to ",(0,a.kt)("inlineCode",{parentName:"li"},"V")," after height ",(0,a.kt)("inlineCode",{parentName:"li"},"Hi")),(0,a.kt)("li",{parentName:"ol"},"evidence of the equivocation by validator ",(0,a.kt)("inlineCode",{parentName:"li"},"V")," is received"),(0,a.kt)("li",{parentName:"ol"},"the tokens of delegator ",(0,a.kt)("inlineCode",{parentName:"li"},"D")," are slashed")),(0,a.kt)("p",null,"In the above scenario, delegator ",(0,a.kt)("inlineCode",{parentName:"p"},"D")," is slashed, even though ",(0,a.kt)("inlineCode",{parentName:"p"},"D"),"'s voting power did not contribute to the infraction. "),(0,a.kt)("h4",{id:"old-evidence"},"Old evidence"),(0,a.kt)("p",null,"In the single-chain case, old evidence (e.g., from 3 years ago) is ignored. This is achieved through\n",(0,a.kt)("a",{parentName:"p",href:"https://docs.cometbft.com/v0.37/spec/consensus/evidence"},"CometBFT")," that ignores old evidence based on the parameters ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeNumBlocks")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeDuration")," (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.37.0/evidence/pool.go#271"},"here"),").\nAdditionally, note that when the evidence is sent by CometBFT to the application, the evidence is rechecked in the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L54"},"evidence module")," of Cosmos SDK and if it is old, the evidence is ignored.\nIn Cosmos Hub, the ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeNumBlocks")," is set to 1000000 (i.e., ~70 days if we assume we need ~6 sec per block) and ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeDuration")," is set to 172800000000000 ns (i.e., 2 days). Because of this check, we can easily exclude old evidence."),(0,a.kt)("h3",{id:"slashing-for-equivocation-on-the-consumer"},"Slashing for equivocation on the consumer"),(0,a.kt)("p",null,"In the single-chain case, slashing requires both the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and the voting ",(0,a.kt)("inlineCode",{parentName:"p"},"power"),".\nIn order to slash on the provider for an equivocation on a consumer, we need to have both the provider's ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and voting ",(0,a.kt)("inlineCode",{parentName:"p"},"power"),".\nNote that the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," on the consumer chain must be mapped to a height on the provider chain.\nUnless we have a way to find the corresponding ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," on the provider chain, we cannot slash for equivocation on the consumer in the same way as we would slash in the single-chain case."),(0,a.kt)("p",null,"The challenge of figuring out the corresponding ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," values on the provider chain is due to the following trust assumption:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"We trust the consensus layer and validator set of the consumer chains, ",(0,a.kt)("em",{parentName:"li"},"but we do not trust the application layer"),".")),(0,a.kt)("p",null,"As a result, we cannot trust anything that stems from the ",(0,a.kt)("em",{parentName:"p"},"application state")," of a consumer chain."),(0,a.kt)("p",null,"Note that when a relayer or a user sends evidence through a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232"},"MsgSubmitConsumerDoubleVoting")," message, the provider gets access to ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.37.0/types/evidence.go#L35"},"DuplicateVoteEvidence"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-protobuf"},'type DuplicateVoteEvidence struct {\n VoteA *Vote `json:"vote_a"`\n VoteB *Vote `json:"vote_b"`\n\n // abci specific information\n TotalVotingPower int64\n ValidatorPower int64\n Timestamp time.Time\n}\n')),(0,a.kt)("p",null,'The "abci specific information" fields cannot be trusted because they are not signed. Therefore,\nwe can use neither ',(0,a.kt)("inlineCode",{parentName:"p"},"ValidatorPower")," for slashing on the provider chain, nor the ",(0,a.kt)("inlineCode",{parentName:"p"},"Timestamp")," to check the evidence age. We can get the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," from the votes, but this ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," corresponds to the infraction height on the consumer and ",(0,a.kt)("strong",{parentName:"p"},"not")," on the provider chain.\nSimilarly, when a relayer or a user sends evidence through a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/826"},"MsgSubmitConsumerMisbehaviour")," message, the provider gets access to ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/v7.3.0/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79"},"Misbehaviour")," that we cannot use to extract the infraction height, power, or the time on the provider chain."),(0,a.kt)("h2",{id:"proposed-solution"},"Proposed solution"),(0,a.kt)("p",null,"As a first iteration, we propose the following approach. At the moment the provider receives evidence of equivocation on a consumer:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"slash all the undelegations and redelegations using ",(0,a.kt)("inlineCode",{parentName:"li"},"slashFactor"),";"),(0,a.kt)("li",{parentName:"ol"},"slash all delegations using as voting ",(0,a.kt)("inlineCode",{parentName:"li"},"power")," the sum of the voting power of the misbehaving validator and the power of all the ongoing undelegations and redelegations.")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Evidence expiration:")," Additionally, because we cannot infer the actual time of the evidence (i.e., the timestamp of the evidence cannot be trusted), we do not consider ",(0,a.kt)("em",{parentName:"p"},"evidence expiration")," and hence old evidence is never ignored (e.g., the provider would act on 3 year-old evidence of equivocation on a consumer).\nAdditionally, we do not need to store equivocation evidence to avoid slashing a validator more than once, because we ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L94"},"do not slash")," tombstoned validators and we ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L138"},"tombstone")," a validator when slashed."),(0,a.kt)("p",null,"We do not act on evidence that was signed by a validator ",(0,a.kt)("a",{parentName:"p",href:"https://tutorials.cosmos.network/tutorials/9-path-to-prod/3-keys.html#what-validator-keys"},"consensus key")," that is ",(0,a.kt)("em",{parentName:"p"},"pruned")," when we receive the evidence. We prune a validator's consensus key if the validator has assigned a new consumer key (using ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey"),") and an unbonding period on the consumer chain has elapsed (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-001-key-assignment.md"},"key assignment ADR"),"). Note that the provider chain is informed that the unbonding period has elapsed on the consumer when the provider receives a ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCMaturedPacket")," and because of this, if the consumer delays the sending of a ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCMaturedPacket"),", we would delay the pruning of the key as well."),(0,a.kt)("h3",{id:"implementation"},"Implementation"),(0,a.kt)("p",null,"The following logic needs to be added to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232"},"HandleConsumerDoubleVoting")," and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/826"},"HandleConsumerMisbehaviour")," methods:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-go"},"undelegationsInTokens := sdk.NewInt(0)\nfor _, v := range k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validatorAddress) {\n for _, entry := range v.Entries {\n if entry.IsMature(now) && !entry.OnHold() {\n // undelegation no longer eligible for slashing, skip it\n continue\n }\n undelegationsInTokens = undelegationsInTokens.Add(entry.InitialBalance)\n }\n}\n\nredelegationsInTokens := sdk.NewInt(0)\nfor _, v := range k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validatorAddress) {\n for _, entry := range v.Entries {\n if entry.IsMature(now) && !entry.OnHold() {\n // redelegation no longer eligible for slashing, skip it\n continue\n }\n redelegationsInTokens = redelegationsInTokens.Add(entry.InitialBalance)\n }\n}\n\ninfractionHeight := 0\nundelegationsAndRedelegationsInPower = sdk.TokensToConsensusPower(undelegationsInTokens.Add(redelegationsInTokens))\ntotalPower := validator's voting power + undelegationsAndRedelegationsInPower\nslashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)\n\nk.stakingKeeper.Slash(ctx, validatorConsAddress, infractionHeight, totalPower, slashFraction, DoubleSign)\n")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Infraction height:")," We provide a zero ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L33"},"Slash")," method in order to slash all ongoing undelegations and redelegations (see checks in ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L92"},"Slash"),", ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L195"},"SlashUnbondingDelegation"),", and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L249"},"SlashRedelegation"),")."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Power:")," We pass the sum of the voting power of the misbehaving validator when the evidence was received (i.e., at evidence height) and the power of all the ongoing undelegations and redelegations.\nIf we assume that the ",(0,a.kt)("inlineCode",{parentName:"p"},"slashFactor")," is ",(0,a.kt)("inlineCode",{parentName:"p"},"5%"),", then the voting power we pass is ",(0,a.kt)("inlineCode",{parentName:"p"},"power + totalPower(undelegations) + totalPower(redelegations)"),".\nHence, when the ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash")," method slashes all the undelegations and redelegations it would end up with ",(0,a.kt)("inlineCode",{parentName:"p"},"0.05 * power + 0.05 * totalPower(undelegations) + 0.05 * totalPower(redelegations) - 0.05 * totalPower(undelegations) - 0.05 * totalPower(redelegations) = 0.05 * power")," and hence it would slash ",(0,a.kt)("inlineCode",{parentName:"p"},"5%")," of the validator's power when the evidence is received."),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("p",null,"With the proposed approach we can quickly implement slashing functionality on the provider chain for consumer chain equivocations.\nThis approach does not need to change the staking module and therefore does not change in any way how slashing is performed today for a single chain."),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"We ",(0,a.kt)("em",{parentName:"li"},"definitely")," slash more when it comes to undelegations and redelegations because we slash for all of them without considering an ",(0,a.kt)("inlineCode",{parentName:"li"},"infractionHeight"),"."),(0,a.kt)("li",{parentName:"ul"},"We ",(0,a.kt)("em",{parentName:"li"},"potentially")," slash more than what we would have slashed if we knew the voting ",(0,a.kt)("inlineCode",{parentName:"li"},"power")," at the corresponding ",(0,a.kt)("inlineCode",{parentName:"li"},"infractionHeight")," in the provider chain."),(0,a.kt)("li",{parentName:"ul"},"We slash on old evidence of equivocation on a consumer.")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md"},"ADR 005: Cryptographic verification of equivocation evidence")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/732"},"EPIC tracking cryptographic equivocation feature")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://forum.cosmos.network/t/cryptographic-equivocation-slashing-design/11400"},"Cosmos Hub Forum discussion on cryptographic equivocation slashing"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/3e7b8ec9.62220d7f.js b/legacy/assets/js/3e7b8ec9.62220d7f.js new file mode 100644 index 0000000000..da5c46d260 --- /dev/null +++ b/legacy/assets/js/3e7b8ec9.62220d7f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[766],{3905:(e,n,t)=>{t.d(n,{Zo:()=>m,kt:()=>d});var r=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function c(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function i(e,n){if(null==e)return{};var t,r,o=function(e,n){if(null==e)return{};var t,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var s=r.createContext({}),l=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):c(c({},n),e)),t},m=function(e){var n=l(e.components);return r.createElement(s.Provider,{value:n},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},p=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,m=i(e,["components","mdxType","originalType","parentName"]),u=l(t),p=o,d=u["".concat(s,".").concat(p)]||u[p]||h[p]||a;return t?r.createElement(d,c(c({ref:n},m),{},{components:t})):r.createElement(d,c({ref:n},m))}));function d(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,c=new Array(a);c[0]=p;var i={};for(var s in n)hasOwnProperty.call(n,s)&&(i[s]=n[s]);i.originalType=e,i[u]="string"==typeof e?e:o,c[1]=i;for(var l=2;l<a;l++)c[l]=t[l];return r.createElement.apply(null,c)}return r.createElement.apply(null,t)}p.displayName="MDXCreateElement"},8049:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>c,default:()=>h,frontMatter:()=>a,metadata:()=>i,toc:()=>l});var r=t(7462),o=(t(7294),t(3905));const a={sidebar_position:2},c="Consumer Chain Governance",i={unversionedId:"consumer-development/consumer-chain-governance",id:"version-v2.0.0/consumer-development/consumer-chain-governance",title:"Consumer Chain Governance",description:'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.',source:"@site/versioned_docs/version-v2.0.0/consumer-development/consumer-chain-governance.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-chain-governance",permalink:"/interchain-security/legacy/v2.0.0/consumer-development/consumer-chain-governance",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/legacy/v2.0.0/consumer-development/app-integration"},next:{title:"Upgrading Consumer Chains",permalink:"/interchain-security/legacy/v2.0.0/consumer-development/consumer-chain-upgrade-procedure"}},s={},l=[{value:"Democracy module",id:"democracy-module",level:2},{value:"CosmWasm",id:"cosmwasm",level:2},{value:"The Whitelist",id:"the-whitelist",level:2}],m={toc:l},u="wrapper";function h(e){let{components:n,...t}=e;return(0,o.kt)(u,(0,r.Z)({},m,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-chain-governance"},"Consumer Chain Governance"),(0,o.kt)("p",null,'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.'),(0,o.kt)("h2",{id:"democracy-module"},"Democracy module"),(0,o.kt)("p",null,"The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy."),(0,o.kt)("p",null,"Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus."),(0,o.kt)("p",null,"For an example, see the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy"},"Democracy Consumer")),(0,o.kt)("h2",{id:"cosmwasm"},"CosmWasm"),(0,o.kt)("p",null,"There several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain."),(0,o.kt)("p",null,"For an example, see ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/neutron-org/neutron/"},"Neutron"),"."),(0,o.kt)("h2",{id:"the-whitelist"},"The Whitelist"),(0,o.kt)("p",null,"Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/neutron-org/neutron/blob/main/app/proposals_allowlisting.go"},"Neutron's")," whitelist."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/40105847.a4dd3ddb.js b/legacy/assets/js/40105847.a4dd3ddb.js new file mode 100644 index 0000000000..ffb862d0fd --- /dev/null +++ b/legacy/assets/js/40105847.a4dd3ddb.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5721],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>d});var o=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function c(e,n){if(null==e)return{};var t,o,r=function(e,n){if(null==e)return{};var t,o,r={},a=Object.keys(e);for(o=0;o<a.length;o++)t=a[o],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o<a.length;o++)t=a[o],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=o.createContext({}),l=function(e){var n=o.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},u=function(e){var n=l(e.components);return o.createElement(s.Provider,{value:n},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},h=o.forwardRef((function(e,n){var t=e.components,r=e.mdxType,a=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=l(t),h=r,d=p["".concat(s,".").concat(h)]||p[h]||m[h]||a;return t?o.createElement(d,i(i({ref:n},u),{},{components:t})):o.createElement(d,i({ref:n},u))}));function d(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var a=t.length,i=new Array(a);i[0]=h;var c={};for(var s in n)hasOwnProperty.call(n,s)&&(c[s]=n[s]);c.originalType=e,c[p]="string"==typeof e?e:r,i[1]=c;for(var l=2;l<a;l++)i[l]=t[l];return o.createElement.apply(null,i)}return o.createElement.apply(null,t)}h.displayName="MDXCreateElement"},2781:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var o=t(7462),r=(t(7294),t(3905));const a={sidebar_position:1},i="Developing an ICS consumer chain",c={unversionedId:"consumer-development/app-integration",id:"version-v3.3.1-lsm/consumer-development/app-integration",title:"Developing an ICS consumer chain",description:"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.",source:"@site/versioned_docs/version-v3.3.1-lsm/consumer-development/app-integration.md",sourceDirName:"consumer-development",slug:"/consumer-development/app-integration",permalink:"/interchain-security/legacy/consumer-development/app-integration",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/legacy/features/slashing"},next:{title:"Consumer Chain Governance",permalink:"/interchain-security/legacy/consumer-development/consumer-chain-governance"}},s={},l=[{value:"Basic consumer chain",id:"basic-consumer-chain",level:2},{value:"Democracy consumer chain",id:"democracy-consumer-chain",level:2},{value:"Standalone chain to consumer chain changeover",id:"standalone-chain-to-consumer-chain-changeover",level:2}],u={toc:l},p="wrapper";function m(e){let{components:n,...t}=e;return(0,r.kt)(p,(0,o.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"developing-an-ics-consumer-chain"},"Developing an ICS consumer chain"),(0,r.kt)("p",null,"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.\nTo help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications."),(0,r.kt)("h2",{id:"basic-consumer-chain"},"Basic consumer chain"),(0,r.kt)("p",null,"The source code for the example app can be found ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer"},"here"),"."),(0,r.kt)("p",null,"Please note that consumer chains do not implement the staking module - the validator set is replicated from the provider, meaning that the provider and the consumer use the same validator set and their stake on the provider directly determines their stake on the consumer.\nAt present there is no opt-in mechanism available, so all validators of the provider must also validate on the provider chain."),(0,r.kt)("p",null,"Your chain should import the consumer module from ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," and register it in the correct places in your ",(0,r.kt)("inlineCode",{parentName:"p"},"app.go"),".\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in.\nYou should not need to manage or override any code from the ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module."),(0,r.kt)("h2",{id:"democracy-consumer-chain"},"Democracy consumer chain"),(0,r.kt)("p",null,"The source code for the example app can be found ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy"},"here"),"."),(0,r.kt)("p",null,"This type of consumer chain wraps the basic CosmosSDK ",(0,r.kt)("inlineCode",{parentName:"p"},"x/distribution"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"x/staking")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"x/governance")," modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system."),(0,r.kt)("p",null,"This allows the consumer chain to leverage those modules while also using the ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module."),(0,r.kt)("p",null,'With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.'),(0,r.kt)("h2",{id:"standalone-chain-to-consumer-chain-changeover"},"Standalone chain to consumer chain changeover"),(0,r.kt)("p",null,"This feature is being actively worked on. Information will be provided at a later time."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/4106f1c5.f7020cca.js b/legacy/assets/js/4106f1c5.f7020cca.js new file mode 100644 index 0000000000..5949d18239 --- /dev/null +++ b/legacy/assets/js/4106f1c5.f7020cca.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[842],{3905:(e,n,t)=>{t.d(n,{Zo:()=>d,kt:()=>m});var i=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function a(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?r(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):r(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,i,o=function(e,n){if(null==e)return{};var t,i,o={},r=Object.keys(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var c=i.createContext({}),l=function(e){var n=i.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):a(a({},n),e)),t},d=function(e){var n=l(e.components);return i.createElement(c.Provider,{value:n},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},h=i.forwardRef((function(e,n){var t=e.components,o=e.mdxType,r=e.originalType,c=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),u=l(t),h=o,m=u["".concat(c,".").concat(h)]||u[h]||p[h]||r;return t?i.createElement(m,a(a({ref:n},d),{},{components:t})):i.createElement(m,a({ref:n},d))}));function m(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var r=t.length,a=new Array(r);a[0]=h;var s={};for(var c in n)hasOwnProperty.call(n,c)&&(s[c]=n[c]);s.originalType=e,s[u]="string"==typeof e?e:o,a[1]=s;for(var l=2;l<r;l++)a[l]=t[l];return i.createElement.apply(null,a)}return i.createElement.apply(null,t)}h.displayName="MDXCreateElement"},2137:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>p,frontMatter:()=>r,metadata:()=>s,toc:()=>l});var i=t(7462),o=(t(7294),t(3905));const r={sidebar_position:4},a="Consumer Initiated Slashing",s={unversionedId:"features/slashing",id:"features/slashing",title:"Consumer Initiated Slashing",description:"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.",source:"@site/docs/features/slashing.md",sourceDirName:"features",slug:"/features/slashing",permalink:"/interchain-security/legacy/features/slashing",draft:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"ICS Provider Proposals",permalink:"/interchain-security/legacy/features/proposals"},next:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/legacy/consumer-development/app-integration"}},c={},l=[{value:"Downtime infractions",id:"downtime-infractions",level:2},{value:"Double-signing (equivocation)",id:"double-signing-equivocation",level:2}],d={toc:l},u="wrapper";function p(e){let{components:n,...t}=e;return(0,o.kt)(u,(0,i.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-initiated-slashing"},"Consumer Initiated Slashing"),(0,o.kt)("p",null,"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.\nIn essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake)."),(0,o.kt)("p",null,"To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized.\nAny infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains."),(0,o.kt)("p",null,"In the current implementation there are 2 important changes brought by the interchain security module:"),(0,o.kt)("h2",{id:"downtime-infractions"},"Downtime infractions"),(0,o.kt)("p",null,"reported by consumer chains are acted upon on the provider as soon as the provider receives the infraction evidence."),(0,o.kt)("p",null,"Instead of slashing, the provider will only jail offending validator for the duration of time established in the chain parameters."),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Slash throttling (sometimes called jail throttling) mechanism ensures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider.")),(0,o.kt)("h2",{id:"double-signing-equivocation"},"Double-signing (equivocation)"),(0,o.kt)("p",null,"infractions are not acted upon immediately."),(0,o.kt)("p",null,"Upon receiving double signing evidence, the provider chain will take note of the evidence and allow for ",(0,o.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," to be submitted to slash the offending validator.\nAny ",(0,o.kt)("inlineCode",{parentName:"p"},"EquivocationProposal"),"s to slash a validator that has not double signed on any of the consumer chains will be automatically rejected by the provider chain."),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"The offending validator will only be slashed (and tombstoned) if an ",(0,o.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," is accepted and passed through governance."),(0,o.kt)("p",{parentName:"admonition"},"The offending validator will effectively get slashed and tombstoned on all consumer chains.")),(0,o.kt)("p",null,"You can find instructions on creating ",(0,o.kt)("inlineCode",{parentName:"p"},"EquivocationProposal"),"s ",(0,o.kt)("a",{parentName:"p",href:"./proposals#equivocationproposal"},"here"),"."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/4255538f.d2560f60.js b/legacy/assets/js/4255538f.d2560f60.js new file mode 100644 index 0000000000..aa21734b38 --- /dev/null +++ b/legacy/assets/js/4255538f.d2560f60.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1535],{3905:(e,r,t)=>{t.d(r,{Zo:()=>l,kt:()=>h});var n=t(7294);function i(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function o(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function a(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?o(Object(t),!0).forEach((function(r){i(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function s(e,r){if(null==e)return{};var t,n,i=function(e,r){if(null==e)return{};var t,n,i={},o=Object.keys(e);for(n=0;n<o.length;n++)t=o[n],r.indexOf(t)>=0||(i[t]=e[t]);return i}(e,r);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)t=o[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var d=n.createContext({}),c=function(e){var r=n.useContext(d),t=r;return e&&(t="function"==typeof e?e(r):a(a({},r),e)),t},l=function(e){var r=c(e.components);return n.createElement(d.Provider,{value:r},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},m=n.forwardRef((function(e,r){var t=e.components,i=e.mdxType,o=e.originalType,d=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=c(t),m=i,h=u["".concat(d,".").concat(m)]||u[m]||p[m]||o;return t?n.createElement(h,a(a({ref:r},l),{},{components:t})):n.createElement(h,a({ref:r},l))}));function h(e,r){var t=arguments,i=r&&r.mdxType;if("string"==typeof e||i){var o=t.length,a=new Array(o);a[0]=m;var s={};for(var d in r)hasOwnProperty.call(r,d)&&(s[d]=r[d]);s.originalType=e,s[u]="string"==typeof e?e:i,a[1]=s;for(var c=2;c<o;c++)a[c]=t[c];return n.createElement.apply(null,a)}return n.createElement.apply(null,t)}m.displayName="MDXCreateElement"},1235:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>d,contentTitle:()=>a,default:()=>p,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var n=t(7462),i=(t(7294),t(3905));const o={sidebar_position:2},a="Reward distribution",s={unversionedId:"features/reward-distribution",id:"version-v3.3.1-lsm/features/reward-distribution",title:"Reward distribution",description:"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.",source:"@site/versioned_docs/version-v3.3.1-lsm/features/reward-distribution.md",sourceDirName:"features",slug:"/features/reward-distribution",permalink:"/interchain-security/legacy/features/reward-distribution",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/legacy/features/key-assignment"},next:{title:"ICS Provider Proposals",permalink:"/interchain-security/legacy/features/proposals"}},d={},c=[{value:"Note",id:"note",level:2},{value:"Instructions for adding a denom",id:"instructions-for-adding-a-denom",level:3},{value:"Parameters",id:"parameters",level:2},{value:"<code>consumer_redistribution_fraction</code>",id:"consumer_redistribution_fraction",level:3},{value:"<code>blocks_per_distribution_transmission</code>",id:"blocks_per_distribution_transmission",level:3},{value:"<code>transfer_timeout_period</code>",id:"transfer_timeout_period",level:3},{value:"<code>distribution_transmission_channel</code>",id:"distribution_transmission_channel",level:3},{value:"<code>provider_fee_pool_addr_str</code>",id:"provider_fee_pool_addr_str",level:3}],l={toc:c},u="wrapper";function p(e){let{components:r,...t}=e;return(0,i.kt)(u,(0,n.Z)({},l,t,{components:r,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"reward-distribution"},"Reward distribution"),(0,i.kt)("p",null,"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.\nIn replicated security block rewards and fees are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel that gets created during consumer chain initialization."),(0,i.kt)("p",null,"Reward distribution on the provider is handled by the distribution module - validators and delegators receive a fraction of the consumer chain tokens as staking rewards.\nThe distributed reward tokens are IBC tokens and therefore cannot be staked on the provider chain."),(0,i.kt)("p",null,"Sending and distributing rewards from consumer chains to provider chain is handled by the ",(0,i.kt)("inlineCode",{parentName:"p"},"Reward Distribution")," sub-protocol."),(0,i.kt)("h2",{id:"note"},"Note"),(0,i.kt)("p",null,"The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerRewardsPool"),".\nThere is a new transaction type called ",(0,i.kt)("inlineCode",{parentName:"p"},"RegisterConsumerRewardDenom"),". This transaction allows consumer chains to register denoms to be used as consumer chain rewards on the provider.\nThe cost to register a denom is configurable (",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerRewardDenomRegistrationFee")," chain param) and the full amount of this fee is transferred to the community pool of the provider chain. Only denoms registered through this transaction are then transferred from the ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerRewardsPool")," to the ",(0,i.kt)("inlineCode",{parentName:"p"},"FeePoolAddress"),", to be distributed out to delegators and validators."),(0,i.kt)("h3",{id:"instructions-for-adding-a-denom"},"Instructions for adding a denom"),(0,i.kt)("p",null,"The transaction must be carried out on the provider chain. Please use the ",(0,i.kt)("inlineCode",{parentName:"p"},"ibc/*")," denom trace format."),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre"},"# reward denoms must be registered on the provider chain (gaia in this example)\ngaiad tx provider register-consumer-reward-denom ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9 --from mykey\n"))),(0,i.kt)("h2",{id:"parameters"},"Parameters"),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"The following chain parameters dictate consumer chain distribution amount and frequency.\nThey are set at consumer genesis and ",(0,i.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction"),"\n",(0,i.kt)("inlineCode",{parentName:"p"},"transfer_timeout_period")," must be provided in every ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerChainAddition")," proposal.")),(0,i.kt)("h3",{id:"consumer_redistribution_fraction"},(0,i.kt)("inlineCode",{parentName:"h3"},"consumer_redistribution_fraction")),(0,i.kt)("p",null,'The fraction of tokens allocated to the consumer redistribution address during distribution events. The fraction is a string representing a decimal number. For example "0.75" would represent 75%.'),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"Example:"),(0,i.kt)("p",{parentName:"admonition"},"With ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction")," set to ",(0,i.kt)("inlineCode",{parentName:"p"},"0.75")," the consumer chain would send 75% of its block rewards and accumulated fees to the consumer redistribution address, and the remaining 25% to the provider chain every ",(0,i.kt)("inlineCode",{parentName:"p"},"n")," blocks where ",(0,i.kt)("inlineCode",{parentName:"p"},"n == blocks_per_distribution_transmission"),".")),(0,i.kt)("h3",{id:"blocks_per_distribution_transmission"},(0,i.kt)("inlineCode",{parentName:"h3"},"blocks_per_distribution_transmission")),(0,i.kt)("p",null,"The number of blocks between IBC token transfers from the consumer chain to the provider chain."),(0,i.kt)("h3",{id:"transfer_timeout_period"},(0,i.kt)("inlineCode",{parentName:"h3"},"transfer_timeout_period")),(0,i.kt)("p",null,"Timeout period for consumer chain reward distribution IBC packets."),(0,i.kt)("h3",{id:"distribution_transmission_channel"},(0,i.kt)("inlineCode",{parentName:"h3"},"distribution_transmission_channel")),(0,i.kt)("p",null,"Provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."),(0,i.kt)("h3",{id:"provider_fee_pool_addr_str"},(0,i.kt)("inlineCode",{parentName:"h3"},"provider_fee_pool_addr_str")),(0,i.kt)("p",null,"Provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/425bba28.bf7a9987.js b/legacy/assets/js/425bba28.bf7a9987.js new file mode 100644 index 0000000000..812c073c68 --- /dev/null +++ b/legacy/assets/js/425bba28.bf7a9987.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1118],{3905:(e,r,n)=>{n.d(r,{Zo:()=>u,kt:()=>h});var t=n(7294);function o(e,r,n){return r in e?Object.defineProperty(e,r,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[r]=n,e}function a(e,r){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);r&&(t=t.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),n.push.apply(n,t)}return n}function i(e){for(var r=1;r<arguments.length;r++){var n=null!=arguments[r]?arguments[r]:{};r%2?a(Object(n),!0).forEach((function(r){o(e,r,n[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(n,r))}))}return e}function s(e,r){if(null==e)return{};var n,t,o=function(e,r){if(null==e)return{};var n,t,o={},a=Object.keys(e);for(t=0;t<a.length;t++)n=a[t],r.indexOf(n)>=0||(o[n]=e[n]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(t=0;t<a.length;t++)n=a[t],r.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=t.createContext({}),l=function(e){var r=t.useContext(c),n=r;return e&&(n="function"==typeof e?e(r):i(i({},r),e)),n},u=function(e){var r=l(e.components);return t.createElement(c.Provider,{value:r},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var r=e.children;return t.createElement(t.Fragment,{},r)}},m=t.forwardRef((function(e,r){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=l(n),m=o,h=d["".concat(c,".").concat(m)]||d[m]||p[m]||a;return n?t.createElement(h,i(i({ref:r},u),{},{components:n})):t.createElement(h,i({ref:r},u))}));function h(e,r){var n=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=m;var s={};for(var c in r)hasOwnProperty.call(r,c)&&(s[c]=r[c]);s.originalType=e,s[d]="string"==typeof e?e:o,i[1]=s;for(var l=2;l<a;l++)i[l]=n[l];return t.createElement.apply(null,i)}return t.createElement.apply(null,n)}m.displayName="MDXCreateElement"},2393:(e,r,n)=>{n.r(r),n.d(r,{assets:()=>c,contentTitle:()=>i,default:()=>p,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var t=n(7462),o=(n(7294),n(3905));const a={sidebar_position:6},i="Consumer Genesis Transformation",s={unversionedId:"consumer-development/consumer-genesis-transformation",id:"consumer-development/consumer-genesis-transformation",title:"Consumer Genesis Transformation",description:"Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentaion on Onboarding and Changeover).",source:"@site/docs/consumer-development/consumer-genesis-transformation.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-genesis-transformation",permalink:"/interchain-security/legacy/consumer-development/consumer-genesis-transformation",draft:!1,tags:[],version:"current",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"tutorialSidebar",previous:{title:"Changeover Procedure",permalink:"/interchain-security/legacy/consumer-development/changeover-procedure"},next:{title:"Overview",permalink:"/interchain-security/legacy/validators/overview"}},c={},l=[{value:"1. Prerequisite",id:"1-prerequisite",level:2},{value:"2. Export the CCV data",id:"2-export-the-ccv-data",level:2},{value:"3. Transform CCV data",id:"3-transform-ccv-data",level:2}],u={toc:l},d="wrapper";function p(e){let{components:r,...n}=e;return(0,o.kt)(d,(0,t.Z)({},u,n,{components:r,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-genesis-transformation"},"Consumer Genesis Transformation"),(0,o.kt)("p",null,"Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentaion on ",(0,o.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/onboarding"},"Onboarding")," and ",(0,o.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/changeover-procedure"},"Changeover"),").\nIn case that the provider chain is running an older version of the InterChainSecurity (ICS) module than the consumer chain the exported CCV data might need to be transformed to the format supported by the ICS implementation run on the consumer chain. This is the case if the cosumer chain runs version 4 of ICS or later and the provider is running version 3 or older of the ICS module."),(0,o.kt)("p",null,"To transform such CCV data follow the instructions below"),(0,o.kt)("h2",{id:"1-prerequisite"},"1. Prerequisite"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Provider chain is running version 3 or older of the ICS provider module"),(0,o.kt)("li",{parentName:"ul"},"Consumer is running version 4 or later of the ICS consumer module."),(0,o.kt)("li",{parentName:"ul"},"interchain-security-cd application complies to the version run on the consumer chain")),(0,o.kt)("h2",{id:"2-export-the-ccv-data"},"2. Export the CCV data"),(0,o.kt)("p",null,"Export the CCV data from the provider chain as descibed in the ",(0,o.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/onboarding"},"Onboarding")," and ",(0,o.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/changeover-procedure"},"Changeover"),") your following.\nAs a result the CCV data will be stored in a file in JSON format."),(0,o.kt)("h2",{id:"3-transform-ccv-data"},"3. Transform CCV data"),(0,o.kt)("p",null,"To transform the CCV data to the newer format run the following command."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"interchain-security-cd genesis transform [genesis-file]\n")),(0,o.kt)("p",null,"where 'genesis-file' is the path to the file containing the CCV data exported in ",(0,o.kt)("a",{parentName:"p",href:"#2-export-the-ccv-data"},"step 2"),".\nAs a result the CCV data in the new format will be written to standard output."),(0,o.kt)("p",null,"Use the new CCV data as described in the procedure you're following."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/432d4f39.d0758794.js b/legacy/assets/js/432d4f39.d0758794.js new file mode 100644 index 0000000000..1d470ac23d --- /dev/null +++ b/legacy/assets/js/432d4f39.d0758794.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6239],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var i=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,i,r=function(e,t){if(null==e)return{};var n,i,r={},o=Object.keys(e);for(i=0;i<o.length;i++)n=o[i],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i<o.length;i++)n=o[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=i.createContext({}),d=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=d(e.components);return i.createElement(l.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},u=i.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),c=d(n),u=r,h=c["".concat(l,".").concat(u)]||c[u]||m[u]||o;return n?i.createElement(h,a(a({ref:t},p),{},{components:n})):i.createElement(h,a({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,a=new Array(o);a[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:r,a[1]=s;for(var d=2;d<o;d++)a[d]=n[d];return i.createElement.apply(null,a)}return i.createElement.apply(null,n)}u.displayName="MDXCreateElement"},1005:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>m,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var i=n(7462),r=(n(7294),n(3905));const o={sidebar_position:3},a="Interchain Security Parameters",s={unversionedId:"introduction/params",id:"version-v3.3.0/introduction/params",title:"Interchain Security Parameters",description:"The parameters necessary for Interchain Security (ICS) are defined in",source:"@site/versioned_docs/version-v3.3.0/introduction/params.md",sourceDirName:"introduction",slug:"/introduction/params",permalink:"/interchain-security/legacy/v3.3.0/introduction/params",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Terminology",permalink:"/interchain-security/legacy/v3.3.0/introduction/terminology"},next:{title:"Technical Specification",permalink:"/interchain-security/legacy/v3.3.0/introduction/technical-specification"}},l={},d=[{value:"Time-based parameters",id:"time-based-parameters",level:2},{value:"ProviderUnbondingPeriod",id:"providerunbondingperiod",level:3},{value:"ConsumerUnbondingPeriod",id:"consumerunbondingperiod",level:3},{value:"TrustingPeriodFraction",id:"trustingperiodfraction",level:3},{value:"CCVTimeoutPeriod",id:"ccvtimeoutperiod",level:3},{value:"InitTimeoutPeriod",id:"inittimeoutperiod",level:3},{value:"VscTimeoutPeriod",id:"vsctimeoutperiod",level:3},{value:"BlocksPerDistributionTransmission",id:"blocksperdistributiontransmission",level:3},{value:"TransferPeriodTimeout",id:"transferperiodtimeout",level:3},{value:"Slash Throttle Parameters",id:"slash-throttle-parameters",level:2},{value:"SlashMeterReplenishPeriod",id:"slashmeterreplenishperiod",level:3},{value:"SlashMeterReplenishFraction",id:"slashmeterreplenishfraction",level:3},{value:"MaxThrottledPackets",id:"maxthrottledpackets",level:3},{value:"RetryDelayPeriod",id:"retrydelayperiod",level:3}],p={toc:d},c="wrapper";function m(e){let{components:t,...n}=e;return(0,r.kt)(c,(0,i.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"interchain-security-parameters"},"Interchain Security Parameters"),(0,r.kt)("p",null,"The parameters necessary for Interchain Security (ICS) are defined in "),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"the ",(0,r.kt)("inlineCode",{parentName:"li"},"Params")," structure in ",(0,r.kt)("inlineCode",{parentName:"li"},"proto/interchain_security/ccv/provider/v1/provider.proto")," for the provider;"),(0,r.kt)("li",{parentName:"ul"},"the ",(0,r.kt)("inlineCode",{parentName:"li"},"Params")," structure in ",(0,r.kt)("inlineCode",{parentName:"li"},"proto/interchain_security/ccv/consumer/v1/consumer.proto")," for the consumer.")),(0,r.kt)("h2",{id:"time-based-parameters"},"Time-based parameters"),(0,r.kt)("p",null,"ICS relies on the following time-based parameters."),(0,r.kt)("h3",{id:"providerunbondingperiod"},"ProviderUnbondingPeriod"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"ProviderUnbondingPeriod")," is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance."),(0,r.kt)("h3",{id:"consumerunbondingperiod"},"ConsumerUnbondingPeriod"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerUnbondingPeriod")," is the unbonding period on the consumer chain."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerUnbondingPeriod")," is set via the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," governance proposal to add a new consumer chain.\nIt is recommended that every consumer chain set and unbonding period shorter than ",(0,r.kt)("inlineCode",{parentName:"p"},"ProviderUnbondingPeriod")),(0,r.kt)("br",null),(0,r.kt)("p",{parentName:"admonition"},"Example:"),(0,r.kt)("pre",{parentName:"admonition"},(0,r.kt)("code",{parentName:"pre"},"ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day\n"))),(0,r.kt)("p",null,"Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer."),(0,r.kt)("h3",{id:"trustingperiodfraction"},"TrustingPeriodFraction"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriodFraction")," is used to calculate the ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriod")," of created IBC clients on both provider and consumer chains. "),(0,r.kt)("p",null,"Setting ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriodFraction")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"0.5")," would result in the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"TrustingPeriodFraction = 0.5\nProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5\nConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5\n")),(0,r.kt)("p",null,"Note that a light clients must be updated within the ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriod")," in order to avoid being frozen."),(0,r.kt)("p",null,"For more details, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/client/ics-007-tendermint-client/README.md"},"IBC specification of Tendermint clients"),"."),(0,r.kt)("h3",{id:"ccvtimeoutperiod"},"CCVTimeoutPeriod"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"CCVTimeoutPeriod")," is the period used to compute the timeout timestamp when sending IBC packets. "),(0,r.kt)("p",null,"For more details, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/core/ics-004-channel-and-packet-semantics/README.md#sending-packets"},"IBC specification of Channel & Packet Semantics"),"."),(0,r.kt)("admonition",{type:"warning"},(0,r.kt)("p",{parentName:"admonition"},"If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed.")),(0,r.kt)("p",null,"CCVTimeoutPeriod may have different values on the provider and consumer chains."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"CCVTimeoutPeriod")," on the provider ",(0,r.kt)("strong",{parentName:"li"},"must")," be larger than ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerUnbondingPeriod")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"CCVTimeoutPeriod")," on the consumer is initial set via the ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal"))),(0,r.kt)("h3",{id:"inittimeoutperiod"},"InitTimeoutPeriod"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"InitTimeoutPeriod")," is the maximum allowed duration for CCV channel initialization to execute."),(0,r.kt)("p",null,"For any consumer chain, if the CCV channel is not established within ",(0,r.kt)("inlineCode",{parentName:"p"},"InitTimeoutPeriod")," then the consumer chain will be removed and therefore will not be secured by the provider chain."),(0,r.kt)("p",null,"The countdown starts when the ",(0,r.kt)("inlineCode",{parentName:"p"},"spawn_time")," specified in the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," is reached."),(0,r.kt)("h3",{id:"vsctimeoutperiod"},"VscTimeoutPeriod"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"VscTimeoutPeriod")," is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live.\nIf the ",(0,r.kt)("inlineCode",{parentName:"p"},"VscTimeoutPeriod")," is ever reached for a consumer chain that chain will be considered not live and removed from interchain security."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"VscTimeoutPeriod")," MUST be larger than the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerUnbondingPeriod"),".")),(0,r.kt)("h3",{id:"blocksperdistributiontransmission"},"BlocksPerDistributionTransmission"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"BlocksPerDistributionTransmission")," is the number of blocks between rewards transfers from the consumer to the provider."),(0,r.kt)("h3",{id:"transferperiodtimeout"},"TransferPeriodTimeout"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"TransferPeriodTimeout")," is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider."),(0,r.kt)("p",null,"If this timeout expires, then the transfer is attempted again after ",(0,r.kt)("inlineCode",{parentName:"p"},"BlocksPerDistributionTransmission")," blocks."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"TransferPeriodTimeout")," on the consumer is initial set via the ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal")," gov proposal to add the consumer"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"TransferPeriodTimeout")," should be smaller than ",(0,r.kt)("inlineCode",{parentName:"li"},"BlocksPerDistributionTransmission x avg_block_time"))),(0,r.kt)("h2",{id:"slash-throttle-parameters"},"Slash Throttle Parameters"),(0,r.kt)("h3",{id:"slashmeterreplenishperiod"},"SlashMeterReplenishPeriod"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishPeriod")," exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed."),(0,r.kt)("p",null,"The meter is replenished to an amount equal to the slash meter allowance for that block, or ",(0,r.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction * CurrentTotalVotingPower"),"."),(0,r.kt)("h3",{id:"slashmeterreplenishfraction"},"SlashMeterReplenishFraction"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction")," exists on the provider as the portion (in range ","[0, 1]",") of total voting power that is replenished to the slash meter when a replenishment occurs."),(0,r.kt)("p",null,"This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a ",(0,r.kt)("inlineCode",{parentName:"p"},"sdk.Dec")," when used."),(0,r.kt)("h3",{id:"maxthrottledpackets"},"MaxThrottledPackets"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"MaxThrottledPackets")," exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value."),(0,r.kt)("p",null,"This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"MaxThrottledPackets")," was deprecated in ICS versions >= v3.2.0 due to the implementation of ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/adrs/adr-008-throttle-retries"},"ADR-008"),".")),(0,r.kt)("h3",{id:"retrydelayperiod"},"RetryDelayPeriod"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"RetryDelayPeriod")," exists on the consumer for ",(0,r.kt)("strong",{parentName:"p"},"ICS versions >= v3.2.0")," (introduced by the implementation of ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/adrs/adr-008-throttle-retries"},"ADR-008"),") and is the period at which the consumer retries to send a ",(0,r.kt)("inlineCode",{parentName:"p"},"SlashPacket")," that was rejected by the provider."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/437cf289.dbfb2a08.js b/legacy/assets/js/437cf289.dbfb2a08.js new file mode 100644 index 0000000000..8dac116ddf --- /dev/null +++ b/legacy/assets/js/437cf289.dbfb2a08.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1289],{3905:(t,e,n)=>{n.d(e,{Zo:()=>p,kt:()=>g});var a=n(7294);function i(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function r(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,a)}return n}function l(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?r(Object(n),!0).forEach((function(e){i(t,e,n[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))}))}return t}function s(t,e){if(null==t)return{};var n,a,i=function(t,e){if(null==t)return{};var n,a,i={},r=Object.keys(t);for(a=0;a<r.length;a++)n=r[a],e.indexOf(n)>=0||(i[n]=t[n]);return i}(t,e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);for(a=0;a<r.length;a++)n=r[a],e.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(i[n]=t[n])}return i}var o=a.createContext({}),u=function(t){var e=a.useContext(o),n=e;return t&&(n="function"==typeof t?t(e):l(l({},e),t)),n},p=function(t){var e=u(t.components);return a.createElement(o.Provider,{value:e},t.children)},d="mdxType",c={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},m=a.forwardRef((function(t,e){var n=t.components,i=t.mdxType,r=t.originalType,o=t.parentName,p=s(t,["components","mdxType","originalType","parentName"]),d=u(n),m=i,g=d["".concat(o,".").concat(m)]||d[m]||c[m]||r;return n?a.createElement(g,l(l({ref:e},p),{},{components:n})):a.createElement(g,l({ref:e},p))}));function g(t,e){var n=arguments,i=e&&e.mdxType;if("string"==typeof t||i){var r=n.length,l=new Array(r);l[0]=m;var s={};for(var o in e)hasOwnProperty.call(e,o)&&(s[o]=e[o]);s.originalType=t,s[d]="string"==typeof t?t:i,l[1]=s;for(var u=2;u<r;u++)l[u]=n[u];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},9814:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>o,contentTitle:()=>l,default:()=>c,frontMatter:()=>r,metadata:()=>s,toc:()=>u});var a=n(7462),i=(n(7294),n(3905));const r={sidebar_position:12,title:"Improving testing and increasing confidence"},l="ADR 11: Improving testing and increasing confidence",s={unversionedId:"adrs/adr-011-improving-test-confidence",id:"version-v3.3.0/adrs/adr-011-improving-test-confidence",title:"Improving testing and increasing confidence",description:"Changelog",source:"@site/versioned_docs/version-v3.3.0/adrs/adr-011-improving-test-confidence.md",sourceDirName:"adrs",slug:"/adrs/adr-011-improving-test-confidence",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-011-improving-test-confidence",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:12,frontMatter:{sidebar_position:12,title:"Improving testing and increasing confidence"},sidebar:"tutorialSidebar",previous:{title:"Standalone to Consumer Changeover",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-010-standalone-changeover"},next:{title:"Separate Releasing",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-012-separate-releasing"}},o={},u=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Current state of testing",id:"current-state-of-testing",level:4},{value:"Unit testing",id:"unit-testing",level:3},{value:"Integration testing",id:"integration-testing",level:3},{value:"End-to-end testing",id:"end-to-end-testing",level:3},{value:"Decision",id:"decision",level:2},{value:"1. Connect specifications to code and tooling",id:"1-connect-specifications-to-code-and-tooling",level:3},{value:"Decision context and hypothesis",id:"decision-context-and-hypothesis",level:4},{value:"Main benefit",id:"main-benefit",level:4},{value:"2. Improve e2e tooling",id:"2-improve-e2e-tooling",level:3},{value:"Matrix tests",id:"matrix-tests",level:4},{value:"Introducing e2e regression testing",id:"introducing-e2e-regression-testing",level:4},{value:"Introducing e2e CometMock tests",id:"introducing-e2e-cometmock-tests",level:4},{value:"3. Introduce innovative testing approaches",id:"3-introduce-innovative-testing-approaches",level:3},{value:"Model",id:"model",level:4},{value:"Driver",id:"driver",level:4},{value:"Harness",id:"harness",level:4},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],p={toc:u},d="wrapper";function c(t){let{components:e,...r}=t;return(0,i.kt)(d,(0,a.Z)({},p,r,{components:e,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"adr-11-improving-testing-and-increasing-confidence"},"ADR 11: Improving testing and increasing confidence"),(0,i.kt)("h2",{id:"changelog"},"Changelog"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"2023-08-11: Proposed, first draft of ADR.")),(0,i.kt)("h2",{id:"status"},"Status"),(0,i.kt)("p",null,"Proposed"),(0,i.kt)("h2",{id:"context"},"Context"),(0,i.kt)("p",null,"Testing, QA, and maintenance of interchain-security libraries is an ever-evolving area of software engineering we have to keep incrementally improving. The purpose of the QA process is to catch bugs as early as possible. In an ideal development workflow a bug should never reach production. A bug found in the specification stage is a lot cheaper to resolve than a bug discovered in production (or even in testnet). Ideally, all bugs should be found during the CI execution, and we hope that no bugs will ever even reach the testnet (although nothing can replace actual system stress test under load interacting with users)."),(0,i.kt)("p",null,"During development and testnet operation the following types of bugs were the most commonly found:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"improper iterator usage"),(0,i.kt)("li",{parentName:"ul"},"unbounded array access/iteration"),(0,i.kt)("li",{parentName:"ul"},"improper input handling and validation"),(0,i.kt)("li",{parentName:"ul"},"improper cached context usage"),(0,i.kt)("li",{parentName:"ul"},"non-determinism check (improper use of maps in go, relying on random values)"),(0,i.kt)("li",{parentName:"ul"},"KV store management and/or how keys are defined"),(0,i.kt)("li",{parentName:"ul"},"deserialization issues arising from consumer/provider versioning mismatch")),(0,i.kt)("p",null,"Such bugs can be discovered earlier with better tooling. Some of these bugs can induce increases in block times, chain halts, state corruption, or introduce an attack surface which is difficult to remove if other systems have started depending on that behavior."),(0,i.kt)("h4",{id:"current-state-of-testing"},"Current state of testing"),(0,i.kt)("p",null,"Our testing suites consist of multiple parts, each with their own trade-offs and benefits with regards to code coverage, complexity and confidence they provide."),(0,i.kt)("h3",{id:"unit-testing"},"Unit testing"),(0,i.kt)("p",null,"Unit testing is employed mostly for testing single-module functionality. It is the first step in testing and often the most practical. While highly important, unit tests often ",(0,i.kt)("strong",{parentName:"p"},"test a single piece of code")," and don't test relationships between different moving parts, this makes them less valuable when dealing with multi-module interactions."),(0,i.kt)("p",null,"Unit tests often employ mocks to abstract parts of the system that are not under test. Mocks are not equivalent to actual models and should not be treated as such."),(0,i.kt)("p",null,"Out of all the approaches used, unit testing has the most tools available and the coverage can simply be displayed as % of code lines tested. Although this is a very nice and very easy to understand metric, it does not speak about the quality of the test coverage."),(0,i.kt)("p",null,"Since distributed systems testing is a lot more involved, unit tests are oftentimes not sufficient to cover complex interactions. Unit tests are still necessary and helpful, but in cases where unit tests are not helpful e2e or integration tests should be favored."),(0,i.kt)("h3",{id:"integration-testing"},"Integration testing"),(0,i.kt)("p",null,"With integration testing we ",(0,i.kt)("strong",{parentName:"p"},"test the multi-module interactions")," while isolating them from the remainder of the system.\nIntegration tests can uncover bugs that are often missed by unit tests."),(0,i.kt)("p",null,"It is very difficult to gauge the actual test coverage imparted by integration tests and the available tooling is limited.\nIn interchain-security we employ the ",(0,i.kt)("inlineCode",{parentName:"p"},"ibc-go/testing")," framework to test interactions in-memory."),(0,i.kt)("p",null,"At present, integration testing does not involve the consensus layer - it is only concerned with application level state and logic."),(0,i.kt)("h3",{id:"end-to-end-testing"},"End-to-end testing"),(0,i.kt)("p",null,"In our context end-to-end testing comprises of tests that use the actual application binaries in an isolated environment (e.g. docker container). During test execution the inputs are meant to simulate actual user interaction, either by submitting transactions/queries using the command line or using gRPC/REST APIs and checking for state changes after an action has been performed. With this testing strategy we also include the consensus layer in all of our runs. This is the closest we can get to testing user interactions without starting a full testnet."),(0,i.kt)("p",null,"End-to-end testing strategies vary between different teams and projects and we strive to unify our approach to the best of our ability (at least for ICS and gaia)."),(0,i.kt)("p",null,"The available tooling does not give us significant (or relevant) line of code coverage information since most of the tools are geared towards analyzing unit tests and simple code branch evaluation."),(0,i.kt)("p",null,"We aim to adapt our best practices by learning from other similar systems and projects such as cosmos-sdk, ibc-go and CometBFT."),(0,i.kt)("h2",{id:"decision"},"Decision"),(0,i.kt)("h3",{id:"1-connect-specifications-to-code-and-tooling"},"1. Connect specifications to code and tooling"),(0,i.kt)("p",null,"Oftentimes, specifications are disconnected from the development and QA processes. This gives rise to problems where the specification does not reflect the actual state of the system and vice-versa.\nUsually specifications are just text files that are rarely used and go unmaintained after a while, resulting in consistency issues and misleading instructions/expectations about system behavior."),(0,i.kt)("h4",{id:"decision-context-and-hypothesis"},"Decision context and hypothesis"),(0,i.kt)("p",null,"Specifications written in a dedicated and executable specification language are easier to maintain than the ones written entirely in text.\nAdditionally, we can create models based on the specification OR make the model equivalent to a specification."),(0,i.kt)("p",null,"Models do not care about the intricacies of implementation and neither do specifications. Since both models and specifications care about concisely and accurately describing a system (such as a finite state machine), we see a benefit of adding model based tools (such as ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/informalsystems/quint"},"quint"),") to our testing and development workflows."),(0,i.kt)("h4",{id:"main-benefit"},"Main benefit"),(0,i.kt)("p",null,"MBT tooling can be used to generate test traces that can be executed by multiple different testing setups."),(0,i.kt)("h3",{id:"2-improve-e2e-tooling"},"2. Improve e2e tooling"),(0,i.kt)("h4",{id:"matrix-tests"},"Matrix tests"),(0,i.kt)("p",null,"Instead of only running tests against current ",(0,i.kt)("inlineCode",{parentName:"p"},"main")," branch we should adopt an approach where we also:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"run regression tests against different released software versions")," (",(0,i.kt)("inlineCode",{parentName:"li"},"ICS v1 vs v2 vs v3"),")"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"run non-determinism tests to uncover issues quickly"))),(0,i.kt)("p",null,"Matrix tests can be implemented using ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/informalsystems/CometMock"},"CometMock")," and refactoring our current e2e CI setup."),(0,i.kt)("h4",{id:"introducing-e2e-regression-testing"},"Introducing e2e regression testing"),(0,i.kt)("p",null,"This e2e test suite would execute using a cronjob in our CI (nightly, multiple times a day etc.)"),(0,i.kt)("p",null,"Briefly, the same set of traces is run against different ",(0,i.kt)("strong",{parentName:"p"},"maintained")," versions of the software and the ",(0,i.kt)("inlineCode",{parentName:"p"},"main")," branch.\nThis would allow us to discover potential issues during development instead of in a testnet scenarios."),(0,i.kt)("p",null,"The most valuable issues that can be discovered in this way are ",(0,i.kt)("strong",{parentName:"p"},"state breaking changes"),", ",(0,i.kt)("strong",{parentName:"p"},"regressions")," and ",(0,i.kt)("strong",{parentName:"p"},"version incompatibilities"),"."),(0,i.kt)("p",null,"The setup is illustrated by the image below.\n",(0,i.kt)("img",{alt:"e2e matrix tests",src:n(1366).Z,width:"2170",height:"1624"})),(0,i.kt)("p",null,"This table explains which versions are tested against each other for the same set of test traces:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"\u2705 marks a passing test"),(0,i.kt)("li",{parentName:"ul"},"\u274c marks a failing test")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"USES: ICS v1 PROVIDER")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"start chain")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"add key")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"delegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"undelegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"redelegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"downtime")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"equivocation")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"stop chain")))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"v1 consumer (sdk45,ibc4.3)")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"v2 consumer (sdk45, ibc4.4)")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"v3 consumer (sdk47, ibc7)")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"main consumer")),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"neutron")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"stride")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c")))),(0,i.kt)("h4",{id:"introducing-e2e-cometmock-tests"},"Introducing e2e CometMock tests"),(0,i.kt)("p",null,"CometMock is a mock implementation of the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft"},"CometBFT")," consensus engine. It supports most operations performed by CometBFT while also being lightweight and relatively easy to use."),(0,i.kt)("p",null,'CometMock tests allow more nuanced control of test scenarios because CometMock can "fool" the blockchain app into thinking that a certain number of blocks had passed.\n',(0,i.kt)("strong",{parentName:"p"},"This allows us to test very nuanced scenarios, difficult edge cases and long-running operations (such as unbonding operations).")),(0,i.kt)("p",null,"Examples of tests made easier with CometMock are listed below:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"regression tests"),(0,i.kt)("li",{parentName:"ul"},"non-determinism tests"),(0,i.kt)("li",{parentName:"ul"},"upgrade tests"),(0,i.kt)("li",{parentName:"ul"},"state-breaking changes")),(0,i.kt)("p",null,"With CometMock, the ",(0,i.kt)("strong",{parentName:"p"},"matrix test")," approach can also be used. The image below illustrates a CometMock setup that can be used to discover non-deterministic behavior and state-breaking changes.\n",(0,i.kt)("img",{alt:"e2e matrix tests",src:n(3809).Z,width:"3714",height:"2082"})),(0,i.kt)("p",null,"This table explains which versions are tested against each other for the same set of test traces:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"\u2705 marks a passing test"),(0,i.kt)("li",{parentName:"ul"},"\u274c marks a failing test")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"SCENARIO")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"start chain")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"add key")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"delegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"undelegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"redelegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"downtime")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"equivocation")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"stop chain")))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"v3 provi + v3 consu")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"main provi + main consu")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"commit provi + commit consu")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c")))),(0,i.kt)("p",null,"Briefly; multiple versions of the application are run against the same CometMock instance and any deviations in app behavior would result in ",(0,i.kt)("inlineCode",{parentName:"p"},"app hash")," errors (the apps would be in different states after performing the same set of actions)."),(0,i.kt)("h3",{id:"3-introduce-innovative-testing-approaches"},"3. Introduce innovative testing approaches"),(0,i.kt)("p",null,"When discussing e2e testing, some very important patterns emerge - especially if test traces are used instead of ad-hoc tests written by hand."),(0,i.kt)("p",null,"We see a unique opportunity to clearly identify concerns and modularize the testing architecture. "),(0,i.kt)("p",null,"The e2e testing frameworks can be split into a ",(0,i.kt)("strong",{parentName:"p"},"pipeline consisting of 3 parts: model, driver and harness"),"."),(0,i.kt)("h4",{id:"model"},"Model"),(0,i.kt)("p",null,"Model is the part of the system that can emulate the behavior of the system under test.\nIdeally, it is very close to the specification and is written in a specification language such as quint, TLA+ or similar.\nOne of the purposes of the model is that it can be used to generate test traces. "),(0,i.kt)("h4",{id:"driver"},"Driver"),(0,i.kt)("p",null,"The purpose of the driver is to accept test traces (generated by the model or written by hand), process them and provide inputs to the next part of the pipeline."),(0,i.kt)("p",null,"Basically, the driver sits between the model and the actual infrastructure on which the test traces are being executed on."),(0,i.kt)("h4",{id:"harness"},"Harness"),(0,i.kt)("p",null,"Harness is the infrastructure layer of the pipeline that accepts inputs from the driver."),(0,i.kt)("p",null,"There can be multiple harnesses as long as they can perform four things:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"bootstrap a test execution environment (local, docker, k8s\u2026)"),(0,i.kt)("li",{parentName:"ul"},"accept inputs from drivers"),(0,i.kt)("li",{parentName:"ul"},"perform the action specified by the driver"),(0,i.kt)("li",{parentName:"ul"},"report results after performing actions")),(0,i.kt)("h2",{id:"consequences"},"Consequences"),(0,i.kt)("p",null,"The procedure outlined in this ADR is not an all-or-nothing approach. Concepts introduced here do not rely on each other, so this ADR may only be applied partially without negative impact on test coverage and code confidence."),(0,i.kt)("h3",{id:"positive"},"Positive"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"introduction of maintainable MBT solutions")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},'improvement over the current "difftest" setup that relies on an opinionated typescript model and go driver')),(0,i.kt)("ol",{start:2},(0,i.kt)("li",{parentName:"ol"},"increased code coverage and confidence")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"using CometMock allows us to run more tests in less time"),(0,i.kt)("li",{parentName:"ul"},"adding matrix e2e tests allows us to quickly pinpoint differences between code versions")),(0,i.kt)("h3",{id:"negative"},"Negative"),(0,i.kt)("p",null,"It might be easier to forgo the MBT tooling and instead focus on pure property based testing"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/667"},"PBT proof of concept")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/flyingmutant/rapid"},"property based testing in go"))),(0,i.kt)("p",null,'The solutions are potentially expensive if we increase usage of the CI pipeline - this is fixed by running "expensive" tests using a cronjob, instead of running them on every commit.'),(0,i.kt)("h3",{id:"neutral"},"Neutral"),(0,i.kt)("p",null,"The process of changing development and testing process is not something that can be thought of and delivered quickly. Luckily, the changes can be rolled out incrementally without impacting existing workflows."),(0,i.kt)("h2",{id:"references"},"References"),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/gaia/issues/2427"},"https://github.com/cosmos/gaia/issues/2427")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/gaia/issues/2420"},"https://github.com/cosmos/gaia/issues/2420")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/ibc-go/tree/main/e2e"},"ibc-go e2e tests"))))}c.isMDXComponent=!0},3809:(t,e,n)=>{n.d(e,{Z:()=>a});const a=n.p+"assets/images/cometmock_matrix_test-714f36252aff9df4214823e3145d0ef5.png"},1366:(t,e,n)=>{n.d(e,{Z:()=>a});const a=n.p+"assets/images/matrix_e2e_tests-30681305077301daaf3097e1952b54bb.png"}}]); \ No newline at end of file diff --git a/legacy/assets/js/44efc911.285ae205.js b/legacy/assets/js/44efc911.285ae205.js new file mode 100644 index 0000000000..533a63c6cb --- /dev/null +++ b/legacy/assets/js/44efc911.285ae205.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[872],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>h});var r=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function s(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?s(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):s(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function i(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},s=Object.keys(e);for(r=0;r<s.length;r++)t=s[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r<s.length;r++)t=s[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var d=r.createContext({}),l=function(e){var n=r.useContext(d),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=l(e.components);return r.createElement(d.Provider,{value:n},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,s=e.originalType,d=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),c=l(t),m=a,h=c["".concat(d,".").concat(m)]||c[m]||p[m]||s;return t?r.createElement(h,o(o({ref:n},u),{},{components:t})):r.createElement(h,o({ref:n},u))}));function h(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var s=t.length,o=new Array(s);o[0]=m;var i={};for(var d in n)hasOwnProperty.call(n,d)&&(i[d]=n[d]);i.originalType=e,i[c]="string"==typeof e?e:a,o[1]=i;for(var l=2;l<s;l++)o[l]=t[l];return r.createElement.apply(null,o)}return r.createElement.apply(null,t)}m.displayName="MDXCreateElement"},5336:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>p,frontMatter:()=>s,metadata:()=>i,toc:()=>l});var r=t(7462),a=(t(7294),t(3905));const s={sidebar_position:3,title:"Key Assignment"},o="ADR 001: Key Assignment",i={unversionedId:"adrs/adr-001-key-assignment",id:"version-v3.1.0/adrs/adr-001-key-assignment",title:"Key Assignment",description:"Changelog",source:"@site/versioned_docs/version-v3.1.0/adrs/adr-001-key-assignment.md",sourceDirName:"adrs",slug:"/adrs/adr-001-key-assignment",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-001-key-assignment",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Key Assignment"},sidebar:"tutorialSidebar",previous:{title:"ADR Template",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-template"},next:{title:"Jail Throttling",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-002-throttle"}},d={},l=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"State required",id:"state-required",level:3},{value:"Protocol overview",id:"protocol-overview",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],u={toc:l},c="wrapper";function p(e){let{components:n,...t}=e;return(0,a.kt)(c,(0,r.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-001-key-assignment"},"ADR 001: Key Assignment"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"2022-12-01: Initial Draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"It is possible to change the keys at any time by submitting a transaction (i.e., ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey"),")."),(0,a.kt)("h3",{id:"state-required"},"State required"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorConsumerPubKey")," - Stores the validator assigned keys for every consumer chain.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorByConsumerAddr")," - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"KeyAssignmentReplacements")," - Stores the key assignments that need to be replaced in the current block. Needed to apply the key assignments received in a block to the validator updates sent to the consumer chains.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"KeyAssignmentReplacementsBytePrefix | len(chainID) | chainID | providerConsAddress -> abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower},\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ConsumerAddrsToPrune")," - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ",(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorByConsumerAddr"),". ")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses\n")),(0,a.kt)("h3",{id:"protocol-overview"},"Protocol overview"),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey(chainID, providerAddr, consumerKey)")," message:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"// get validator from staking module \nvalidator, found := stakingKeeper.GetValidator(providerAddr)\nif !found {\n return ErrNoValidatorFound\n}\nproviderConsAddr := validator.GetConsAddr()\n\n// make sure consumer key is not in use\nconsumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)\nif _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {\n return ErrInvalidConsumerConsensusPubKey\n}\n\n// check whether the consumer chain is already registered\n// i.e., a client to the consumer was already created\nif _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {\n // get the previous key assigned for this validator on this consumer chain\n oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)\n if found {\n // mark this old consumer key as prunable once the VSCMaturedPacket\n // for the current VSC ID is received\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n vscID := GetValidatorSetUpdateId()\n AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)\n } else {\n // the validator had no key assigned on this consumer chain\n oldConsumerKey := validator.TmConsPublicKey()\n }\n\n // check whether the validator is valid, i.e., its power is positive\n if currentPower := stakingKeeper.GetLastValidatorPower(providerAddr); currentPower > 0 {\n // to enable multiple calls of AssignConsumerKey in the same block by the same validator\n // the key assignment replacement should not be overwritten\n if _, found := GetKeyAssignmentReplacement(chainID, providerConsAddr); !found {\n // store old key and power for modifying the valset update in EndBlock\n oldKeyAssignment := abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower}\n SetKeyAssignmentReplacement(chainID, providerConsAddr, oldKeyAssignment)\n }\n }\n} else {\n // if the consumer chain is not registered, then remove the previous reverse mapping\n if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)\n }\n}\n\n\n// set the mapping from this validator's provider address to the new consumer key\nSetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)\n\n// set the reverse mapping: from this validator's new consensus address \n// on the consumer to its consensus address on the provider\nSetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)\n")),(0,a.kt)("p",null,"When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see ",(0,a.kt)("inlineCode",{parentName:"p"},"MakeConsumerGenesis"),"). "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {\n // ...\n // get initial valset from the staking module\n var updates []abci.ValidatorUpdate{}\n stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {\n validator := stakingKeeper.GetValidator(providerAddr)\n providerKey := validator.TmConsPublicKey()\n updates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})\n return false\n })\n\n // applies the key assignment to the initial validator\n for i, update := range updates {\n providerAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)\n if consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {\n updates[i].PubKey = consumerKey\n }\n }\n gen.InitialValSet = updates\n\n // get a hash of the consumer validator set from the update\n updatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)\n hash := tendermint.NewValidatorSet(updatesAsValSet).Hash()\n\n return gen, hash, nil\n}\n")),(0,a.kt)("p",null,"On ",(0,a.kt)("inlineCode",{parentName:"p"},"EndBlock")," while queueing ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCPacket"),"s to send to registered consumer chains:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func QueueVSCPackets() {\n valUpdateID := GetValidatorSetUpdateId()\n // get the validator updates from the staking module\n valUpdates := stakingKeeper.GetValidatorUpdates()\n\n IterateConsumerChains(func(chainID, clientID string) (stop bool) {\n // apply the key assignment to the validator updates\n valUpdates := ApplyKeyAssignmentToValUpdates(chainID, valUpdates)\n // ..\n })\n // ...\n}\n\nfunc ApplyKeyAssignmentToValUpdates(\n chainID string, \n valUpdates []abci.ValidatorUpdate,\n) (newUpdates []abci.ValidatorUpdate) {\n for _, valUpdate := range valUpdates {\n providerAddr := utils.TMCryptoPublicKeyToConsAddr(valUpdate.PubKey)\n\n // if a key assignment replacement is found, then\n // remove the valupdate with the old consumer key\n // and create two new valupdates\n prevConsumerKey, _, found := GetKeyAssignmentReplacement(chainID, providerAddr)\n if found {\n // set the old consumer key's power to 0\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: prevConsumerKey,\n Power: 0,\n })\n // set the new consumer key's power to the power in the update\n newConsumerKey := GetValidatorConsumerPubKey(chainID, providerAddr)\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: newConsumerKey,\n Power: valUpdate.Power,\n })\n // delete key assignment replacement\n DeleteKeyAssignmentReplacement(chainID, providerAddr)\n } else {\n // there is no key assignment replacement;\n // check if the validator's key is assigned\n consumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr)\n if found {\n // replace the update containing the provider key \n // with an update containing the consumer key\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: consumerKey,\n Power: valUpdate.Power,\n })\n } else {\n // keep the same update\n newUpdates = append(newUpdates, valUpdate)\n }\n }\n }\n\n // iterate over the remaining key assignment replacements\n IterateKeyAssignmentReplacements(chainID, func(\n pAddr sdk.ConsAddress,\n prevCKey tmprotocrypto.PublicKey,\n power int64,\n ) (stop bool) {\n // set the old consumer key's power to 0\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: prevCKey,\n Power: 0,\n })\n // set the new consumer key's power to the power in key assignment replacement\n newConsumerKey := GetValidatorConsumerPubKey(chainID, pAddr)\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: newConsumerKey,\n Power: power,\n })\n return false\n })\n\n // remove all the key assignment replacements\n \n return newUpdates\n}\n")),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"SlashPacket")," from a consumer chain with id ",(0,a.kt)("inlineCode",{parentName:"p"},"chainID")," for a infraction of a validator ",(0,a.kt)("inlineCode",{parentName:"p"},"data.Validator"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {\n // ...\n // the slash packet validator address may be known only on the consumer chain;\n // in this case, it must be mapped back to the consensus address on the provider chain\n consumerAddr := sdk.ConsAddress(data.Validator.Address)\n providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)\n if !found {\n // the validator has the same key on the consumer as on the provider\n providerAddr = consumer\n }\n // ...\n}\n")),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCMatured"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {\n // ...\n // prune previous consumer validator address that are no longer needed\n consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n for _, addr := range consumerAddrs {\n DeleteValidatorByConsumerAddr(chainID, addr)\n }\n DeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n // ...\n}\n")),(0,a.kt)("p",null,"On stopping a consumer chain:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {\n // ...\n // deletes all the state needed for key assignments on this consumer chain\n // ...\n}\n")),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Validators can use different consensus keys on the consumer chains.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"None")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"The consensus state necessary to create a client to the consumer chain must use the hash returned by the ",(0,a.kt)("inlineCode",{parentName:"li"},"MakeConsumerGenesis")," method as the ",(0,a.kt)("inlineCode",{parentName:"li"},"nextValsHash"),"."),(0,a.kt)("li",{parentName:"ul"},"The consumer chain can no longer check the initial validator set against the consensus state on ",(0,a.kt)("inlineCode",{parentName:"li"},"InitGenesis"),".")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/26"},"Key assignment issue"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/455b0b19.4415e5b6.js b/legacy/assets/js/455b0b19.4415e5b6.js new file mode 100644 index 0000000000..5d0c6c8bde --- /dev/null +++ b/legacy/assets/js/455b0b19.4415e5b6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[492],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>g});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function l(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function o(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),d=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},p=function(e){var t=d(e.components);return n.createElement(c.Provider,{value:t},e.children)},s="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),s=d(r),m=a,g=s["".concat(c,".").concat(m)]||s[m]||u[m]||i;return r?n.createElement(g,l(l({ref:t},p),{},{components:r})):n.createElement(g,l({ref:t},p))}));function g(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,l=new Array(i);l[0]=m;var o={};for(var c in t)hasOwnProperty.call(t,c)&&(o[c]=t[c]);o.originalType=e,o[s]="string"==typeof e?e:a,l[1]=o;for(var d=2;d<i;d++)l[d]=r[d];return n.createElement.apply(null,l)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},3277:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>l,default:()=>u,frontMatter:()=>i,metadata:()=>o,toc:()=>d});var n=r(7462),a=(r(7294),r(3905));const i={sidebar_position:1,title:"ADRs"},l="Architecture Decision Records (ADR)",o={unversionedId:"adrs/intro",id:"version-v3.2.0/adrs/intro",title:"ADRs",description:"This is a location to record all high-level architecture decisions in the Interchain Security project.",source:"@site/versioned_docs/version-v3.2.0/adrs/intro.md",sourceDirName:"adrs",slug:"/adrs/intro",permalink:"/interchain-security/legacy/v3.2.0/adrs/intro",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:1,frontMatter:{sidebar_position:1,title:"ADRs"},sidebar:"tutorialSidebar",previous:{title:"Frequently Asked Questions",permalink:"/interchain-security/legacy/v3.2.0/faq"},next:{title:"ADR Template",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop"}},c={},d=[{value:"Table of Contents",id:"table-of-contents",level:2}],p={toc:d},s="wrapper";function u(e){let{components:t,...r}=e;return(0,a.kt)(s,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"architecture-decision-records-adr"},"Architecture Decision Records (ADR)"),(0,a.kt)("p",null,"This is a location to record all high-level architecture decisions in the Interchain Security project."),(0,a.kt)("p",null,"You can read more about the ADR concept in this ",(0,a.kt)("a",{parentName:"p",href:"https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0#.78xhdix6t"},"blog post"),"."),(0,a.kt)("p",null,"An ADR should provide:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Context on the relevant goals and the current state"),(0,a.kt)("li",{parentName:"ul"},"Proposed changes to achieve the goals"),(0,a.kt)("li",{parentName:"ul"},"Summary of pros and cons"),(0,a.kt)("li",{parentName:"ul"},"References"),(0,a.kt)("li",{parentName:"ul"},"Changelog")),(0,a.kt)("p",null,"Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and\njustification for a change in architecture, or for the architecture of something\nnew. The spec is much more compressed and streamlined summary of everything as\nit is or should be."),(0,a.kt)("p",null,"If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match."),(0,a.kt)("p",null,"Note the context/background should be written in the present tense."),(0,a.kt)("p",null,"To suggest an ADR, please make use of the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.2.0/adrs/adr-template"},"ADR template")," provided."),(0,a.kt)("h2",{id:"table-of-contents"},"Table of Contents"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"ADR ","#"),(0,a.kt)("th",{parentName:"tr",align:null},"Description"),(0,a.kt)("th",{parentName:"tr",align:null},"Status"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.2.0/adrs/adr-001-key-assignment"},"001")),(0,a.kt)("td",{parentName:"tr",align:null},"Consumer chain key assignment"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.2.0/adrs/adr-002-throttle"},"002")),(0,a.kt)("td",{parentName:"tr",align:null},"Jail Throttling"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.2.0/adrs/adr-003-equivocation-gov-proposal"},"003")),(0,a.kt)("td",{parentName:"tr",align:null},"Equivocation governance proposal"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"./adr-004-denom-dos-fixes"},"004")),(0,a.kt)("td",{parentName:"tr",align:null},"Denom DOS fixes"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.2.0/adrs/adr-005-cryptographic-equivocation-verification"},"005")),(0,a.kt)("td",{parentName:"tr",align:null},"Cryptographic verification of equivocation evidence"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, In-progress")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop"},"007")),(0,a.kt)("td",{parentName:"tr",align:null},"Pause validator unbonding during equivocation proposal"),(0,a.kt)("td",{parentName:"tr",align:null},"Proposed")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.2.0/adrs/adr-008-throttle-retries"},"008")),(0,a.kt)("td",{parentName:"tr",align:null},"Throttle with retries"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, In-progress")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.2.0/adrs/adr-009-soft-opt-out"},"009")),(0,a.kt)("td",{parentName:"tr",align:null},"Soft Opt-out"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.2.0/adrs/adr-010-standalone-changeover"},"010")),(0,a.kt)("td",{parentName:"tr",align:null},"Standalone to Consumer Changeover"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.2.0/adrs/adr-011-improving-test-confidence"},"011")),(0,a.kt)("td",{parentName:"tr",align:null},"Improving testing and increasing confidence"),(0,a.kt)("td",{parentName:"tr",align:null},"Proposed")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.2.0/adrs/adr-012-separate-releasing"},"012")),(0,a.kt)("td",{parentName:"tr",align:null},"Separate Releasing"),(0,a.kt)("td",{parentName:"tr",align:null},"Proposed")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.2.0/adrs/adr-013-equivocation-slashing"},"013")),(0,a.kt)("td",{parentName:"tr",align:null},"Slashing on the provider for consumer equivocation"),(0,a.kt)("td",{parentName:"tr",align:null},"Proposed")))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/45f2a265.8cbf978c.js b/legacy/assets/js/45f2a265.8cbf978c.js new file mode 100644 index 0000000000..f6ac26d754 --- /dev/null +++ b/legacy/assets/js/45f2a265.8cbf978c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5864],{3905:(e,r,n)=>{n.d(r,{Zo:()=>u,kt:()=>h});var t=n(7294);function o(e,r,n){return r in e?Object.defineProperty(e,r,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[r]=n,e}function a(e,r){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);r&&(t=t.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),n.push.apply(n,t)}return n}function i(e){for(var r=1;r<arguments.length;r++){var n=null!=arguments[r]?arguments[r]:{};r%2?a(Object(n),!0).forEach((function(r){o(e,r,n[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(n,r))}))}return e}function s(e,r){if(null==e)return{};var n,t,o=function(e,r){if(null==e)return{};var n,t,o={},a=Object.keys(e);for(t=0;t<a.length;t++)n=a[t],r.indexOf(n)>=0||(o[n]=e[n]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(t=0;t<a.length;t++)n=a[t],r.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=t.createContext({}),l=function(e){var r=t.useContext(c),n=r;return e&&(n="function"==typeof e?e(r):i(i({},r),e)),n},u=function(e){var r=l(e.components);return t.createElement(c.Provider,{value:r},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var r=e.children;return t.createElement(t.Fragment,{},r)}},m=t.forwardRef((function(e,r){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=l(n),m=o,h=d["".concat(c,".").concat(m)]||d[m]||p[m]||a;return n?t.createElement(h,i(i({ref:r},u),{},{components:n})):t.createElement(h,i({ref:r},u))}));function h(e,r){var n=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=m;var s={};for(var c in r)hasOwnProperty.call(r,c)&&(s[c]=r[c]);s.originalType=e,s[d]="string"==typeof e?e:o,i[1]=s;for(var l=2;l<a;l++)i[l]=n[l];return t.createElement.apply(null,i)}return t.createElement.apply(null,n)}m.displayName="MDXCreateElement"},2350:(e,r,n)=>{n.r(r),n.d(r,{assets:()=>c,contentTitle:()=>i,default:()=>p,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var t=n(7462),o=(n(7294),n(3905));const a={sidebar_position:6},i="Consumer Genesis Transformation",s={unversionedId:"consumer-development/consumer-genesis-transformation",id:"version-v3.3.0/consumer-development/consumer-genesis-transformation",title:"Consumer Genesis Transformation",description:"Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentaion on Onboarding and Changeover).",source:"@site/versioned_docs/version-v3.3.0/consumer-development/consumer-genesis-transformation.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-genesis-transformation",permalink:"/interchain-security/legacy/v3.3.0/consumer-development/consumer-genesis-transformation",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"tutorialSidebar",previous:{title:"Changeover Procedure",permalink:"/interchain-security/legacy/v3.3.0/consumer-development/changeover-procedure"},next:{title:"Overview",permalink:"/interchain-security/legacy/v3.3.0/validators/overview"}},c={},l=[{value:"1. Prerequisite",id:"1-prerequisite",level:2},{value:"2. Export the CCV data",id:"2-export-the-ccv-data",level:2},{value:"3. Transform CCV data",id:"3-transform-ccv-data",level:2}],u={toc:l},d="wrapper";function p(e){let{components:r,...n}=e;return(0,o.kt)(d,(0,t.Z)({},u,n,{components:r,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-genesis-transformation"},"Consumer Genesis Transformation"),(0,o.kt)("p",null,"Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentaion on ",(0,o.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/consumer-development/onboarding"},"Onboarding")," and ",(0,o.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/consumer-development/changeover-procedure"},"Changeover"),").\nIn case that the provider chain is running an older version of the InterChainSecurity (ICS) module than the consumer chain the exported CCV data might need to be transformed to the format supported by the ICS implementation run on the consumer chain. This is the case if the cosumer chain runs version 4 of ICS or later and the provider is running version 3 or older of the ICS module."),(0,o.kt)("p",null,"To transform such CCV data follow the instructions below"),(0,o.kt)("h2",{id:"1-prerequisite"},"1. Prerequisite"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Provider chain is running version 3 or older of the ICS provider module"),(0,o.kt)("li",{parentName:"ul"},"Consumer is running version 4 or later of the ICS consumer module."),(0,o.kt)("li",{parentName:"ul"},"interchain-security-cd application complies to the version run on the consumer chain")),(0,o.kt)("h2",{id:"2-export-the-ccv-data"},"2. Export the CCV data"),(0,o.kt)("p",null,"Export the CCV data from the provider chain as descibed in the ",(0,o.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/consumer-development/onboarding"},"Onboarding")," and ",(0,o.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/consumer-development/changeover-procedure"},"Changeover"),") your following.\nAs a result the CCV data will be stored in a file in JSON format."),(0,o.kt)("h2",{id:"3-transform-ccv-data"},"3. Transform CCV data"),(0,o.kt)("p",null,"To transform the CCV data to the newer format run the following command."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"interchain-security-cd genesis transform [genesis-file]\n")),(0,o.kt)("p",null,"where 'genesis-file' is the path to the file containing the CCV data exported in ",(0,o.kt)("a",{parentName:"p",href:"#2-export-the-ccv-data"},"step 2"),".\nAs a result the CCV data in the new format will be written to standard output."),(0,o.kt)("p",null,"Use the new CCV data as described in the procedure you're following."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/46057b98.3691d884.js b/legacy/assets/js/46057b98.3691d884.js new file mode 100644 index 0000000000..3453fd8559 --- /dev/null +++ b/legacy/assets/js/46057b98.3691d884.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3159],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),c=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),m=a,h=u["".concat(l,".").concat(m)]||u[m]||d[m]||i;return n?o.createElement(h,r(r({ref:t},p),{},{components:n})):o.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,r=new Array(i);r[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,r[1]=s;for(var c=2;c<i;c++)r[c]=n[c];return o.createElement.apply(null,r)}return o.createElement.apply(null,n)}m.displayName="MDXCreateElement"},704:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var o=n(7462),a=(n(7294),n(3905));const i={sidebar_position:4,title:"Equivocation governance proposal"},r="ADR 003: Equivocation governance proposal",s={unversionedId:"adrs/adr-003-equivocation-gov-proposal",id:"adrs/adr-003-equivocation-gov-proposal",title:"Equivocation governance proposal",description:"Changelog",source:"@site/docs/adrs/adr-003-equivocation-gov-proposal.md",sourceDirName:"adrs",slug:"/adrs/adr-003-equivocation-gov-proposal",permalink:"/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposal",draft:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Equivocation governance proposal"},sidebar:"tutorialSidebar",previous:{title:"Jail Throttling",permalink:"/interchain-security/legacy/adrs/adr-002-throttle"},next:{title:"Cryptographic verification of equivocation evidence",permalink:"/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification"}},l={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],p={toc:c},u="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-003-equivocation-governance-proposal"},"ADR 003: Equivocation governance proposal"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"2023-02-06: Initial draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain."),(0,a.kt)("p",null,"For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain."),(0,a.kt)("p",null,"A new kind of governance proposal is added to the ",(0,a.kt)("inlineCode",{parentName:"p"},"provider")," module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain."),(0,a.kt)("p",null,"If such proposal passes, the proposal handler delegates to the ",(0,a.kt)("inlineCode",{parentName:"p"},"evidence")," module to process the equivocation. This module ensures the evidence isn\u2019t too old, or else ignores it (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/21021b837882d1d40f1d79bcbc4fad2e79a3fefe/x/evidence/keeper/infraction.go#L54-L62"},"code"),"). ",(0,a.kt)("em",{parentName:"p"},"Too old")," is determined by 2 consensus params : "),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"evidence.max_age_duration")," number of nanoseconds before an evidence is considered too old"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"evidence.max_age_numblocks")," number of blocks before an evidence is considered too old.")),(0,a.kt)("p",null,"On the hub, those parameters are equals to "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682\n(...)\n"evidence": {\n "max_age_num_blocks": "1000000",\n "max_age_duration": "172800000000000",\n (...)\n},\n(...)\n')),(0,a.kt)("p",null,"A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the ",(0,a.kt)("inlineCode",{parentName:"p"},"evidence")," module when the proposal passes and is handled by the hub."),(0,a.kt)("p",null,"For ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks=1M"),", the parameter is big enough if we consider the hub produces 12k blocks per day (",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_year/365 = 436,0000/365"),"). The evidence can be up to 83 days old (",(0,a.kt)("inlineCode",{parentName:"p"},"1,000,000/12,000"),") and not be ignored."),(0,a.kt)("p",null,"For ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_duration=172,800,000,000,000"),", the parameter is too low, because the value is in nanoseconds so it\u2019s 2 days. Fortunately the condition that checks those 2 parameters uses a ",(0,a.kt)("strong",{parentName:"p"},"AND"),", so if ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks")," condition passes, the evidence won\u2019t be ignored."),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Remove the possibility from a malicious consumer chain to \u201cattack\u201d the provider chain by slashing/jailing validators."),(0,a.kt)("li",{parentName:"ul"},"Provide a more acceptable implementation for the validator community.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Punishment action of double-signing isn\u2019t \u201cautomated\u201d, a governance proposal is required which takes more time."),(0,a.kt)("li",{parentName:"ul"},"You need to pay 250ATOM to submit an equivocation evidence.")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"PR that ignores non downtime slash packet : ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/692"},"https://github.com/cosmos/interchain-security/pull/692")),(0,a.kt)("li",{parentName:"ul"},"PR that adds the governance slash proposal: ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/703"},"https://github.com/cosmos/interchain-security/pull/703"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/46dddd35.04e8e182.js b/legacy/assets/js/46dddd35.04e8e182.js new file mode 100644 index 0000000000..fafec16d1f --- /dev/null +++ b/legacy/assets/js/46dddd35.04e8e182.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5474],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>d});var o=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function c(e,n){if(null==e)return{};var t,o,r=function(e,n){if(null==e)return{};var t,o,r={},a=Object.keys(e);for(o=0;o<a.length;o++)t=a[o],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o<a.length;o++)t=a[o],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=o.createContext({}),l=function(e){var n=o.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},u=function(e){var n=l(e.components);return o.createElement(s.Provider,{value:n},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},h=o.forwardRef((function(e,n){var t=e.components,r=e.mdxType,a=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=l(t),h=r,d=p["".concat(s,".").concat(h)]||p[h]||m[h]||a;return t?o.createElement(d,i(i({ref:n},u),{},{components:t})):o.createElement(d,i({ref:n},u))}));function d(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var a=t.length,i=new Array(a);i[0]=h;var c={};for(var s in n)hasOwnProperty.call(n,s)&&(c[s]=n[s]);c.originalType=e,c[p]="string"==typeof e?e:r,i[1]=c;for(var l=2;l<a;l++)i[l]=t[l];return o.createElement.apply(null,i)}return o.createElement.apply(null,t)}h.displayName="MDXCreateElement"},9639:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var o=t(7462),r=(t(7294),t(3905));const a={sidebar_position:1},i="Developing an ICS consumer chain",c={unversionedId:"consumer-development/app-integration",id:"version-v3.2.0/consumer-development/app-integration",title:"Developing an ICS consumer chain",description:"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.",source:"@site/versioned_docs/version-v3.2.0/consumer-development/app-integration.md",sourceDirName:"consumer-development",slug:"/consumer-development/app-integration",permalink:"/interchain-security/legacy/v3.2.0/consumer-development/app-integration",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/legacy/v3.2.0/features/slashing"},next:{title:"Consumer Chain Governance",permalink:"/interchain-security/legacy/v3.2.0/consumer-development/consumer-chain-governance"}},s={},l=[{value:"Basic consumer chain",id:"basic-consumer-chain",level:2},{value:"Democracy consumer chain",id:"democracy-consumer-chain",level:2},{value:"Standalone chain to consumer chain changeover",id:"standalone-chain-to-consumer-chain-changeover",level:2}],u={toc:l},p="wrapper";function m(e){let{components:n,...t}=e;return(0,r.kt)(p,(0,o.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"developing-an-ics-consumer-chain"},"Developing an ICS consumer chain"),(0,r.kt)("p",null,"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.\nTo help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications."),(0,r.kt)("h2",{id:"basic-consumer-chain"},"Basic consumer chain"),(0,r.kt)("p",null,"The source code for the example app can be found ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer"},"here"),"."),(0,r.kt)("p",null,"Please note that consumer chains do not implement the staking module - the validator set is replicated from the provider, meaning that the provider and the consumer use the same validator set and their stake on the provider directly determines their stake on the consumer.\nAt present there is no opt-in mechanism available, so all validators of the provider must also validate on the provider chain."),(0,r.kt)("p",null,"Your chain should import the consumer module from ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," and register it in the correct places in your ",(0,r.kt)("inlineCode",{parentName:"p"},"app.go"),".\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in.\nYou should not need to manage or override any code from the ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module."),(0,r.kt)("h2",{id:"democracy-consumer-chain"},"Democracy consumer chain"),(0,r.kt)("p",null,"The source code for the example app can be found ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy"},"here"),"."),(0,r.kt)("p",null,"This type of consumer chain wraps the basic CosmosSDK ",(0,r.kt)("inlineCode",{parentName:"p"},"x/distribution"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"x/staking")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"x/governance")," modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system."),(0,r.kt)("p",null,"This allows the consumer chain to leverage those modules while also using the ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module."),(0,r.kt)("p",null,'With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.'),(0,r.kt)("h2",{id:"standalone-chain-to-consumer-chain-changeover"},"Standalone chain to consumer chain changeover"),(0,r.kt)("p",null,"This feature is being actively worked on. Information will be provided at a later time."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/4972.9374abde.js b/legacy/assets/js/4972.9374abde.js new file mode 100644 index 0000000000..27b3f75298 --- /dev/null +++ b/legacy/assets/js/4972.9374abde.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4972],{4972:(e,t,n)=>{n.r(t),n.d(t,{default:()=>i});var a=n(7294),l=n(5999),o=n(1944),r=n(7961);function i(){return a.createElement(a.Fragment,null,a.createElement(o.d,{title:(0,l.I)({id:"theme.NotFound.title",message:"Page Not Found"})}),a.createElement(r.Z,null,a.createElement("main",{className:"container margin-vert--xl"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col col--6 col--offset-3"},a.createElement("h1",{className:"hero__title"},a.createElement(l.Z,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),a.createElement("p",null,a.createElement(l.Z,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),a.createElement("p",null,a.createElement(l.Z,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.")))))))}}}]); \ No newline at end of file diff --git a/legacy/assets/js/4b0243dd.91644af8.js b/legacy/assets/js/4b0243dd.91644af8.js new file mode 100644 index 0000000000..cad1555e2a --- /dev/null +++ b/legacy/assets/js/4b0243dd.91644af8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1136],{3905:(e,t,i)=>{i.d(t,{Zo:()=>h,kt:()=>m});var n=i(7294);function a(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}function o(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function s(e){for(var t=1;t<arguments.length;t++){var i=null!=arguments[t]?arguments[t]:{};t%2?o(Object(i),!0).forEach((function(t){a(e,t,i[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(i)):o(Object(i)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(i,t))}))}return e}function r(e,t){if(null==e)return{};var i,n,a=function(e,t){if(null==e)return{};var i,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)i=o[n],t.indexOf(i)>=0||(a[i]=e[i]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)i=o[n],t.indexOf(i)>=0||Object.prototype.propertyIsEnumerable.call(e,i)&&(a[i]=e[i])}return a}var c=n.createContext({}),l=function(e){var t=n.useContext(c),i=t;return e&&(i="function"==typeof e?e(t):s(s({},t),e)),i},h=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var i=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,h=r(e,["components","mdxType","originalType","parentName"]),d=l(i),p=a,m=d["".concat(c,".").concat(p)]||d[p]||u[p]||o;return i?n.createElement(m,s(s({ref:t},h),{},{components:i})):n.createElement(m,s({ref:t},h))}));function m(e,t){var i=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=i.length,s=new Array(o);s[0]=p;var r={};for(var c in t)hasOwnProperty.call(t,c)&&(r[c]=t[c]);r.originalType=e,r[d]="string"==typeof e?e:a,s[1]=r;for(var l=2;l<o;l++)s[l]=i[l];return n.createElement.apply(null,s)}return n.createElement.apply(null,i)}p.displayName="MDXCreateElement"},4:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>u,frontMatter:()=>o,metadata:()=>r,toc:()=>l});var n=i(7462),a=(i(7294),i(3905));const o={sidebar_position:4,title:"Cryptographic verification of equivocation evidence"},s="ADR 005: Cryptographic verification of equivocation evidence",r={unversionedId:"adrs/adr-005-cryptographic-equivocation-verification",id:"version-v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verification",title:"Cryptographic verification of equivocation evidence",description:"Changelog",source:"@site/versioned_docs/version-v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verification.md",sourceDirName:"adrs",slug:"/adrs/adr-005-cryptographic-equivocation-verification",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verification",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Cryptographic verification of equivocation evidence"},sidebar:"tutorialSidebar",previous:{title:"Equivocation governance proposal",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposal"},next:{title:"Slashing on the provider for consumer equivocation",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-013-equivocation-slashing"}},c={},l=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Light Client Attack",id:"light-client-attack",level:3},{value:"Double Signing Attack",id:"double-signing-attack",level:3},{value:"Decision",id:"decision",level:2},{value:"Light Client Attack",id:"light-client-attack-1",level:3},{value:"Double Signing Attack",id:"double-signing-attack-1",level:3},{value:"Current limitations:",id:"current-limitations",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}],h={toc:l},d="wrapper";function u(e){let{components:t,...i}=e;return(0,a.kt)(d,(0,n.Z)({},h,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-005-cryptographic-verification-of-equivocation-evidence"},"ADR 005: Cryptographic verification of equivocation evidence"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"5/1/2023: First draft"),(0,a.kt)("li",{parentName:"ul"},"7/23/2023: Add light client attacks handling"),(0,a.kt)("li",{parentName:"ul"},"9/6/2023: Add double signing attacks handling"),(0,a.kt)("li",{parentName:"ul"},"11/3/2023: Update limitations to clarify amnesia attacks are ignored")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"Currently, we use a governance proposal to slash validators for equivocation (double signing and light client attacks).\nEvery proposal needs to go through a (two weeks) voting period before it can be approved.\nGiven a three-week unbonding period, this means that an equivocation proposal needs to be submitted within one week since the infraction occurred."),(0,a.kt)("p",null,"This ADR proposes a system to slash validators automatically for equivocation, immediately upon the provider chain's receipt of the evidence. Another thing to note is that we intend to introduce this system in stages, since even the partial ability to slash and/or tombstone is a strict improvement in security.\nThe feature is implemented in two parts, each with its dedicated endpoint. One endpoint handles light client attacks, while the other handles double signing attacks."),(0,a.kt)("h3",{id:"light-client-attack"},"Light Client Attack"),(0,a.kt)("p",null,"In a nutshell, the light client is a process that solely verifies a specific state machine's\nconsensus without executing the transactions. The light clients get new headers by querying\nmultiple nodes, called primary and witness nodes. "),(0,a.kt)("p",null,"Light clients download new headers committed on chain from a primary. Headers can be verified in two ways: sequentially,\nwhere the block height of headers is serial, or using skipping. This second verification method allows light clients to download headers\nwith nonconsecutive block height, where some intermediate headers are skipped (see ",(0,a.kt)("a",{parentName:"p",href:"https://arxiv.org/pdf/2010.07031.pdf"},"Tendermint Light Client, Figure 1 and Figure 3"),").\nAdditionally, light clients are cross-checking new headers obtained from a primary with witnesses to ensure all nodes share the same state."),(0,a.kt)("p",null,"A light client attack occurs when a Byzantine validator sends invalid headers to a light client.\nAs the light client doesn't execute transactions, it can be deceived into trusting corrupted application state transitions.\nFor instance, if a light client receives header ",(0,a.kt)("inlineCode",{parentName:"p"},"A")," from the primary and header ",(0,a.kt)("inlineCode",{parentName:"p"},"B")," from a witness for the same block height ",(0,a.kt)("inlineCode",{parentName:"p"},"H"),",\nand both headers are successfully verified, it indicates a light client attack.\nNote that in this case, either the primary or the witness or both are malicious."),(0,a.kt)("p",null,"The types of light client attacks are defined by analyzing the differences between the conflicting headers.\nThere are three types of light client attacks: lunatic attack, equivocation attack, and amnesia attack.\nFor details, see the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/main/spec/light-client/attacks/notes-on-evidence-handling.md#evidence-handling"},"CometBFT specification"),"."),(0,a.kt)("p",null,"When a light client agent detects two conflicting headers, it will initially verify their traces (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/light/detector.go#L28"},"cometBFT detector"),") using its primary and witness nodes.\nIf these headers pass successful verification, the Byzantine validators will be identified based on the header's commit signatures\nand the type of light client attack. The agent will then transmit this information to its nodes using a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#light-client-attacks"},(0,a.kt)("inlineCode",{parentName:"a"},"LightClientAttackEvidence"))," evidence to be eventually voted on and added to a block.\nNote that from a light client agent perspective, it is not possible to establish whether a primary or a witness node, or both, are malicious.\nTherefore, it will create and send two evidences: one against the primary (sent to the witness), and one against the witness (sent to the primary).\nBoth nodes will then verify it before broadcasting it and adding it to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/evidence/pool.go#L28"},"evidence pool"),".\nIf an evidence is finally committed to a block, the chain's evidence module will execute it, resulting in the jailing and the slashing of the validators responsible for the light client attack."),(0,a.kt)("p",null,"Light clients are a core component of IBC. In the event of a light client attack, IBC relayers notify the affected chains by submitting an ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/v4.4.2/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79"},"IBC misbehavior message"),".\nA misbehavior message includes the conflicting headers that constitute a light client attack evidence. Upon receiving such a message,\na chain will first verify whether these headers would have convinced its light client. This verification is achieved by checking\nthe header states against the light client consensus states (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/v4.4.2/modules/light-clients/07-tendermint/types/misbehaviour_handle.go#L24"},"IBC misbehaviour handler"),'). If the misbehaviour is successfully verified, the chain will then "freeze" the\nlight client, halting any further trust in or updating of its states.'),(0,a.kt)("h3",{id:"double-signing-attack"},"Double Signing Attack"),(0,a.kt)("p",null,"A double signing attack, also known as equivocation,\noccurs when a validator votes for two different blocks in the same round of the CometBFT consensus.\nThis consensus mechanism operates with multiple voting rounds at each block height,\nand it strictly prohibits sending two votes of the same type during a round\n(see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/consensus.md#state-machine-overview"},"CometBFT State Machine Overview"),")."),(0,a.kt)("p",null,"When a node observes two votes from the same peer, it will use these two votes to create\na ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/types/evidence.go#L35"},(0,a.kt)("inlineCode",{parentName:"a"},"DuplicateVoteEvidence")),"\nevidence and gossip it to the other nodes in the network\n(see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#detection"},"CometBFT equivocation detection"),").\nEach node will then verify the evidence according to the CometBFT rules that define a valid double signing infraction, and based on this verification, they will decide whether to add the evidence to a block.\nDuring the evidence verification process, the signatures of the conflicting votes must be verified successfully.\nNote that this is achieved using the public key of the misbehaving validator, along with the chain ID of the chain where the infraction occurred (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#verification"},"CometBFT equivocation verification"),")."),(0,a.kt)("p",null,"Once a double signing evidence is committed to a block, the consensus layer will report the equivocation to the evidence module of the Cosmos SDK application layer.\nThe application will, in turn, punish the malicious validator through jailing, tombstoning and slashing\n(see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/evidence/keeper/infraction.go#L263"},"handleEquivocationEvidence"),")."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("h3",{id:"light-client-attack-1"},"Light Client Attack"),(0,a.kt)("p",null,"In the first part of the feature, we introduce a new endpoint: ",(0,a.kt)("inlineCode",{parentName:"p"},"HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour)"),".\nThe main idea is to leverage the current IBC misbehaviour handling and update it to solely jail and slash the validators that\nperformed a light client attack. Note that in this context, we assume that chains connected via a light client\nshare the same validator set, as is the case with Replicated Security. "),(0,a.kt)("p",null,"This endpoint reuses the IBC client libraries to verify that the misbehaviour headers would have fooled the light client.\nAdditionally, it\u2019s crucial that the endpoint logic results in the slashing and jailing of validators under the same conditions\nas a light client agent detector. Therefore, the endpoint ensures that the two conditions are met:\nthe headers in the misbehaviour message have the same block height, and\nthe light client isn\u2019t expired."),(0,a.kt)("p",null,"After having successfully verified a misbehaviour, the endpoint executes the jailing and slashing of the malicious validators similarly as in the evidence module. "),(0,a.kt)("h3",{id:"double-signing-attack-1"},"Double Signing Attack"),(0,a.kt)("p",null,"In the second part of the feature, we introduce a new endpoint ",(0,a.kt)("inlineCode",{parentName:"p"},"HandleConsumerDoubleVoting(\nctx sdk.Context, evidence *tmtypes.DuplicateVoteEvidence, chainID string, pubkey cryptotypes.PubKey)"),".\nSimply put, the handling logic verifies a double signing evidence against a provided\npublic key and chain ID and, if successful, executes the jailing of the malicious validator who double voted."),(0,a.kt)("p",null,"We define a new\n",(0,a.kt)("inlineCode",{parentName:"p"},"MsgSubmitConsumerDoubleVoting")," message to report a double voting evidence observed\non a consumer chain to the endpoint of the provider chain. This message contains two fields:\na double signing evidence\n",(0,a.kt)("inlineCode",{parentName:"p"},"duplicate_vote_evidence")," and a light client header for the infraction block height,\nreferred to as ",(0,a.kt)("inlineCode",{parentName:"p"},"infraction_block_header"),".\nThe latter provides the malicious validator's public key and the chain ID required to verify the signature of the votes contained in the evidence."),(0,a.kt)("p",null,"Note that double signing evidence is not verified using the same conditions as in the implementation CometBFT (see\n",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/evidence/verify.go#L19"},(0,a.kt)("inlineCode",{parentName:"a"},"verify(evidence types.Evidence)"))," method). Specifically, we do not check that the evidence hasn't expired.\nMore details can be found in the ",(0,a.kt)("a",{parentName:"p",href:"#current-limitations"},'"Current limitations"')," section below. "),(0,a.kt)("p",null,"Upon a successful equivocation verification, the misbehaving validator is jailed for the maximum time\n(see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/evidence/types/params.go#L11"},"DoubleSignJailEndTime"),"\nin the SDK evidence module)."),(0,a.kt)("h3",{id:"current-limitations"},"Current limitations:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"We cannot derive an infraction height from the evidence, so it is only possible to jail validators, not actually slash them.\nTo explain the technical reasons behind this limitation, let's recap the initial consumer initiated slashing logic.\nIn a nutshell, consumer heights are mapped to provider heights through VSCPackets, namely through the so called vscIDs.\nWhen an infraction occurs on the consumer, a SlashPacket containing the vscID obtained from mapping the consumer infraction height\nis sent to the provider. Upon receiving the packet, the provider maps the consumer infraction height to a local infraction height,\nwhich is used to slash the misbehaving validator. In the context of untrusted consumer chains, all their states, including vscIDs,\ncould be corrupted and therefore cannot be used for slashing purposes.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"For the same reasons explained above, the age of a consumer double signing evidence can't be verified,\neither using its infraction height or its unsigned timestamp. Note that changes the jailing behaviour, potentially leading to a validator's jailing based on some \"old\" evidence from a consumer, which wouldn't occur if the consumer were a standalone chain.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"In the first stage of this feature, validators are jailed indefinitely without being tombstoned.\nThe underlying reason is that a malicious validator could take advantage of getting tombstoned\nto avoid being slashed on the provider (",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232#issuecomment-1693127641"},"see comment"),"). ")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Currently, the endpoint can only handle ",(0,a.kt)("em",{parentName:"p"},"equivocation")," light client attacks. This is because the ",(0,a.kt)("em",{parentName:"p"},"lunatic")," attacks require the endpoint to possess the ability to dissociate which header is conflicted or trusted upon receiving a misbehavior message. Without this information, it's not possible to extract the Byzantine validators from the conflicting headers (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/826#discussion_r1268668684"},"comment"),'). In addition, "amnesia" attacks are ignored, similar to CometBFT (see ',(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/main/docs/architecture/tendermint-core/adr-056-light-client-amnesia-attacks.md#decision"},"ADR-056"),")."))),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"It is now possible for the provider chain to jail validators who committed\nlight client or double signing attacks on a consumer chain.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"N/A")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/826"},"ICS misbehaviour handling PR")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/1232"},"Consumer double voting handler PR")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://docs.google.com/document/d/1fe1uSJl1ZIYWXoME3Yf4Aodvz7V597Ric875JH-rigM/edit#heading=h.rv4t8i6d6jfn"},"Architectural diagrams")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-013-equivocation-slashing.md"},"ADR on equivocation slashing"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/4bec4d8c.a17acccd.js b/legacy/assets/js/4bec4d8c.a17acccd.js new file mode 100644 index 0000000000..6780143b16 --- /dev/null +++ b/legacy/assets/js/4bec4d8c.a17acccd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8124],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(n),d=o,f=u["".concat(c,".").concat(d)]||u[d]||m[d]||i;return n?r.createElement(f,a(a({ref:t},p),{},{components:n})):r.createElement(f,a({ref:t},p))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:o,a[1]=s;for(var l=2;l<i;l++)a[l]=n[l];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},8879:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>m,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var r=n(7462),o=(n(7294),n(3905));const i={sidebar_position:4,title:"Offboarding Checklist"},a="Consumer Offboarding",s={unversionedId:"consumer-development/offboarding",id:"version-v3.2.0/consumer-development/offboarding",title:"Offboarding Checklist",description:"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).",source:"@site/versioned_docs/version-v3.2.0/consumer-development/offboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/offboarding",permalink:"/interchain-security/legacy/v3.2.0/consumer-development/offboarding",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Offboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Onboarding Checklist",permalink:"/interchain-security/legacy/v3.2.0/consumer-development/onboarding"},next:{title:"Changeover Procedure",permalink:"/interchain-security/legacy/v3.2.0/consumer-development/changeover-procedure"}},c={},l=[],p={toc:l},u="wrapper";function m(e){let{components:t,...n}=e;return(0,o.kt)(u,(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-offboarding"},"Consumer Offboarding"),(0,o.kt)("p",null,"To offboard a consumer chain simply submit a ",(0,o.kt)("inlineCode",{parentName:"p"},"ConsumerRemovalProposal")," governance proposal listing a ",(0,o.kt)("inlineCode",{parentName:"p"},"stop_time"),". After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates)."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.\n// If it passes, all the consumer chain\'s state is removed from the provider chain. The outstanding unbonding\n// operation funds are released.\n{\n // the title of the proposal\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n}\n')),(0,o.kt)("p",null,"More information will be listed in a future version of this document."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/4c058ddf.3688d9f0.js b/legacy/assets/js/4c058ddf.3688d9f0.js new file mode 100644 index 0000000000..d936aaf827 --- /dev/null +++ b/legacy/assets/js/4c058ddf.3688d9f0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[333],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>d});var o=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function c(e,n){if(null==e)return{};var t,o,r=function(e,n){if(null==e)return{};var t,o,r={},a=Object.keys(e);for(o=0;o<a.length;o++)t=a[o],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o<a.length;o++)t=a[o],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=o.createContext({}),l=function(e){var n=o.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},u=function(e){var n=l(e.components);return o.createElement(s.Provider,{value:n},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},h=o.forwardRef((function(e,n){var t=e.components,r=e.mdxType,a=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=l(t),h=r,d=p["".concat(s,".").concat(h)]||p[h]||m[h]||a;return t?o.createElement(d,i(i({ref:n},u),{},{components:t})):o.createElement(d,i({ref:n},u))}));function d(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var a=t.length,i=new Array(a);i[0]=h;var c={};for(var s in n)hasOwnProperty.call(n,s)&&(c[s]=n[s]);c.originalType=e,c[p]="string"==typeof e?e:r,i[1]=c;for(var l=2;l<a;l++)i[l]=t[l];return o.createElement.apply(null,i)}return o.createElement.apply(null,t)}h.displayName="MDXCreateElement"},6978:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var o=t(7462),r=(t(7294),t(3905));const a={sidebar_position:1},i="Developing an ICS consumer chain",c={unversionedId:"consumer-development/app-integration",id:"version-v3.1.0/consumer-development/app-integration",title:"Developing an ICS consumer chain",description:"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.",source:"@site/versioned_docs/version-v3.1.0/consumer-development/app-integration.md",sourceDirName:"consumer-development",slug:"/consumer-development/app-integration",permalink:"/interchain-security/legacy/v3.1.0/consumer-development/app-integration",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/legacy/v3.1.0/features/slashing"},next:{title:"Consumer Chain Governance",permalink:"/interchain-security/legacy/v3.1.0/consumer-development/consumer-chain-governance"}},s={},l=[{value:"Basic consumer chain",id:"basic-consumer-chain",level:2},{value:"Democracy consumer chain",id:"democracy-consumer-chain",level:2},{value:"Standalone chain to consumer chain changeover",id:"standalone-chain-to-consumer-chain-changeover",level:2}],u={toc:l},p="wrapper";function m(e){let{components:n,...t}=e;return(0,r.kt)(p,(0,o.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"developing-an-ics-consumer-chain"},"Developing an ICS consumer chain"),(0,r.kt)("p",null,"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.\nTo help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications."),(0,r.kt)("h2",{id:"basic-consumer-chain"},"Basic consumer chain"),(0,r.kt)("p",null,"The source code for the example app can be found ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer"},"here"),"."),(0,r.kt)("p",null,"Please note that consumer chains do not implement the staking module - the validator set is replicated from the provider, meaning that the provider and the consumer use the same validator set and their stake on the provider directly determines their stake on the consumer.\nAt present there is no opt-in mechanism available, so all validators of the provider must also validate on the provider chain."),(0,r.kt)("p",null,"Your chain should import the consumer module from ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," and register it in the correct places in your ",(0,r.kt)("inlineCode",{parentName:"p"},"app.go"),".\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in.\nYou should not need to manage or override any code from the ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module."),(0,r.kt)("h2",{id:"democracy-consumer-chain"},"Democracy consumer chain"),(0,r.kt)("p",null,"The source code for the example app can be found ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy"},"here"),"."),(0,r.kt)("p",null,"This type of consumer chain wraps the basic CosmosSDK ",(0,r.kt)("inlineCode",{parentName:"p"},"x/distribution"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"x/staking")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"x/governance")," modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system."),(0,r.kt)("p",null,"This allows the consumer chain to leverage those modules while also using the ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module."),(0,r.kt)("p",null,'With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.'),(0,r.kt)("h2",{id:"standalone-chain-to-consumer-chain-changeover"},"Standalone chain to consumer chain changeover"),(0,r.kt)("p",null,"This feature is being actively worked on. Information will be provided at a later time."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/4c7d82ee.da063855.js b/legacy/assets/js/4c7d82ee.da063855.js new file mode 100644 index 0000000000..f741939873 --- /dev/null +++ b/legacy/assets/js/4c7d82ee.da063855.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7649],{3905:(e,t,i)=>{i.d(t,{Zo:()=>h,kt:()=>m});var n=i(7294);function a(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}function o(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function s(e){for(var t=1;t<arguments.length;t++){var i=null!=arguments[t]?arguments[t]:{};t%2?o(Object(i),!0).forEach((function(t){a(e,t,i[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(i)):o(Object(i)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(i,t))}))}return e}function r(e,t){if(null==e)return{};var i,n,a=function(e,t){if(null==e)return{};var i,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)i=o[n],t.indexOf(i)>=0||(a[i]=e[i]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)i=o[n],t.indexOf(i)>=0||Object.prototype.propertyIsEnumerable.call(e,i)&&(a[i]=e[i])}return a}var c=n.createContext({}),l=function(e){var t=n.useContext(c),i=t;return e&&(i="function"==typeof e?e(t):s(s({},t),e)),i},h=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var i=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,h=r(e,["components","mdxType","originalType","parentName"]),d=l(i),p=a,m=d["".concat(c,".").concat(p)]||d[p]||u[p]||o;return i?n.createElement(m,s(s({ref:t},h),{},{components:i})):n.createElement(m,s({ref:t},h))}));function m(e,t){var i=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=i.length,s=new Array(o);s[0]=p;var r={};for(var c in t)hasOwnProperty.call(t,c)&&(r[c]=t[c]);r.originalType=e,r[d]="string"==typeof e?e:a,s[1]=r;for(var l=2;l<o;l++)s[l]=i[l];return n.createElement.apply(null,s)}return n.createElement.apply(null,i)}p.displayName="MDXCreateElement"},1089:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>u,frontMatter:()=>o,metadata:()=>r,toc:()=>l});var n=i(7462),a=(i(7294),i(3905));const o={sidebar_position:4,title:"Cryptographic verification of equivocation evidence"},s="ADR 005: Cryptographic verification of equivocation evidence",r={unversionedId:"adrs/adr-005-cryptographic-equivocation-verification",id:"adrs/adr-005-cryptographic-equivocation-verification",title:"Cryptographic verification of equivocation evidence",description:"Changelog",source:"@site/docs/adrs/adr-005-cryptographic-equivocation-verification.md",sourceDirName:"adrs",slug:"/adrs/adr-005-cryptographic-equivocation-verification",permalink:"/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification",draft:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Cryptographic verification of equivocation evidence"},sidebar:"tutorialSidebar",previous:{title:"Equivocation governance proposal",permalink:"/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposal"},next:{title:"Throttle with retries",permalink:"/interchain-security/legacy/adrs/adr-008-throttle-retries"}},c={},l=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Light Client Attack",id:"light-client-attack",level:3},{value:"Double Signing Attack",id:"double-signing-attack",level:3},{value:"Decision",id:"decision",level:2},{value:"Light Client Attack",id:"light-client-attack-1",level:3},{value:"Double Signing Attack",id:"double-signing-attack-1",level:3},{value:"Current limitations:",id:"current-limitations",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}],h={toc:l},d="wrapper";function u(e){let{components:t,...i}=e;return(0,a.kt)(d,(0,n.Z)({},h,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-005-cryptographic-verification-of-equivocation-evidence"},"ADR 005: Cryptographic verification of equivocation evidence"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"5/1/2023: First draft"),(0,a.kt)("li",{parentName:"ul"},"7/23/2023: Add light client attacks handling"),(0,a.kt)("li",{parentName:"ul"},"9/6/2023: Add double signing attacks handling")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"Currently, we use a governance proposal to slash validators for equivocation (double signing and light client attacks).\nEvery proposal needs to go through a (two weeks) voting period before it can be approved.\nGiven a three-week unbonding period, this means that an equivocation proposal needs to be submitted within one week since the infraction occurred."),(0,a.kt)("p",null,"This ADR proposes a system to slash validators automatically for equivocation, immediately upon the provider chain's receipt of the evidence. Another thing to note is that we intend to introduce this system in stages, since even the partial ability to slash and/or tombstone is a strict improvement in security.\nThe feature is implemented in two parts, each with its dedicated endpoint. One endpoint handles light client attacks, while the other handles double signing attacks."),(0,a.kt)("h3",{id:"light-client-attack"},"Light Client Attack"),(0,a.kt)("p",null,"In a nutshell, the light client is a process that solely verifies a specific state machine's\nconsensus without executing the transactions. The light clients get new headers by querying\nmultiple nodes, called primary and witness nodes. "),(0,a.kt)("p",null,"Light clients download new headers committed on chain from a primary. Headers can be verified in two ways: sequentially,\nwhere the block height of headers is serial, or using skipping. This second verification method allows light clients to download headers\nwith nonconsecutive block height, where some intermediate headers are skipped (see ",(0,a.kt)("a",{parentName:"p",href:"https://arxiv.org/pdf/2010.07031.pdf"},"Tendermint Light Client, Figure 1 and Figure 3"),").\nAdditionally, light clients are cross-checking new headers obtained from a primary with witnesses to ensure all nodes share the same state."),(0,a.kt)("p",null,"A light client attack occurs when a Byzantine validator sends invalid headers to a light client.\nAs the light client doesn't execute transactions, it can be deceived into trusting corrupted application state transitions.\nFor instance, if a light client receives header ",(0,a.kt)("inlineCode",{parentName:"p"},"A")," from the primary and header ",(0,a.kt)("inlineCode",{parentName:"p"},"B")," from a witness for the same block height ",(0,a.kt)("inlineCode",{parentName:"p"},"H"),",\nand both headers are successfully verified, it indicates a light client attack.\nNote that in this case, either the primary or the witness or both are malicious."),(0,a.kt)("p",null,"The types of light client attacks are defined by analyzing the differences between the conflicting headers.\nThere are three types of light client attacks: lunatic attack, equivocation attack, and amnesia attack.\nFor details, see the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/main/spec/light-client/attacks/notes-on-evidence-handling.md#evidence-handling"},"CometBFT specification"),"."),(0,a.kt)("p",null,"When a light client agent detects two conflicting headers, it will initially verify their traces (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/light/detector.go#L28"},"cometBFT detector"),") using its primary and witness nodes.\nIf these headers pass successful verification, the Byzantine validators will be identified based on the header's commit signatures\nand the type of light client attack. The agent will then transmit this information to its nodes using a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#light-client-attacks"},(0,a.kt)("inlineCode",{parentName:"a"},"LightClientAttackEvidence"))," evidence to be eventually voted on and added to a block.\nNote that from a light client agent perspective, it is not possible to establish whether a primary or a witness node, or both, are malicious.\nTherefore, it will create and send two evidences: one against the primary (sent to the witness), and one against the witness (sent to the primary).\nBoth nodes will then verify it before broadcasting it and adding it to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/evidence/pool.go#L28"},"evidence pool"),".\nIf an evidence is finally committed to a block, the chain's evidence module will execute it, resulting in the jailing and the slashing of the validators responsible for the light client attack."),(0,a.kt)("p",null,"Light clients are a core component of IBC. In the event of a light client attack, IBC relayers notify the affected chains by submitting an ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/v4.4.2/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79"},"IBC misbehavior message"),".\nA misbehavior message includes the conflicting headers that constitute a light client attack evidence. Upon receiving such a message,\na chain will first verify whether these headers would have convinced its light client. This verification is achieved by checking\nthe header states against the light client consensus states (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/v4.4.2/modules/light-clients/07-tendermint/types/misbehaviour_handle.go#L24"},"IBC misbehaviour handler"),'). If the misbehaviour is successfully verified, the chain will then "freeze" the\nlight client, halting any further trust in or updating of its states.'),(0,a.kt)("h3",{id:"double-signing-attack"},"Double Signing Attack"),(0,a.kt)("p",null,"A double signing attack, also known as equivocation,\noccurs when a validator votes for two different blocks in the same round of the CometBFT consensus.\nThis consensus mechanism operates with multiple voting rounds at each block height,\nand it strictly prohibits sending two votes of the same type during a round\n(see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/consensus.md#state-machine-overview"},"CometBFT State Machine Overview"),")."),(0,a.kt)("p",null,"When a node observes two votes from the same peer, it will use these two votes to create\na ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/types/evidence.go#L35"},(0,a.kt)("inlineCode",{parentName:"a"},"DuplicateVoteEvidence")),"\nevidence and gossip it to the other nodes in the network\n(see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#detection"},"CometBFT equivocation detection"),").\nEach node will then verify the evidence according to the CometBFT rules that define a valid double signing infraction, and based on this verification, they will decide whether to add the evidence to a block.\nDuring the evidence verification process, the signatures of the conflicting votes must be verified successfully.\nNote that this is achieved using the public key of the misbehaving validator, along with the chain ID of the chain where the infraction occurred (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#verification"},"CometBFT equivocation verification"),")."),(0,a.kt)("p",null,"Once a double signing evidence is committed to a block, the consensus layer will report the equivocation to the evidence module of the Cosmos SDK application layer.\nThe application will, in turn, punish the malicious validator through jailing, tombstoning and slashing\n(see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/evidence/keeper/infraction.go#L263"},"handleEquivocationEvidence"),")."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("h3",{id:"light-client-attack-1"},"Light Client Attack"),(0,a.kt)("p",null,"In the first part of the feature, we introduce a new endpoint: ",(0,a.kt)("inlineCode",{parentName:"p"},"HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour)"),".\nThe main idea is to leverage the current IBC misbehaviour handling and update it to solely jail and slash the validators that\nperformed a light client attack. Note that in this context, we assume that chains connected via a light client\nshare the same validator set, as is the case with Replicated Security. "),(0,a.kt)("p",null,"This endpoint reuses the IBC client libraries to verify that the misbehaviour headers would have fooled the light client.\nAdditionally, it\u2019s crucial that the endpoint logic results in the slashing and jailing of validators under the same conditions\nas a light client agent detector. Therefore, the endpoint ensures that the two conditions are met:\nthe headers in the misbehaviour message have the same block height, and\nthe light client isn\u2019t expired."),(0,a.kt)("p",null,"After having successfully verified a misbehaviour, the endpoint executes the jailing and slashing of the malicious validators similarly as in the evidence module. "),(0,a.kt)("h3",{id:"double-signing-attack-1"},"Double Signing Attack"),(0,a.kt)("p",null,"In the second part of the feature, we introduce a new endpoint ",(0,a.kt)("inlineCode",{parentName:"p"},"HandleConsumerDoubleVoting(\nctx sdk.Context, evidence *tmtypes.DuplicateVoteEvidence, chainID string, pubkey cryptotypes.PubKey)"),".\nSimply put, the handling logic verifies a double signing evidence against a provided\npublic key and chain ID and, if successful, executes the jailing of the malicious validator who double voted."),(0,a.kt)("p",null,"We define a new\n",(0,a.kt)("inlineCode",{parentName:"p"},"MsgSubmitConsumerDoubleVoting")," message to report a double voting evidence observed\non a consumer chain to the endpoint of the provider chain. This message contains two fields:\na double signing evidence\n",(0,a.kt)("inlineCode",{parentName:"p"},"duplicate_vote_evidence")," and a light client header for the infraction block height,\nreferred to as ",(0,a.kt)("inlineCode",{parentName:"p"},"infraction_block_header"),".\nThe latter provides the malicious validator's public key and the chain ID required to verify the signature of the votes contained in the evidence."),(0,a.kt)("p",null,"Note that double signing evidence is not verified using the same conditions as in the implementation CometBFT (see\n",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/evidence/verify.go#L19"},(0,a.kt)("inlineCode",{parentName:"a"},"verify(evidence types.Evidence)"))," method). Specifically, we do not check that the evidence hasn't expired.\nMore details can be found in the ",(0,a.kt)("a",{parentName:"p",href:"#current-limitations"},'"Current limitations"')," section below. "),(0,a.kt)("p",null,"Upon a successful equivocation verification, the misbehaving validator is jailed for the maximum time\n(see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/evidence/types/params.go#L11"},"DoubleSignJailEndTime"),"\nin the SDK evidence module)."),(0,a.kt)("h3",{id:"current-limitations"},"Current limitations:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"We cannot derive an infraction height from the evidence, so it is only possible to jail validators, not actually slash them.\nTo explain the technical reasons behind this limitation, let's recap the initial consumer initiated slashing logic.\nIn a nutshell, consumer heights are mapped to provider heights through VSCPackets, namely through the so called vscIDs.\nWhen an infraction occurs on the consumer, a SlashPacket containing the vscID obtained from mapping the consumer infraction height\nis sent to the provider. Upon receiving the packet, the provider maps the consumer infraction height to a local infraction height,\nwhich is used to slash the misbehaving validator. In the context of untrusted consumer chains, all their states, including vscIDs,\ncould be corrupted and therefore cannot be used for slashing purposes.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"For the same reasons explained above, the age of a consumer double signing evidence can't be verified,\neither using its infraction height or its unsigned timestamp. Note that changes the jailing behaviour, potentially leading to a validator's jailing based on some \"old\" evidence from a consumer, which wouldn't occur if the consumer were a standalone chain.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"In the first stage of this feature, validators are jailed indefinitely without being tombstoned.\nThe underlying reason is that a malicious validator could take advantage of getting tombstoned\nto avoid being slashed on the provider (",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232#issuecomment-1693127641"},"see comment"),"). ")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},'Currently, the endpoint can only handle "equivocation" light client attacks. This is because the "lunatic" attacks require the endpoint to possess the ability to dissociate which header is conflicted or trusted upon receiving a misbehavior message. Without this information, it\'s not possible to define the Byzantine validators from the conflicting headers (see ',(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/826#discussion_r1268668684"},"comment"),")."))),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"It is now possible for the provider chain to jail validators who committed\nlight client or double signing attacks on a consumer chain.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"N/A")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/826"},"ICS misbehaviour handling PR")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/1232"},"Consumer double voting handler PR")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://docs.google.com/document/d/1fe1uSJl1ZIYWXoME3Yf4Aodvz7V597Ric875JH-rigM/edit#heading=h.rv4t8i6d6jfn"},"Architectural diagrams")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-013-equivocation-slashing.md"},"ADR on equivocation slashing"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/4c855390.3b0f05f7.js b/legacy/assets/js/4c855390.3b0f05f7.js new file mode 100644 index 0000000000..76b5c8c7b0 --- /dev/null +++ b/legacy/assets/js/4c855390.3b0f05f7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[375],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>y});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?c(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):c(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function a(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},c=Object.keys(e);for(r=0;r<c.length;r++)n=c[r],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(r=0;r<c.length;r++)n=c[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var p=r.createContext({}),s=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},l=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,c=e.originalType,p=e.parentName,l=a(e,["components","mdxType","originalType","parentName"]),u=s(n),d=i,y=u["".concat(p,".").concat(d)]||u[d]||f[d]||c;return n?r.createElement(y,o(o({ref:t},l),{},{components:n})):r.createElement(y,o({ref:t},l))}));function y(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var c=n.length,o=new Array(c);o[0]=d;var a={};for(var p in t)hasOwnProperty.call(t,p)&&(a[p]=t[p]);a.originalType=e,a[u]="string"==typeof e?e:i,o[1]=a;for(var s=2;s<c;s++)o[s]=n[s];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},3614:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>f,frontMatter:()=>c,metadata:()=>a,toc:()=>s});var r=n(7462),i=(n(7294),n(3905));const c={sidebar_position:4},o="Technical Specification",a={unversionedId:"introduction/technical-specification",id:"version-v2.0.0/introduction/technical-specification",title:"Technical Specification",description:"For a technical deep dive into the replicated security protocol, see the specification.",source:"@site/versioned_docs/version-v2.0.0/introduction/technical-specification.md",sourceDirName:"introduction",slug:"/introduction/technical-specification",permalink:"/interchain-security/legacy/v2.0.0/introduction/technical-specification",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Parameters",permalink:"/interchain-security/legacy/v2.0.0/introduction/params"},next:{title:"Key Assignment",permalink:"/interchain-security/legacy/v2.0.0/features/key-assignment"}},p={},s=[],l={toc:s},u="wrapper";function f(e){let{components:t,...n}=e;return(0,i.kt)(u,(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"technical-specification"},"Technical Specification"),(0,i.kt)("p",null,"For a technical deep dive into the replicated security protocol, see the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/README.md"},"specification"),"."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/4cc37eaf.1fce0a56.js b/legacy/assets/js/4cc37eaf.1fce0a56.js new file mode 100644 index 0000000000..2c0d3981ae --- /dev/null +++ b/legacy/assets/js/4cc37eaf.1fce0a56.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4322],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,m=u["".concat(c,".").concat(h)]||u[h]||d[h]||i;return n?a.createElement(m,o(o({ref:t},p),{},{components:n})):a.createElement(m,o({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:r,o[1]=s;for(var l=2;l<i;l++)o[l]=n[l];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},9117:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var a=n(7462),r=(n(7294),n(3905));const i={sidebar_position:2,title:"Joining Replicated Security testnet"},o="Introduction",s={unversionedId:"validators/joining-testnet",id:"version-v2.4.0-lsm/validators/joining-testnet",title:"Joining Replicated Security testnet",description:"This short guide will teach you how to join the Replicated Security testnet.",source:"@site/versioned_docs/version-v2.4.0-lsm/validators/joining-testnet.md",sourceDirName:"validators",slug:"/validators/joining-testnet",permalink:"/interchain-security/legacy/v2.4.0-lsm/validators/joining-testnet",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"Joining Replicated Security testnet"},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/legacy/v2.4.0-lsm/validators/overview"},next:{title:"Withdrawing consumer chain validator rewards",permalink:"/interchain-security/legacy/v2.4.0-lsm/validators/withdraw_rewards"}},c={},l=[{value:"Initialization",id:"initialization",level:2},{value:"Re-using consensus key",id:"re-using-consensus-key",level:2},{value:"Assigning consensus keys",id:"assigning-consensus-keys",level:2},{value:"Baryon",id:"baryon",level:2},{value:"Noble",id:"noble",level:2}],p={toc:l},u="wrapper";function d(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"This short guide will teach you how to join the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security"},"Replicated Security testnet"),"."),(0,r.kt)("p",null,"The experience gained in the testnet will prepare you for validating interchain secured chains."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set."),(0,r.kt)("p",{parentName:"admonition"},"For general information about running cosmos-sdk based chains check out the ",(0,r.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html"},"validator basics")," and ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/main/run-node/run-node"},"Running a Node section")," of Cosmos SDK docs")),(0,r.kt)("h1",{id:"joining-the-provider-chain"},"Joining the provider chain"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain.")),(0,r.kt)("p",null,"A comprehensive guide is available ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security/provider"},"here"),"."),(0,r.kt)("h2",{id:"initialization"},"Initialization"),(0,r.kt)("p",null,"First, initialize your ",(0,r.kt)("inlineCode",{parentName:"p"},"$NODE_HOME")," using the ",(0,r.kt)("inlineCode",{parentName:"p"},"provider")," chain binary."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"NODE_MONIKER=<your_node>\nCHAIN_ID=provider\nNODE_HOME=<path_to_your_home>\n\ngaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME\n")),(0,r.kt)("p",null,"Add your key to the keyring - more details available ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/main/run-node/keyring"},"here"),"."),(0,r.kt)("p",null,"In this example we will use the ",(0,r.kt)("inlineCode",{parentName:"p"},"test")," keyring-backend. This option is not safe to use in production."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad keys add <key_moniker> --keyring-backend test\n\n# save the address as variable for later use\nMY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)\n")),(0,r.kt)("p",null,"Before issuing any transactions, use the ",(0,r.kt)("inlineCode",{parentName:"p"},"provider")," testnet faucet to add funds to your address."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider\n\n# example output:\n{\n "address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",\n "amount": "10000000uatom",\n "chain": "provider",\n "hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",\n "status": "success"\n}\n')),(0,r.kt)("p",null,"Then, use the account associated with the keyring to issue a ",(0,r.kt)("inlineCode",{parentName:"p"},"create-validator")," transaction which will register your validator on chain."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad tx staking create-validator \\\n --amount=1000000uatom \\\n --pubkey=$(gaiad tendermint show-validator) \\\n --moniker="choose a moniker" \\\n --chain-id=$CHAIN_ID" \\\n --commission-rate="0.10" \\\n --commission-max-rate="0.20" \\\n --commission-max-change-rate="0.01" \\\n --min-self-delegation="1000000" \\\n --gas="auto" \\\n --gas-prices="0.0025uatom" \\\n --from=<key_moniker>\n')),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Check this ",(0,r.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html#edit-validator-description"},"guide")," to edit your validator.")),(0,r.kt)("p",null,"After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use ",(0,r.kt)("inlineCode",{parentName:"p"},"statesync")," to catch up to the rest of the network."),(0,r.kt)("p",null,"You can use this script to modify your ",(0,r.kt)("inlineCode",{parentName:"p"},"config.toml")," with the required statesync parameters."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"# create the statesync script\n$: cd $NODE_HOME\n$: touch statesync.sh\n$ chmod 700 statesync.sh # make executable\n")),(0,r.kt)("p",null,"Paste the following instructions into the ",(0,r.kt)("inlineCode",{parentName:"p"},"statesync.sh"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'#!/bin/bash\n\nSNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"\n\nLATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \\\nBLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \\\nTRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)\n\nsed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\\1true| ; \\\ns|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\\1\\"$SNAP_RPC,$SNAP_RPC\\"| ; \\\ns|^(trust_height[[:space:]]+=[[:space:]]+).*$|\\1$BLOCK_HEIGHT| ; \\\ns|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\\1\\"$TRUST_HASH\\"|" $NODE_HOME/config/config.toml\n')),(0,r.kt)("p",null,"Then, you can execute the script:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"$: ./statesync.sh # setup config.toml for statesync\n")),(0,r.kt)("p",null,"Finally, copy the provider genesis and start your node:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/replicated-security/provider/provider-genesis.json\n$: wget $GENESIS_URL -O genesis.json\n$: genesis.json $NODE_HOME/config/genesis.json\n# start the service\n$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"\n')),(0,r.kt)("p",null,"Additional scripts to setup your nodes are available ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/provider/join-rs-provider.sh"},"here")," and ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/provider/join-rs-provider-cv.sh"},"here"),". The scripts will configure your node and create the required services - the scripts only work in linux environments."),(0,r.kt)("h1",{id:"joining-consumer-chains"},"Joining consumer chains"),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Once you reach the active set on the provider chain, you will be required to validate all available consumer chains."),(0,r.kt)("p",{parentName:"admonition"},"You can use the same consensus key on all consumer chains, or opt to use a different key on each consumer chain.\nCheck out this ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.4.0-lsm/features/key-assignment"},"guide")," to learn more about key assignment in replicated security.")),(0,r.kt)("p",null,"To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"When running the provider chain and consumers on the same machine please update the ",(0,r.kt)("inlineCode",{parentName:"p"},"PORT")," numbers for each of them and make sure they do not overlap (otherwise the binaries will not start)."),(0,r.kt)("p",{parentName:"admonition"},"Important ports to re-configure:"),(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--rpc.laddr")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--p2p.laddr")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--api.address")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--grpc.address")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--grpc-web.address")))),(0,r.kt)("h2",{id:"re-using-consensus-key"},"Re-using consensus key"),(0,r.kt)("p",null,"To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the ",(0,r.kt)("inlineCode",{parentName:"p"},"priv_validator_key.json")," into the home directory of your consumer chain (",(0,r.kt)("inlineCode",{parentName:"p"},"<consumer_home>/config/priv_validator_key.json"),")."),(0,r.kt)("p",null,"When you start the chain, the consensus key will be the same on the provider and the consumer chain."),(0,r.kt)("h2",{id:"assigning-consensus-keys"},"Assigning consensus keys"),(0,r.kt)("p",null,"Whenever you initialize a new node, it will be configured with a consensus key you can use."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'# machine running consumer chain\nconsumerd init <node_moniker> --home <home_path> --chain-id consumer-1\n\n# use the output of this command to get the consumer chain consensus key\nconsumerd tendermint show-validator\n# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}\n')),(0,r.kt)("p",null,"Then, let the provider know which key you will be using for the consumer chain:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"# machine running the provider chain\ngaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b block -y -o json\n")),(0,r.kt)("p",null,"After this step, you are ready to copy the consumer genesis into your nodes's ",(0,r.kt)("inlineCode",{parentName:"p"},"/config")," folder, start your consumer chain node and catch up to the network."),(0,r.kt)("h2",{id:"baryon"},"Baryon"),(0,r.kt)("p",null,"You can find the onboarding repo instructions for the Baryon chain ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/stopped/baryon-1/README.md"},"here")),(0,r.kt)("h2",{id:"noble"},"Noble"),(0,r.kt)("p",null,"You can find the onboarding repo instructions for the Noble chain ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/stopped/noble-1/README.md"},"here")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/4edc808e.20fd5a0c.js b/legacy/assets/js/4edc808e.20fd5a0c.js new file mode 100644 index 0000000000..e7b9b50157 --- /dev/null +++ b/legacy/assets/js/4edc808e.20fd5a0c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4173],{3905:(e,r,t)=>{t.d(r,{Zo:()=>d,kt:()=>f});var n=t(7294);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function o(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?i(Object(t),!0).forEach((function(r){a(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function c(e,r){if(null==e)return{};var t,n,a=function(e,r){if(null==e)return{};var t,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=n.createContext({}),u=function(e){var r=n.useContext(s),t=r;return e&&(t="function"==typeof e?e(r):o(o({},r),e)),t},d=function(e){var r=u(e.components);return n.createElement(s.Provider,{value:r},e.children)},l="mdxType",m={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},p=n.forwardRef((function(e,r){var t=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,d=c(e,["components","mdxType","originalType","parentName"]),l=u(t),p=a,f=l["".concat(s,".").concat(p)]||l[p]||m[p]||i;return t?n.createElement(f,o(o({ref:r},d),{},{components:t})):n.createElement(f,o({ref:r},d))}));function f(e,r){var t=arguments,a=r&&r.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=p;var c={};for(var s in r)hasOwnProperty.call(r,s)&&(c[s]=r[s]);c.originalType=e,c[l]="string"==typeof e?e:a,o[1]=c;for(var u=2;u<i;u++)o[u]=t[u];return n.createElement.apply(null,o)}return n.createElement.apply(null,t)}p.displayName="MDXCreateElement"},2307:(e,r,t)=>{t.d(r,{Z:()=>i});var n=t(7294);const a=function(e){return n.createElement("a",{href:e.href,className:"border shadow rounded-sm border-stone-200 dark:border-stone-800 dark:bg-neutral-900 hover:border-stone-300 hover:shadow-lg dark:hover:border-stone-200 transition-all duration-200 no-underline"},n.createElement("div",{className:"p-6"},n.createElement("h2",{className:""},e.header),n.createElement("p",{className:""},e.summary)))};const i=function(e){return n.createElement("div",{className:"card-section grid grid-cols-1 lg:grid-cols-2 gap-4 no-underline"},e.cards.map(((e,r)=>n.createElement(a,{key:r,href:e.href,header:e.header,summary:e.summary}))))}},8758:(e,r,t)=>{t.d(r,{Z:()=>n});const n=[{href:"/interchain-security/introduction/overview",header:"Basic concepts",summary:"Get started with the basic concepts and ideas."},{href:"/interchain-security/consumer-development/app-integration",header:"Start building",summary:"Click here to start building with Interchain security"},{href:"/interchain-security/features/key-assignment",header:"Feature: Key Assignment",summary:"Learn about the key assignment feature"},{href:"/interchain-security/features/reward-distribution",header:"Feature: Reward Distribution",summary:"Learn about consumer chain rewards distribution"},{href:"/interchain-security/consumer-development/onboarding",header:"Onboarding Checklist",summary:"Checklist to help you integrate Interchain Security, get support and onboard validators"},{href:"/interchain-security/faq",header:"FAQ",summary:"Frequently asked questions about the protocol and its implications"}]},1788:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>d,contentTitle:()=>s,default:()=>f,frontMatter:()=>c,metadata:()=>u,toc:()=>l});var n=t(7462),a=(t(7294),t(3905)),i=t(2307),o=t(8758);const c={sidebar_position:1},s="Interchain Security Docs",u={unversionedId:"index",id:"index",title:"Interchain Security Docs",description:"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.",source:"@site/docs/index.mdx",sourceDirName:".",slug:"/",permalink:"/interchain-security/legacy/",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",next:{title:"Overview",permalink:"/interchain-security/legacy/introduction/overview"}},d={},l=[],m={toc:l},p="wrapper";function f(e){let{components:r,...t}=e;return(0,a.kt)(p,(0,n.Z)({},m,t,{components:r,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"interchain-security-docs"},"Interchain Security Docs"),(0,a.kt)("p",null,"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains."),(0,a.kt)("p",null,"Here you can find information about replicated security, consumer chain development and instructions for validator onboarding."),(0,a.kt)(i.Z,{cards:o.Z,mdxType:"CardSection"}))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/4f50acdf.f48be075.js b/legacy/assets/js/4f50acdf.f48be075.js new file mode 100644 index 0000000000..3ebf2fdf3e --- /dev/null +++ b/legacy/assets/js/4f50acdf.f48be075.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9815],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,m=u["".concat(c,".").concat(h)]||u[h]||d[h]||i;return n?a.createElement(m,o(o({ref:t},p),{},{components:n})):a.createElement(m,o({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:r,o[1]=s;for(var l=2;l<i;l++)o[l]=n[l];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},177:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var a=n(7462),r=(n(7294),n(3905));const i={sidebar_position:2,title:"Joining Replicated Security testnet"},o=void 0,s={unversionedId:"validators/joining-testnet",id:"validators/joining-testnet",title:"Joining Replicated Security testnet",description:"Introduction",source:"@site/docs/validators/joining-testnet.md",sourceDirName:"validators",slug:"/validators/joining-testnet",permalink:"/interchain-security/legacy/validators/joining-testnet",draft:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"Joining Replicated Security testnet"},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/legacy/validators/overview"},next:{title:"Withdrawing consumer chain validator rewards",permalink:"/interchain-security/legacy/validators/withdraw_rewards"}},c={},l=[{value:"Introduction",id:"introduction",level:2},{value:"Joining the provider chain",id:"joining-the-provider-chain",level:2},{value:"Initialization",id:"initialization",level:2},{value:"Joining consumer chains",id:"joining-consumer-chains",level:2},{value:"Re-using consensus key",id:"re-using-consensus-key",level:2},{value:"Assigning consensus keys",id:"assigning-consensus-keys",level:2}],p={toc:l},u="wrapper";function d(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"This short guide will teach you how to join the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security"},"Replicated Security testnet"),"."),(0,r.kt)("p",null,"The experience gained in the testnet will prepare you for validating interchain secured chains."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set."),(0,r.kt)("p",{parentName:"admonition"},"For general information about running cosmos-sdk based chains check out the ",(0,r.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html"},"validator basics")," and ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/main/run-node/run-node"},"Running a Node section")," of Cosmos SDK docs")),(0,r.kt)("h2",{id:"joining-the-provider-chain"},"Joining the provider chain"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain.")),(0,r.kt)("p",null,"A comprehensive guide is available ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security/provider"},"here"),"."),(0,r.kt)("h2",{id:"initialization"},"Initialization"),(0,r.kt)("p",null,"First, initialize your ",(0,r.kt)("inlineCode",{parentName:"p"},"$NODE_HOME")," using the ",(0,r.kt)("inlineCode",{parentName:"p"},"provider")," chain binary."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"NODE_MONIKER=<your_node>\nCHAIN_ID=provider\nNODE_HOME=<path_to_your_home>\n\ngaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME\n")),(0,r.kt)("p",null,"Add your key to the keyring - more details available ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/main/run-node/keyring"},"here"),"."),(0,r.kt)("p",null,"In this example we will use the ",(0,r.kt)("inlineCode",{parentName:"p"},"test")," keyring-backend. This option is not safe to use in production."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad keys add <key_moniker> --keyring-backend test\n\n# save the address as variable for later use\nMY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)\n")),(0,r.kt)("p",null,"Before issuing any transactions, use the ",(0,r.kt)("inlineCode",{parentName:"p"},"provider")," testnet faucet to add funds to your address."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider\n\n# example output:\n{\n "address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",\n "amount": "10000000uatom",\n "chain": "provider",\n "hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",\n "status": "success"\n}\n')),(0,r.kt)("p",null,"Then, use the account associated with the keyring to issue a ",(0,r.kt)("inlineCode",{parentName:"p"},"create-validator")," transaction which will register your validator on chain."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad tx staking create-validator \\\n --amount=1000000uatom \\\n --pubkey=$(gaiad tendermint show-validator) \\\n --moniker="choose a moniker" \\\n --chain-id=$CHAIN_ID" \\\n --commission-rate="0.10" \\\n --commission-max-rate="0.20" \\\n --commission-max-change-rate="0.01" \\\n --min-self-delegation="1000000" \\\n --gas="auto" \\\n --gas-prices="0.0025uatom" \\\n --from=<key_moniker>\n')),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Check this ",(0,r.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html#edit-validator-description"},"guide")," to edit your validator.")),(0,r.kt)("p",null,"After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use ",(0,r.kt)("inlineCode",{parentName:"p"},"statesync")," to catch up to the rest of the network."),(0,r.kt)("p",null,"You can use this script to modify your ",(0,r.kt)("inlineCode",{parentName:"p"},"config.toml")," with the required statesync parameters."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"# create the statesync script\n$: cd $NODE_HOME\n$: touch statesync.sh\n$ chmod 700 statesync.sh # make executable\n")),(0,r.kt)("p",null,"Paste the following instructions into the ",(0,r.kt)("inlineCode",{parentName:"p"},"statesync.sh"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'#!/bin/bash\n\nSNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"\n\nLATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \\\nBLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \\\nTRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)\n\nsed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\\1true| ; \\\ns|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\\1\\"$SNAP_RPC,$SNAP_RPC\\"| ; \\\ns|^(trust_height[[:space:]]+=[[:space:]]+).*$|\\1$BLOCK_HEIGHT| ; \\\ns|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\\1\\"$TRUST_HASH\\"|" $NODE_HOME/config/config.toml\n')),(0,r.kt)("p",null,"Then, you can execute the script:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"$: ./statesync.sh # setup config.toml for statesync\n")),(0,r.kt)("p",null,"Finally, copy the provider genesis and start your node:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/replicated-security/provider/provider-genesis.json\n$: wget $GENESIS_URL -O genesis.json\n$: genesis.json $NODE_HOME/config/genesis.json\n# start the service\n$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"\n')),(0,r.kt)("p",null,"Additional scripts to setup your nodes are available ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/provider/join-rs-provider.sh"},"here")," and ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/provider/join-rs-provider-cv.sh"},"here"),". The scripts will configure your node and create the required services - the scripts only work in linux environments."),(0,r.kt)("h2",{id:"joining-consumer-chains"},"Joining consumer chains"),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Once you reach the active set on the provider chain, you will be required to validate all available consumer chains."),(0,r.kt)("p",{parentName:"admonition"},"You can use the same consensus key on all consumer chains, or opt to use a different key on each consumer chain.\nCheck out this ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/features/key-assignment"},"guide")," to learn more about key assignment in replicated security.")),(0,r.kt)("p",null,"To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"When running the provider chain and consumers on the same machine please update the ",(0,r.kt)("inlineCode",{parentName:"p"},"PORT")," numbers for each of them and make sure they do not overlap (otherwise the binaries will not start)."),(0,r.kt)("p",{parentName:"admonition"},"Important ports to re-configure:"),(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--rpc.laddr")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--p2p.laddr")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--api.address")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--grpc.address")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--grpc-web.address")))),(0,r.kt)("h2",{id:"re-using-consensus-key"},"Re-using consensus key"),(0,r.kt)("p",null,"To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the ",(0,r.kt)("inlineCode",{parentName:"p"},"priv_validator_key.json")," into the home directory of your consumer chain (",(0,r.kt)("inlineCode",{parentName:"p"},"<consumer_home>/config/priv_validator_key.json"),")."),(0,r.kt)("p",null,"When you start the chain, the consensus key will be the same on the provider and the consumer chain."),(0,r.kt)("h2",{id:"assigning-consensus-keys"},"Assigning consensus keys"),(0,r.kt)("p",null,"Whenever you initialize a new node, it will be configured with a consensus key you can use."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'# machine running consumer chain\nconsumerd init <node_moniker> --home <home_path> --chain-id consumer-1\n\n# use the output of this command to get the consumer chain consensus key\nconsumerd tendermint show-validator\n# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}\n')),(0,r.kt)("p",null,"Then, let the provider know which key you will be using for the consumer chain:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"# machine running the provider chain\ngaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b sync -y -o json\n")),(0,r.kt)("p",null,"After this step, you are ready to copy the consumer genesis into your nodes's ",(0,r.kt)("inlineCode",{parentName:"p"},"/config")," folder, start your consumer chain node and catch up to the network."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/50036eb1.2765b1a3.js b/legacy/assets/js/50036eb1.2765b1a3.js new file mode 100644 index 0000000000..2138a76876 --- /dev/null +++ b/legacy/assets/js/50036eb1.2765b1a3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7249],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>m});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),d=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},h="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),h=d(n),u=i,m=h["".concat(s,".").concat(u)]||h[u]||p[u]||r;return n?a.createElement(m,o(o({ref:t},c),{},{components:n})):a.createElement(m,o({ref:t},c))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[h]="string"==typeof e?e:i,o[1]=l;for(var d=2;d<r;d++)o[d]=n[d];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}u.displayName="MDXCreateElement"},2003:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>p,frontMatter:()=>r,metadata:()=>l,toc:()=>d});var a=n(7462),i=(n(7294),n(3905));const r={sidebar_position:7,title:"Throttle with retries"},o=void 0,l={unversionedId:"adrs/adr-008-throttle-retries",id:"version-v3.3.1-lsm/adrs/adr-008-throttle-retries",title:"Throttle with retries",description:"ADR 008: Throttle with retries",source:"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-008-throttle-retries.md",sourceDirName:"adrs",slug:"/adrs/adr-008-throttle-retries",permalink:"/interchain-security/legacy/adrs/adr-008-throttle-retries",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:7,frontMatter:{sidebar_position:7,title:"Throttle with retries"},sidebar:"tutorialSidebar",previous:{title:"Cryptographic verification of equivocation evidence",permalink:"/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification"},next:{title:"Soft Opt-Out",permalink:"/interchain-security/legacy/adrs/adr-009-soft-opt-out"}},s={},d=[{value:"ADR 008: Throttle with retries",id:"adr-008-throttle-with-retries",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consumer changes",id:"consumer-changes",level:3},{value:"Consumer pending packets storage optimization",id:"consumer-pending-packets-storage-optimization",level:4},{value:"Provider changes",id:"provider-changes",level:3},{value:"Handling <code>VSCMaturedPackets</code> immediately",id:"handling-vscmaturedpackets-immediately",level:4},{value:"Why the provider can handle VSCMatured packets immediately",id:"why-the-provider-can-handle-vscmatured-packets-immediately",level:4},{value:"Splitting of PRs and Upgrade Order",id:"splitting-of-prs-and-upgrade-order",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],c={toc:d},h="wrapper";function p(e){let{components:t,...n}=e;return(0,i.kt)(h,(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h2",{id:"adr-008-throttle-with-retries"},"ADR 008: Throttle with retries"),(0,i.kt)("h2",{id:"changelog"},"Changelog"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"6/9/23: Initial draft"),(0,i.kt)("li",{parentName:"ul"},"6/22/23: added note on consumer pending packets storage optimization"),(0,i.kt)("li",{parentName:"ul"},"7/14/23: Added note on upgrade order")),(0,i.kt)("h2",{id:"status"},"Status"),(0,i.kt)("p",null,"Accepted"),(0,i.kt)("h2",{id:"context"},"Context"),(0,i.kt)("p",null,"For context on why the throttling mechanism exists, see ",(0,i.kt)("a",{parentName:"p",href:"/interchain-security/legacy/adrs/adr-002-throttle"},"ADR 002"),"."),(0,i.kt)("p",null,"Note the terms slash throttling and jail throttling are synonymous, since in replicated security a ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPacket")," simply jails a validator for downtime infractions. "),(0,i.kt)("p",null,"Currently the throttling mechanism is designed so that provider logic (slash meter, etc.) dictates how many ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," can be handled over time.\nThrottled ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," are persisted on the provider, leading to multiple possible issues. Namely:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"If ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashPackets")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"VSCMaturedPackets")," are actually throttled/queued on the provider, state can grow and potentially lead to a DoS attack.\nWe have short term solutions around this, but overall they come with their own weaknesses.\nSee ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/594"},"#594"),"."),(0,i.kt)("li",{parentName:"ul"},"If a jailing attack described in ",(0,i.kt)("a",{parentName:"li",href:"/interchain-security/legacy/adrs/adr-002-throttle"},"ADR 002")," were actually to be carried out with the current throttling design, we'd likely have to halt the provider, and perform an emergency upgrade and/or migration to clear the queues of ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashPackets")," that were deemed to be malicious.\nAlternatively, validators would just have to ",(0,i.kt)("em",{parentName:"li"},"tough it out")," and wait for the queues to clear, during which all/most validators would be jailed.\nRight after being jailed, validators would have to unjail themselves promptly to ensure safety.\nThe coordination required to maintain safety in such a scenario is not ideal.")),(0,i.kt)("p",null,"As as solution, we can improve the throttling mechanism to instead queue/persist relevant data on each consumer, and have consumers retry slash requests as needed."),(0,i.kt)("h2",{id:"decision"},"Decision"),(0,i.kt)("h3",{id:"consumer-changes"},"Consumer changes"),(0,i.kt)("p",null,"Note the consumer already queues up both ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets")," via ",(0,i.kt)("inlineCode",{parentName:"p"},"AppendPendingPacket"),".\nThose packets are dequeued in every ",(0,i.kt)("inlineCode",{parentName:"p"},"EndBlock")," in ",(0,i.kt)("inlineCode",{parentName:"p"},"SendPackets")," and sent to the provider."),(0,i.kt)("p",null,"Instead, we will now introduce the following logic on ",(0,i.kt)("inlineCode",{parentName:"p"},"EndBlock"),":"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Slash packets will always be sent to the provider once they're at the head of the queue.\nHowever, once sent, the consumer will not send any subsequent ",(0,i.kt)("inlineCode",{parentName:"li"},"VSCMaturedPackets")," from the queue until the provider responds with an acknowledgement that the sent ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashPacket")," has been handled, i.e., validator was jailed.\nThat is, ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashPackets")," block the sending of subsequent ",(0,i.kt)("inlineCode",{parentName:"li"},"VSCMaturedPackets")," in the consumer queue."),(0,i.kt)("li",{parentName:"ul"},"If two ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashPackets")," are at the head of the queue, the consumer will send the first ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashPacket"),", and then wait for a success acknowledgement from the provider before sending the second ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashPacket"),".\nThis seems like it'd simplify implementation."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"VSCMaturedPackets")," at the head of the queue (i.e., NOT following a ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashPacket"),") can be sent immediately, and do not block any other packets in the queue, since the provider always handles them immediately.")),(0,i.kt)("p",null,"To prevent the provider from having to keep track of what ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," have been rejected, the consumer will have to retry the sending of ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," over some period of time.\nThis can be achieved with an on-chain consumer param, i.e., ",(0,i.kt)("inlineCode",{parentName:"p"},"RetryDelayPeriod"),".\nTo reduce the amount of redundant re-sends, we recommend setting ",(0,i.kt)("inlineCode",{parentName:"p"},"RetryDelayPeriod ~ SlashMeterReplenishmentPeriod"),", i.e., waiting for the provider slash meter to be replenished before resending the rejected ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPacket"),"."),(0,i.kt)("p",null,"Note to prevent weird edge case behavior, a retry would not be attempted until either a success or failure acknowledgement has been received from the provider."),(0,i.kt)("p",null,"With the behavior described, we maintain very similar behavior to the previous throttling mechanism regarding the timing that ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets")," are handled on the provider.\nObviously the queueing and blocking logic is moved, and the two chains would have to send more messages between one another (only in the case the throttling mechanism is triggered)."),(0,i.kt)("p",null,"In the normal case, when no or a few ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," are being sent, the ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets")," will not be delayed, and hence unbonding will not be delayed."),(0,i.kt)("p",null,"For the implementation of this design, see ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/fec3eccad59416cbdb6844e279f59e3f81242888/x/ccv/consumer/keeper/throttle_retry.go"},"throttle_retry.go"),"."),(0,i.kt)("h4",{id:"consumer-pending-packets-storage-optimization"},"Consumer pending packets storage optimization"),(0,i.kt)("p",null,"In addition to the mentioned consumer changes, an optimization will need to be made to the consumer's pending packets storage to properly implement the feature from this ADR."),(0,i.kt)("p",null,'The consumer ccv module previously queued "pending packets" to be sent in each ',(0,i.kt)("inlineCode",{parentName:"p"},"EndBlock")," in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/3bc4e7135066d848aac60b0787364c07157fd36d/x/ccv/consumer/keeper/relay.go#L178"},"SendPackets"),".\nThese packets are queued in state with a protobuf list of ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerPacketData"),".\nFor a single append operation, the entire list is deserialized, then a packet is appended to that list, and the list is serialized again.\nSee older version of ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/05c2dae7c6372b1252b9e97215d07c6aa7618f33/x/ccv/consumer/keeper/keeper.go#L606"},"AppendPendingPacket"),".\nThat is, a single append operation has O(N) complexity, where N is the size of the list."),(0,i.kt)("p",null,"This poor append performance isn't a problem when the pending packets list is small.\nBut with this ADR being implemented, the pending packets list could potentially grow to the order of thousands of entries when ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," need to be resent."),(0,i.kt)("p",null,"We can improve the append time for this queue by converting it from a protobuf-esq list, to a queue implemented with sdk-esq code.\nThe idea is to persist an uint64 index that will be incremented each time you queue up a packet.\nYou can think of this as storing the tail of the queue.\nThen, packet data will be keyed by that index, making the data naturally ordered byte-wise for sdk's iterator.\nThe index will also be stored in the packet data value bytes, so that the index can later be used to delete certain packets from the queue."),(0,i.kt)("p",null,"Two things are achieved with this approach:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"More efficient packet append/enqueue times"),(0,i.kt)("li",{parentName:"ul"},"The ability to delete select packets from the queue (previously all packets were deleted at once)")),(0,i.kt)("h3",{id:"provider-changes"},"Provider changes"),(0,i.kt)("p",null,"The main change needed for the provider is the removal of queuing logic for ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets")," upon being received."),(0,i.kt)("p",null,"Instead, the provider will consult the slash meter to determine if a ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPacket")," can be handled immediately.\nIf not, the provider will return an acknowledgement message to the consumer communicating that the ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPacket")," could not be handled, and needs to be sent again in the future (retried)."),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets")," will always be handled immediately upon being received by the provider."),(0,i.kt)("p",null,"Note ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"spec"),". Specifically the section on ",(0,i.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order"),". Previously the onus was on the provider to maintain this property via queuing packets and handling them FIFO."),(0,i.kt)("p",null,"Now this property will be maintained by the consumer sending packets in the correct order, and blocking the sending of ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets")," as needed. Then, the ordered IBC channel will ensure that ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets")," are received in the correct order on the provider."),(0,i.kt)("p",null,"The provider's main responsibility regarding throttling will now be to determine if a received ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPacket")," can be handled via slash meter etc., and appropriately acknowledge to the sending consumer."),(0,i.kt)("h4",{id:"handling-vscmaturedpackets-immediately"},"Handling ",(0,i.kt)("inlineCode",{parentName:"h4"},"VSCMaturedPackets")," immediately"),(0,i.kt)("h4",{id:"why-the-provider-can-handle-vscmatured-packets-immediately"},"Why the provider can handle VSCMatured packets immediately"),(0,i.kt)("p",null,"A ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPacket")," communicates to the provider that sufficient time passed on the consumer since the corresponding ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCPacket")," has been applied (on the consumer) such that infractions committed on the consumer could have been submitted."),(0,i.kt)("p",null,"If the consumer is following the queuing/blocking protocol described, then no bad behavior occurs and the ",(0,i.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order")," property is maintained."),(0,i.kt)("p",null,"If a consumer sends ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets")," too leniently -- the consumer is malicious and sends duplicate ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets"),", or sends the packets sooner than the CCV protocol specifies -- then the provider needs to handle ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets")," immediately to prevent DOS, state bloat, or other issues.\nThe only possible negative outcome is that the malicious consumer may not be able to jail a validator who should have been jailed.\nThe malicious behavior only creates a negative outcome for the consumer chain that is being malicious."),(0,i.kt)("p",null,"If a consumer blocks the sending of ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets"),", then unbonding operations on the provider will be delayed, but only until the VSC timeout period has elapsed.\nAt that time, the consumer is removed.\nAgain the malicious behavior only creates a negative outcome for the consumer chain that is being malicious."),(0,i.kt)("h3",{id:"splitting-of-prs-and-upgrade-order"},"Splitting of PRs and Upgrade Order"),(0,i.kt)("p",null,"This feature will implement consumer changes in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1024"},"#1024"),". "),(0,i.kt)("p",null,"\u2757",(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("em",{parentName:"strong"},"These changes should be deployed to production for all consumers before the provider changes are deployed to production."))," "),(0,i.kt)("p",null,"In other words, the consumer changes in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1024"},"#1024"),' are compatible with the current ("v1") provider implementation of throttling that\'s running on the Cosmos Hub as of July 2023.'),(0,i.kt)("p",null,"Once all consumers have deployed the changes in #1024, the provider changes from ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1321"},"#1321")," can be deployed to production, fully enabling v2 throttling."),(0,i.kt)("h2",{id:"consequences"},"Consequences"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Consumers will now have to manage their own queues, and retry logic."),(0,i.kt)("li",{parentName:"ul"},"Consumers still aren't trustless, but the provider is now less susceptible to mismanaged or malicious consumers."),(0,i.kt)("li",{parentName:"ul"},'Recovering from the "jailing attack" is more elegant.'),(0,i.kt)("li",{parentName:"ul"},"Some issues like ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/1001"},"#1001")," will now be handled implicitly by the improved throttling mechanism."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"SlashPackets")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"VSCMaturedPackets")," can be handled immediately once received by the provider if the slash meter allows."),(0,i.kt)("li",{parentName:"ul"},"In general, we reduce the amount of computation that happens in the provider ",(0,i.kt)("inlineCode",{parentName:"li"},"EndBlock"),".")),(0,i.kt)("h3",{id:"positive"},"Positive"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},'We no longer have to reason about a "global queue" and a "chain specific queue", and keeping those all in-sync.\nNow ',(0,i.kt)("inlineCode",{parentName:"li"},"SlashPackets")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"VSCMaturedPackets")," queuing is handled on each consumer individually."),(0,i.kt)("li",{parentName:"ul"},"Due to the above, the throttling protocol becomes less complex overall."),(0,i.kt)("li",{parentName:"ul"},"We no longer have to worry about throttle related DoS attack on the provider, since no queuing exists on the provider.")),(0,i.kt)("h3",{id:"negative"},"Negative"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Increased number of IBC packets being relayed anytime throttling logic is triggered."),(0,i.kt)("li",{parentName:"ul"},"Consumer complexity increases, since consumers now have manage queuing themselves, and implement packet retry logic.")),(0,i.kt)("h3",{id:"neutral"},"Neutral"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Core throttling logic on the provider remains unchanged, i.e., slash meter, replenishment cycles, etc.")),(0,i.kt)("h2",{id:"references"},"References"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/713"},"EPIC")," tracking the changes proposed by this ADR"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/interchain-security/legacy/adrs/adr-002-throttle"},"ADR 002: Jail Throttling")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/594"},"#594"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/545e4084.ea4e8960.js b/legacy/assets/js/545e4084.ea4e8960.js new file mode 100644 index 0000000000..026bc1cd08 --- /dev/null +++ b/legacy/assets/js/545e4084.ea4e8960.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4457],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),h=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=h(e.components);return o.createElement(l.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),c=h(n),u=a,m=c["".concat(l,".").concat(u)]||c[u]||p[u]||i;return n?o.createElement(m,r(r({ref:t},d),{},{components:n})):o.createElement(m,r({ref:t},d))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,r=new Array(i);r[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:a,r[1]=s;for(var h=2;h<i;h++)r[h]=n[h];return o.createElement.apply(null,r)}return o.createElement.apply(null,n)}u.displayName="MDXCreateElement"},5993:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>h});var o=n(7462),a=(n(7294),n(3905));const i={sidebar_position:14,title:"Slashing on the provider for consumer equivocation"},r="ADR 013: Slashing on the provider for consumer equivocation",s={unversionedId:"adrs/adr-013-equivocation-slashing",id:"version-v3.3.1-lsm/adrs/adr-013-equivocation-slashing",title:"Slashing on the provider for consumer equivocation",description:"Changelog",source:"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-013-equivocation-slashing.md",sourceDirName:"adrs",slug:"/adrs/adr-013-equivocation-slashing",permalink:"/interchain-security/legacy/adrs/adr-013-equivocation-slashing",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:14,frontMatter:{sidebar_position:14,title:"Slashing on the provider for consumer equivocation"},sidebar:"tutorialSidebar",previous:{title:"Separate Releasing",permalink:"/interchain-security/legacy/adrs/adr-012-separate-releasing"}},l={},h=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Single-chain slashing",id:"single-chain-slashing",level:3},{value:"Slashing undelegations and redelegations",id:"slashing-undelegations-and-redelegations",level:4},{value:"Slashing delegations",id:"slashing-delegations",level:4},{value:"Old evidence",id:"old-evidence",level:4},{value:"Slashing for equivocation on the consumer",id:"slashing-for-equivocation-on-the-consumer",level:3},{value:"Proposed solution",id:"proposed-solution",level:2},{value:"Implementation",id:"implementation",level:3},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}],d={toc:h},c="wrapper";function p(e){let{components:t,...n}=e;return(0,a.kt)(c,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-013-slashing-on-the-provider-for-consumer-equivocation"},"ADR 013: Slashing on the provider for consumer equivocation"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"1st Sept. 2023: Initial draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Proposed"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"This ADR presents some approaches on how to slash on the provider chain validators that performed equivocations on consumer chains.\nCurrently, the provider chain can ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232"},"receive and verify evidence of equivocation"),", but it cannot slash the misbehaving validator."),(0,a.kt)("p",null,"In the remainder of this section, we explain how slashing is performed on a single chain and show why slashing on the provider for equivocation on the consumer is challenging."),(0,a.kt)("p",null,"Note that future versions of the Cosmos SDK, CometBFT, and ibc-go could modify the way we slash, etc. Therefore, a future reader of this ADR, should note that when we refer to Cosmos SDK, CometBFT, and ibc-go we specifically refer to their ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/intro/overview"},"v0.47"),", ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cometbft.com/v0.37/"},"v0.37")," and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/v7.3.0"},"v7.3.0")," versions respectively."),(0,a.kt)("h3",{id:"single-chain-slashing"},"Single-chain slashing"),(0,a.kt)("p",null,"Slashing is implemented across the ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/slashing"},"slashing"),"\nand ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/staking"},"staking")," modules.\nThe slashing module's keeper calls the staking module's ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash()")," method, passing among others, the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," (i.e., the height when the equivocation occurred), the validator's ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," at the infraction height, and the ",(0,a.kt)("inlineCode",{parentName:"p"},"slashFactor")," (currently set to ",(0,a.kt)("inlineCode",{parentName:"p"},"5%")," in case of equivocation on the Cosmos Hub)."),(0,a.kt)("h4",{id:"slashing-undelegations-and-redelegations"},"Slashing undelegations and redelegations"),(0,a.kt)("p",null,"To slash undelegations, ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash")," goes through all undelegations and checks whether they started before or after the infraction occurred. If an undelegation started before the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight"),", then it is ",(0,a.kt)("strong",{parentName:"p"},"not")," slashed, otherwise it is slashed by ",(0,a.kt)("inlineCode",{parentName:"p"},"slashFactor"),"."),(0,a.kt)("p",null,"The slashing of redelegations happens in a similar way, meaning that ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash")," goes through all redelegations and checks whether the redelegations started before or after the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight"),"."),(0,a.kt)("h4",{id:"slashing-delegations"},"Slashing delegations"),(0,a.kt)("p",null,"Besides undelegations and redelegations, the validator's delegations need to also be slashed.\nThis is performed by deducting the appropriate amount of tokens from the validator. Note that this deduction is computed based on the voting ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," the misbehaving validator had at the height of the equivocation. As a result of the tokens deduction,\nthe ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/staking#delegator-shares"},"tokens per share"),"\nreduce and hence later on, when delegators undelegate or redelegate, the delegators retrieve back less\ntokens, effectively having their tokens slashed. The rationale behind this slashing mechanism, as mentioned in the ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/staking#delegator-shares"},"Cosmos SDK documentation")," "),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"[...]"," is to simplify the accounting around slashing. Rather than iteratively slashing the tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, effectively reducing the value of each issued delegator share.")),(0,a.kt)("p",null,"This approach of slashing delegations does not utilize the\n",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," in any way and hence the following scenario could occur:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"a validator ",(0,a.kt)("inlineCode",{parentName:"li"},"V")," performs an equivocation at a height ",(0,a.kt)("inlineCode",{parentName:"li"},"Hi")),(0,a.kt)("li",{parentName:"ol"},"a new delegator ",(0,a.kt)("inlineCode",{parentName:"li"},"D")," delegates to ",(0,a.kt)("inlineCode",{parentName:"li"},"V")," after height ",(0,a.kt)("inlineCode",{parentName:"li"},"Hi")),(0,a.kt)("li",{parentName:"ol"},"evidence of the equivocation by validator ",(0,a.kt)("inlineCode",{parentName:"li"},"V")," is received"),(0,a.kt)("li",{parentName:"ol"},"the tokens of delegator ",(0,a.kt)("inlineCode",{parentName:"li"},"D")," are slashed")),(0,a.kt)("p",null,"In the above scenario, delegator ",(0,a.kt)("inlineCode",{parentName:"p"},"D")," is slashed, even though ",(0,a.kt)("inlineCode",{parentName:"p"},"D"),"'s voting power did not contribute to the infraction. "),(0,a.kt)("h4",{id:"old-evidence"},"Old evidence"),(0,a.kt)("p",null,"In the single-chain case, old evidence (e.g., from 3 years ago) is ignored. This is achieved through\n",(0,a.kt)("a",{parentName:"p",href:"https://docs.cometbft.com/v0.37/spec/consensus/evidence"},"CometBFT")," that ignores old evidence based on the parameters ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeNumBlocks")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeDuration")," (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.37.0/evidence/pool.go#271"},"here"),").\nAdditionally, note that when the evidence is sent by CometBFT to the application, the evidence is rechecked in the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L54"},"evidence module")," of Cosmos SDK and if it is old, the evidence is ignored.\nIn Cosmos Hub, the ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeNumBlocks")," is set to 1000000 (i.e., ~70 days if we assume we need ~6 sec per block) and ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeDuration")," is set to 172800000000000 ns (i.e., 2 days). Because of this check, we can easily exclude old evidence."),(0,a.kt)("h3",{id:"slashing-for-equivocation-on-the-consumer"},"Slashing for equivocation on the consumer"),(0,a.kt)("p",null,"In the single-chain case, slashing requires both the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and the voting ",(0,a.kt)("inlineCode",{parentName:"p"},"power"),".\nIn order to slash on the provider for an equivocation on a consumer, we need to have both the provider's ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and voting ",(0,a.kt)("inlineCode",{parentName:"p"},"power"),".\nNote that the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," on the consumer chain must be mapped to a height on the provider chain.\nUnless we have a way to find the corresponding ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," on the provider chain, we cannot slash for equivocation on the consumer in the same way as we would slash in the single-chain case."),(0,a.kt)("p",null,"The challenge of figuring out the corresponding ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," values on the provider chain is due to the following trust assumption:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"We trust the consensus layer and validator set of the consumer chains, ",(0,a.kt)("em",{parentName:"li"},"but we do not trust the application layer"),".")),(0,a.kt)("p",null,"As a result, we cannot trust anything that stems from the ",(0,a.kt)("em",{parentName:"p"},"application state")," of a consumer chain."),(0,a.kt)("p",null,"Note that when a relayer or a user sends evidence through a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232"},"MsgSubmitConsumerDoubleVoting")," message, the provider gets access to ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.37.0/types/evidence.go#L35"},"DuplicateVoteEvidence"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-protobuf"},'type DuplicateVoteEvidence struct {\n VoteA *Vote `json:"vote_a"`\n VoteB *Vote `json:"vote_b"`\n\n // abci specific information\n TotalVotingPower int64\n ValidatorPower int64\n Timestamp time.Time\n}\n')),(0,a.kt)("p",null,'The "abci specific information" fields cannot be trusted because they are not signed. Therefore,\nwe can use neither ',(0,a.kt)("inlineCode",{parentName:"p"},"ValidatorPower")," for slashing on the provider chain, nor the ",(0,a.kt)("inlineCode",{parentName:"p"},"Timestamp")," to check the evidence age. We can get the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," from the votes, but this ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," corresponds to the infraction height on the consumer and ",(0,a.kt)("strong",{parentName:"p"},"not")," on the provider chain.\nSimilarly, when a relayer or a user sends evidence through a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/826"},"MsgSubmitConsumerMisbehaviour")," message, the provider gets access to ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/v7.3.0/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79"},"Misbehaviour")," that we cannot use to extract the infraction height, power, or the time on the provider chain."),(0,a.kt)("h2",{id:"proposed-solution"},"Proposed solution"),(0,a.kt)("p",null,"As a first iteration, we propose the following approach. At the moment the provider receives evidence of equivocation on a consumer:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"slash all the undelegations and redelegations using ",(0,a.kt)("inlineCode",{parentName:"li"},"slashFactor"),";"),(0,a.kt)("li",{parentName:"ol"},"slash all delegations using as voting ",(0,a.kt)("inlineCode",{parentName:"li"},"power")," the sum of the voting power of the misbehaving validator and the power of all the ongoing undelegations and redelegations.")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Evidence expiration:")," Additionally, because we cannot infer the actual time of the evidence (i.e., the timestamp of the evidence cannot be trusted), we do not consider ",(0,a.kt)("em",{parentName:"p"},"evidence expiration")," and hence old evidence is never ignored (e.g., the provider would act on 3 year-old evidence of equivocation on a consumer).\nAdditionally, we do not need to store equivocation evidence to avoid slashing a validator more than once, because we ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L94"},"do not slash")," tombstoned validators and we ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L138"},"tombstone")," a validator when slashed."),(0,a.kt)("p",null,"We do not act on evidence that was signed by a validator ",(0,a.kt)("a",{parentName:"p",href:"https://tutorials.cosmos.network/tutorials/9-path-to-prod/3-keys.html#what-validator-keys"},"consensus key")," that is ",(0,a.kt)("em",{parentName:"p"},"pruned")," when we receive the evidence. We prune a validator's consensus key if the validator has assigned a new consumer key (using ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey"),") and an unbonding period on the consumer chain has elapsed (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-001-key-assignment.md"},"key assignment ADR"),"). Note that the provider chain is informed that the unbonding period has elapsed on the consumer when the provider receives a ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCMaturedPacket")," and because of this, if the consumer delays the sending of a ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCMaturedPacket"),", we would delay the pruning of the key as well."),(0,a.kt)("h3",{id:"implementation"},"Implementation"),(0,a.kt)("p",null,"The following logic needs to be added to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232"},"HandleConsumerDoubleVoting")," and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/826"},"HandleConsumerMisbehaviour")," methods:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-go"},"undelegationsInTokens := sdk.NewInt(0)\nfor _, v := range k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validatorAddress) {\n for _, entry := range v.Entries {\n if entry.IsMature(now) && !entry.OnHold() {\n // undelegation no longer eligible for slashing, skip it\n continue\n }\n undelegationsInTokens = undelegationsInTokens.Add(entry.InitialBalance)\n }\n}\n\nredelegationsInTokens := sdk.NewInt(0)\nfor _, v := range k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validatorAddress) {\n for _, entry := range v.Entries {\n if entry.IsMature(now) && !entry.OnHold() {\n // redelegation no longer eligible for slashing, skip it\n continue\n }\n redelegationsInTokens = redelegationsInTokens.Add(entry.InitialBalance)\n }\n}\n\ninfractionHeight := 0\nundelegationsAndRedelegationsInPower = sdk.TokensToConsensusPower(undelegationsInTokens.Add(redelegationsInTokens))\ntotalPower := validator's voting power + undelegationsAndRedelegationsInPower\nslashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)\n\nk.stakingKeeper.Slash(ctx, validatorConsAddress, infractionHeight, totalPower, slashFraction, DoubleSign)\n")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Infraction height:")," We provide a zero ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L33"},"Slash")," method in order to slash all ongoing undelegations and redelegations (see checks in ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L92"},"Slash"),", ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L195"},"SlashUnbondingDelegation"),", and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L249"},"SlashRedelegation"),")."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Power:")," We pass the sum of the voting power of the misbehaving validator when the evidence was received (i.e., at evidence height) and the power of all the ongoing undelegations and redelegations.\nIf we assume that the ",(0,a.kt)("inlineCode",{parentName:"p"},"slashFactor")," is ",(0,a.kt)("inlineCode",{parentName:"p"},"5%"),", then the voting power we pass is ",(0,a.kt)("inlineCode",{parentName:"p"},"power + totalPower(undelegations) + totalPower(redelegations)"),".\nHence, when the ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash")," method slashes all the undelegations and redelegations it would end up with ",(0,a.kt)("inlineCode",{parentName:"p"},"0.05 * power + 0.05 * totalPower(undelegations) + 0.05 * totalPower(redelegations) - 0.05 * totalPower(undelegations) - 0.05 * totalPower(redelegations) = 0.05 * power")," and hence it would slash ",(0,a.kt)("inlineCode",{parentName:"p"},"5%")," of the validator's power when the evidence is received."),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("p",null,"With the proposed approach we can quickly implement slashing functionality on the provider chain for consumer chain equivocations.\nThis approach does not need to change the staking module and therefore does not change in any way how slashing is performed today for a single chain."),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"We ",(0,a.kt)("em",{parentName:"li"},"definitely")," slash more when it comes to undelegations and redelegations because we slash for all of them without considering an ",(0,a.kt)("inlineCode",{parentName:"li"},"infractionHeight"),"."),(0,a.kt)("li",{parentName:"ul"},"We ",(0,a.kt)("em",{parentName:"li"},"potentially")," slash more than what we would have slashed if we knew the voting ",(0,a.kt)("inlineCode",{parentName:"li"},"power")," at the corresponding ",(0,a.kt)("inlineCode",{parentName:"li"},"infractionHeight")," in the provider chain."),(0,a.kt)("li",{parentName:"ul"},"We slash on old evidence of equivocation on a consumer.")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md"},"ADR 005: Cryptographic verification of equivocation evidence")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/732"},"EPIC tracking cryptographic equivocation feature")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://forum.cosmos.network/t/cryptographic-equivocation-slashing-design/11400"},"Cosmos Hub Forum discussion on cryptographic equivocation slashing"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/54e4400b.a869b7ad.js b/legacy/assets/js/54e4400b.a869b7ad.js new file mode 100644 index 0000000000..9f6006ad6f --- /dev/null +++ b/legacy/assets/js/54e4400b.a869b7ad.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2344],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>h});var r=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function s(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?s(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):s(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function i(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},s=Object.keys(e);for(r=0;r<s.length;r++)t=s[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r<s.length;r++)t=s[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var d=r.createContext({}),l=function(e){var n=r.useContext(d),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=l(e.components);return r.createElement(d.Provider,{value:n},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,s=e.originalType,d=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),c=l(t),m=a,h=c["".concat(d,".").concat(m)]||c[m]||p[m]||s;return t?r.createElement(h,o(o({ref:n},u),{},{components:t})):r.createElement(h,o({ref:n},u))}));function h(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var s=t.length,o=new Array(s);o[0]=m;var i={};for(var d in n)hasOwnProperty.call(n,d)&&(i[d]=n[d]);i.originalType=e,i[c]="string"==typeof e?e:a,o[1]=i;for(var l=2;l<s;l++)o[l]=t[l];return r.createElement.apply(null,o)}return r.createElement.apply(null,t)}m.displayName="MDXCreateElement"},6713:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>p,frontMatter:()=>s,metadata:()=>i,toc:()=>l});var r=t(7462),a=(t(7294),t(3905));const s={sidebar_position:3,title:"Key Assignment"},o="ADR 001: Key Assignment",i={unversionedId:"adrs/adr-001-key-assignment",id:"adrs/adr-001-key-assignment",title:"Key Assignment",description:"Changelog",source:"@site/docs/adrs/adr-001-key-assignment.md",sourceDirName:"adrs",slug:"/adrs/adr-001-key-assignment",permalink:"/interchain-security/legacy/adrs/adr-001-key-assignment",draft:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Key Assignment"},sidebar:"tutorialSidebar",previous:{title:"ADR Template",permalink:"/interchain-security/legacy/adrs/adr-template"},next:{title:"Jail Throttling",permalink:"/interchain-security/legacy/adrs/adr-002-throttle"}},d={},l=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"State required",id:"state-required",level:3},{value:"Protocol overview",id:"protocol-overview",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],u={toc:l},c="wrapper";function p(e){let{components:n,...t}=e;return(0,a.kt)(c,(0,r.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-001-key-assignment"},"ADR 001: Key Assignment"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"2022-12-01: Initial Draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"It is possible to change the keys at any time by submitting a transaction (i.e., ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey"),")."),(0,a.kt)("h3",{id:"state-required"},"State required"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorConsumerPubKey")," - Stores the validator assigned keys for every consumer chain.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorByConsumerAddr")," - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"KeyAssignmentReplacements")," - Stores the key assignments that need to be replaced in the current block. Needed to apply the key assignments received in a block to the validator updates sent to the consumer chains.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"KeyAssignmentReplacementsBytePrefix | len(chainID) | chainID | providerConsAddress -> abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower},\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ConsumerAddrsToPrune")," - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ",(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorByConsumerAddr"),". ")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses\n")),(0,a.kt)("h3",{id:"protocol-overview"},"Protocol overview"),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey(chainID, providerAddr, consumerKey)")," message:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"// get validator from staking module \nvalidator, found := stakingKeeper.GetValidator(providerAddr)\nif !found {\n return ErrNoValidatorFound\n}\nproviderConsAddr := validator.GetConsAddr()\n\n// make sure consumer key is not in use\nconsumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)\nif _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {\n return ErrInvalidConsumerConsensusPubKey\n}\n\n// check whether the consumer chain is already registered\n// i.e., a client to the consumer was already created\nif _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {\n // get the previous key assigned for this validator on this consumer chain\n oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)\n if found {\n // mark this old consumer key as prunable once the VSCMaturedPacket\n // for the current VSC ID is received\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n vscID := GetValidatorSetUpdateId()\n AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)\n } else {\n // the validator had no key assigned on this consumer chain\n oldConsumerKey := validator.TmConsPublicKey()\n }\n\n // check whether the validator is valid, i.e., its power is positive\n if currentPower := stakingKeeper.GetLastValidatorPower(providerAddr); currentPower > 0 {\n // to enable multiple calls of AssignConsumerKey in the same block by the same validator\n // the key assignment replacement should not be overwritten\n if _, found := GetKeyAssignmentReplacement(chainID, providerConsAddr); !found {\n // store old key and power for modifying the valset update in EndBlock\n oldKeyAssignment := abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower}\n SetKeyAssignmentReplacement(chainID, providerConsAddr, oldKeyAssignment)\n }\n }\n} else {\n // if the consumer chain is not registered, then remove the previous reverse mapping\n if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)\n }\n}\n\n\n// set the mapping from this validator's provider address to the new consumer key\nSetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)\n\n// set the reverse mapping: from this validator's new consensus address \n// on the consumer to its consensus address on the provider\nSetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)\n")),(0,a.kt)("p",null,"When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see ",(0,a.kt)("inlineCode",{parentName:"p"},"MakeConsumerGenesis"),"). "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {\n // ...\n // get initial valset from the staking module\n var updates []abci.ValidatorUpdate{}\n stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {\n validator := stakingKeeper.GetValidator(providerAddr)\n providerKey := validator.TmConsPublicKey()\n updates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})\n return false\n })\n\n // applies the key assignment to the initial validator\n for i, update := range updates {\n providerAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)\n if consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {\n updates[i].PubKey = consumerKey\n }\n }\n gen.InitialValSet = updates\n\n // get a hash of the consumer validator set from the update\n updatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)\n hash := tendermint.NewValidatorSet(updatesAsValSet).Hash()\n\n return gen, hash, nil\n}\n")),(0,a.kt)("p",null,"On ",(0,a.kt)("inlineCode",{parentName:"p"},"EndBlock")," while queueing ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCPacket"),"s to send to registered consumer chains:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func QueueVSCPackets() {\n valUpdateID := GetValidatorSetUpdateId()\n // get the validator updates from the staking module\n valUpdates := stakingKeeper.GetValidatorUpdates()\n\n IterateConsumerChains(func(chainID, clientID string) (stop bool) {\n // apply the key assignment to the validator updates\n valUpdates := ApplyKeyAssignmentToValUpdates(chainID, valUpdates)\n // ..\n })\n // ...\n}\n\nfunc ApplyKeyAssignmentToValUpdates(\n chainID string, \n valUpdates []abci.ValidatorUpdate,\n) (newUpdates []abci.ValidatorUpdate) {\n for _, valUpdate := range valUpdates {\n providerAddr := utils.TMCryptoPublicKeyToConsAddr(valUpdate.PubKey)\n\n // if a key assignment replacement is found, then\n // remove the valupdate with the old consumer key\n // and create two new valupdates\n prevConsumerKey, _, found := GetKeyAssignmentReplacement(chainID, providerAddr)\n if found {\n // set the old consumer key's power to 0\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: prevConsumerKey,\n Power: 0,\n })\n // set the new consumer key's power to the power in the update\n newConsumerKey := GetValidatorConsumerPubKey(chainID, providerAddr)\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: newConsumerKey,\n Power: valUpdate.Power,\n })\n // delete key assignment replacement\n DeleteKeyAssignmentReplacement(chainID, providerAddr)\n } else {\n // there is no key assignment replacement;\n // check if the validator's key is assigned\n consumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr)\n if found {\n // replace the update containing the provider key \n // with an update containing the consumer key\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: consumerKey,\n Power: valUpdate.Power,\n })\n } else {\n // keep the same update\n newUpdates = append(newUpdates, valUpdate)\n }\n }\n }\n\n // iterate over the remaining key assignment replacements\n IterateKeyAssignmentReplacements(chainID, func(\n pAddr sdk.ConsAddress,\n prevCKey tmprotocrypto.PublicKey,\n power int64,\n ) (stop bool) {\n // set the old consumer key's power to 0\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: prevCKey,\n Power: 0,\n })\n // set the new consumer key's power to the power in key assignment replacement\n newConsumerKey := GetValidatorConsumerPubKey(chainID, pAddr)\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: newConsumerKey,\n Power: power,\n })\n return false\n })\n\n // remove all the key assignment replacements\n \n return newUpdates\n}\n")),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"SlashPacket")," from a consumer chain with id ",(0,a.kt)("inlineCode",{parentName:"p"},"chainID")," for a infraction of a validator ",(0,a.kt)("inlineCode",{parentName:"p"},"data.Validator"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {\n // ...\n // the slash packet validator address may be known only on the consumer chain;\n // in this case, it must be mapped back to the consensus address on the provider chain\n consumerAddr := sdk.ConsAddress(data.Validator.Address)\n providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)\n if !found {\n // the validator has the same key on the consumer as on the provider\n providerAddr = consumer\n }\n // ...\n}\n")),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCMatured"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {\n // ...\n // prune previous consumer validator address that are no longer needed\n consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n for _, addr := range consumerAddrs {\n DeleteValidatorByConsumerAddr(chainID, addr)\n }\n DeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n // ...\n}\n")),(0,a.kt)("p",null,"On stopping a consumer chain:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {\n // ...\n // deletes all the state needed for key assignments on this consumer chain\n // ...\n}\n")),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Validators can use different consensus keys on the consumer chains.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"None")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"The consensus state necessary to create a client to the consumer chain must use the hash returned by the ",(0,a.kt)("inlineCode",{parentName:"li"},"MakeConsumerGenesis")," method as the ",(0,a.kt)("inlineCode",{parentName:"li"},"nextValsHash"),"."),(0,a.kt)("li",{parentName:"ul"},"The consumer chain can no longer check the initial validator set against the consensus state on ",(0,a.kt)("inlineCode",{parentName:"li"},"InitGenesis"),".")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/26"},"Key assignment issue"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/56185081.6b064da2.js b/legacy/assets/js/56185081.6b064da2.js new file mode 100644 index 0000000000..b8b48d0677 --- /dev/null +++ b/legacy/assets/js/56185081.6b064da2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8087],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>m});var i=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?r(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):r(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,i,a=function(e,n){if(null==e)return{};var t,i,a={},r=Object.keys(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=i.createContext({}),c=function(e){var n=i.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},p=function(e){var n=c(e.components);return i.createElement(l.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},h=i.forwardRef((function(e,n){var t=e.components,a=e.mdxType,r=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(t),h=a,m=d["".concat(l,".").concat(h)]||d[h]||u[h]||r;return t?i.createElement(m,o(o({ref:n},p),{},{components:t})):i.createElement(m,o({ref:n},p))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var r=t.length,o=new Array(r);o[0]=h;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:a,o[1]=s;for(var c=2;c<r;c++)o[c]=t[c];return i.createElement.apply(null,o)}return i.createElement.apply(null,t)}h.displayName="MDXCreateElement"},3476:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>s,toc:()=>c});var i=t(7462),a=(t(7294),t(3905));const r={sidebar_position:1},o="Overview",s={unversionedId:"validators/overview",id:"version-v3.2.0/validators/overview",title:"Overview",description:"We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.",source:"@site/versioned_docs/version-v3.2.0/validators/overview.md",sourceDirName:"validators",slug:"/validators/overview",permalink:"/interchain-security/legacy/v3.2.0/validators/overview",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Changeover Procedure",permalink:"/interchain-security/legacy/v3.2.0/consumer-development/changeover-procedure"},next:{title:"Joining Replicated Security testnet",permalink:"/interchain-security/legacy/v3.2.0/validators/joining-testnet"}},l={},c=[{value:"Startup sequence overview",id:"startup-sequence-overview",level:2},{value:"1. Consumer Chain init + 2. Genesis generation",id:"1-consumer-chain-init--2-genesis-generation",level:3},{value:"3. Submit Proposal",id:"3-submit-proposal",level:3},{value:"4. CCV Genesis state generation",id:"4-ccv-genesis-state-generation",level:3},{value:"5. Updating the genesis file",id:"5-updating-the-genesis-file",level:3},{value:"6. Chain start",id:"6-chain-start",level:3},{value:"7. Creating IBC connections",id:"7-creating-ibc-connections",level:3},{value:"Downtime Infractions",id:"downtime-infractions",level:2},{value:"Double-signing Infractions",id:"double-signing-infractions",level:2},{value:"Key assignment",id:"key-assignment",level:2},{value:"References:",id:"references",level:2}],p={toc:c},d="wrapper";function u(e){let{components:n,...r}=e;return(0,a.kt)(d,(0,i.Z)({},p,r,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"overview"},"Overview"),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"We advise that you join the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security"},"Replicated Security testnet")," to gain hands-on experience with running consumer chains.")),(0,a.kt)("p",null,"At present, replicated security requires all validators of the provider chain (ie. Cosmos Hub) to run validator nodes for all governance-approved consumer chains."),(0,a.kt)("p",null,"Once a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," passes, validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains."),(0,a.kt)("p",null,"Provider chain and consumer chains represent standalone chains that only share the validator set ie. the same validator operators are tasked with running all chains."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 180 validators for Cosmos Hub).")),(0,a.kt)("h2",{id:"startup-sequence-overview"},"Startup sequence overview"),(0,a.kt)("p",null,"Consumer chains cannot start and be secured by the validator set of the provider unless a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," is passed.\nEach proposal contains defines a ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider."),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"Validators are required to run consumer chain binaries only after ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," has passed.")),(0,a.kt)("p",null,"Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains."),(0,a.kt)("p",null,"The image below illustrates the startup sequence\n",(0,a.kt)("img",{alt:"startup",src:t(7728).Z,width:"942",height:"632"})),(0,a.kt)("h3",{id:"1-consumer-chain-init--2-genesis-generation"},"1. Consumer Chain init + 2. Genesis generation"),(0,a.kt)("p",null,"Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")),(0,a.kt)("h3",{id:"3-submit-proposal"},"3. Submit Proposal"),(0,a.kt)("p",null,"Consumer chain team (or their advocates) submits a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal"),".\nThe most important parameters for validators are:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"spawn_time")," - the time after which the consumer chain must be started"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"genesis_hash")," - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and ",(0,a.kt)("inlineCode",{parentName:"li"},"spawn_time")," is reached"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"binary_hash")," - hash of the consumer chain binary used to validate the software builds")),(0,a.kt)("h3",{id:"4-ccv-genesis-state-generation"},"4. CCV Genesis state generation"),(0,a.kt)("p",null,"After reaching ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json"),". The CCV validator set consists of the validator set on the provider at ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time"),"."),(0,a.kt)("p",null,"The state can be queried on the provider chain (in this case the Cosmos Hub):"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json\n")),(0,a.kt)("p",null,"This is used by the launch coordinator to create the final ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," that will be distributed to validators in step 5."),(0,a.kt)("h3",{id:"5-updating-the-genesis-file"},"5. Updating the genesis file"),(0,a.kt)("p",null,"Upon reaching the ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," the initial validator set state will become available on the provider chain. The initial validator set is included in the ",(0,a.kt)("strong",{parentName:"p"},"final genesis.json")," of the consumer chain."),(0,a.kt)("h3",{id:"6-chain-start"},"6. Chain start"),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences.")),(0,a.kt)("p",null,"The new ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," to start their consumer chain node."),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"Please pay attention to any onboarding repositories provided by the consumer chain teams.\nRecommendations are available in ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.2.0/consumer-development/onboarding"},"Consumer Onboarding Checklist"),".\nAnother comprehensive guide is available in the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md"},"Replicated Security testnet repo"),".")),(0,a.kt)("h3",{id:"7-creating-ibc-connections"},"7. Creating IBC connections"),(0,a.kt)("p",null,"Finally, to fully establish replicated security an IBC relayer is used to establish connections and create the required channels."),(0,a.kt)("admonition",{type:"warning"},(0,a.kt)("p",{parentName:"admonition"},"The relayer can establish the connection only after the consumer chain starts producing blocks.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> \nhermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1\nhermes start\n")),(0,a.kt)("h2",{id:"downtime-infractions"},"Downtime Infractions"),(0,a.kt)("p",null,"At present, the consumer chain can report evidence about downtime infractions to the provider chain. The ",(0,a.kt)("inlineCode",{parentName:"p"},"min_signed_per_window")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"signed_blocks_window")," can be different on each consumer chain and are subject to changes via consumer chain governance."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains."),(0,a.kt)("p",{parentName:"admonition"},"To unjail, the validator must wait for the jailing period to elapse on the provider chain and ",(0,a.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html#unjail-validator"},"submit an unjail transaction")," on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains."),(0,a.kt)("p",{parentName:"admonition"},"More information is available in ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.2.0/features/slashing#downtime-infractions"},"Downtime Slashing documentation"))),(0,a.kt)("h2",{id:"double-signing-infractions"},"Double-signing Infractions"),(0,a.kt)("p",null,"To learn more about equivocation handling in replicated security check out the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.2.0/features/slashing#double-signing-equivocation"},"Slashing")," and ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.2.0/features/proposals#equivocationproposal"},"EquivocationProposal")," documentation sections"),(0,a.kt)("h2",{id:"key-assignment"},"Key assignment"),(0,a.kt)("p",null,"Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use."),(0,a.kt)("p",null,"For more information check our the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.2.0/features/key-assignment"},"Key assignment overview and guide")),(0,a.kt)("h2",{id:"references"},"References:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-faq.html"},"Cosmos Hub Validators FAQ")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-setup.html"},"Cosmos Hub Running a validator")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md#chain-launch"},"Startup Sequence")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-setup.html#unjail-validator"},"Submit Unjailing Transaction"))))}u.isMDXComponent=!0},7728:(e,n,t)=>{t.d(n,{Z:()=>i});const i=t.p+"assets/images/hypha-consumer-start-process-2141109f76c584706dd994d7965fd692.svg"}}]); \ No newline at end of file diff --git a/legacy/assets/js/568ca951.5df0b615.js b/legacy/assets/js/568ca951.5df0b615.js new file mode 100644 index 0000000000..1e0f1267c6 --- /dev/null +++ b/legacy/assets/js/568ca951.5df0b615.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6438],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},d=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},h="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},p=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),h=c(n),p=r,m=h["".concat(l,".").concat(p)]||h[p]||u[p]||o;return n?a.createElement(m,s(s({ref:t},d),{},{components:n})):a.createElement(m,s({ref:t},d))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,s=new Array(o);s[0]=p;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[h]="string"==typeof e?e:r,s[1]=i;for(var c=2;c<o;c++)s[c]=n[c];return a.createElement.apply(null,s)}return a.createElement.apply(null,n)}p.displayName="MDXCreateElement"},781:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>c});var a=n(7462),r=(n(7294),n(3905));const o={sidebar_position:11,title:"Standalone to Consumer Changeover"},s=void 0,i={unversionedId:"adrs/adr-010-standalone-changeover",id:"version-v3.3.1-lsm/adrs/adr-010-standalone-changeover",title:"Standalone to Consumer Changeover",description:"ADR 010: Standalone to Consumer Changeover",source:"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-010-standalone-changeover.md",sourceDirName:"adrs",slug:"/adrs/adr-010-standalone-changeover",permalink:"/interchain-security/legacy/adrs/adr-010-standalone-changeover",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:11,frontMatter:{sidebar_position:11,title:"Standalone to Consumer Changeover"},sidebar:"tutorialSidebar",previous:{title:"Soft Opt-Out",permalink:"/interchain-security/legacy/adrs/adr-009-soft-opt-out"},next:{title:"Improving testing and increasing confidence",permalink:"/interchain-security/legacy/adrs/adr-011-improving-test-confidence"}},l={},c=[{value:"ADR 010: Standalone to Consumer Changeover",id:"adr-010-standalone-to-consumer-changeover",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Process",id:"process",level:3},{value:"Changes to CCV Protocol",id:"changes-to-ccv-protocol",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}],d={toc:c},h="wrapper";function u(e){let{components:t,...n}=e;return(0,r.kt)(h,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"adr-010-standalone-to-consumer-changeover"},"ADR 010: Standalone to Consumer Changeover"),(0,r.kt)("h2",{id:"changelog"},"Changelog"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"6/30/23: Feature completed, first draft of ADR.")),(0,r.kt)("h2",{id:"status"},"Status"),(0,r.kt)("p",null,"Implemented"),(0,r.kt)("h2",{id:"context"},"Context"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/Stride-Labs/stride"},"Stride"),' will be the first consumer to "changeover" from a standalone cosmos blockchain, to a consumer chain secured by the Cosmos Hub. This document will outline the changes made to the replicated security protocol to support this changeover process.'),(0,r.kt)("h2",{id:"decision"},"Decision"),(0,r.kt)("h3",{id:"process"},"Process"),(0,r.kt)("p",null,'Prior to the changeover, the consumer chain will have an existing staking keeper and validator set, these may be referred to as the "standalone staking keeper" and "standalone validator set" respectively. '),(0,r.kt)("p",null,"The first step in the changeover process is to submit a ConsumerAdditionProposal. If the proposal passes, the provider will create a new IBC client for the consumer at spawn time, with the provider's validator set. A consumer genesis will also be constructed by the provider for validators to query. Within this consumer genesis contains the initial validator set for the consumer to apply after the changeover."),(0,r.kt)("p",null,"Next, the standalone consumer chain runs an upgrade which adds the CCV module, and is properly setup to execute changeover logic."),(0,r.kt)("p",null,"The consumer upgrade height must be reached after the provider has created the new IBC client. Any replicated security validators who will run the consumer, but are not a part of the sovereign validator set, must sync up a full node before the consumer upgrade height is reached. The disc state of said full node will be used to run the consumer chain after the changeover has completed."),(0,r.kt)("p",null,"The meat of the changeover logic is that the consumer chain validator set is updated to that which was specified by the provider via the queried consumer genesis. Validators which were a part of the old set, but not the new set, are given zero voting power. Once these validator updates are given to Comet, the set is committed, and in effect 2 blocks later (see ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/x/ccv/consumer/keeper/changeover.go#L19"},"FirstConsumerHeight"),")."),(0,r.kt)("p",null,"A relayer then establishes the new IBC connection between the provider and consumer. The CCV channel handshake is started on top of this connection. Once the CCV channel is established and VSC packets are being relayed, the consumer chain is secured by the provider."),(0,r.kt)("h3",{id:"changes-to-ccv-protocol"},"Changes to CCV Protocol"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Consumer Genesis state is updated to include a ",(0,r.kt)("inlineCode",{parentName:"li"},"PreCCV")," boolean. When this boolean is set true in the consumer genesis JSON, ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/x/ccv/consumer/keeper/changeover.go"},"special logic")," is executed on InitGenesis to trigger the changeover process on the consumer's first endblocker after the upgrade which adds the CCV module. Note that InitGenesis is not automatically called during chain upgrades, so the consumer must manually call the consumer's InitGenesis method in an upgrade handler."),(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal")," type is updated to include a ",(0,r.kt)("inlineCode",{parentName:"li"},"DistributionTransmissionChannel")," field. This field allows the consumer to use an existing IBC transfer channel to send rewards as a part of the CCV protocol. Consumers that're not changing over from a standalone chain will leave this field blank, indicating that a new transfer channel should be created on top of the same connection as the CCV channel."),(0,r.kt)("li",{parentName:"ul"},"The CCV consumer keeper is updated to contain an optional reference to the standalone staking keeper. The standalone staking keeper is used to slash for infractions that happened before the changeover was completed. Ie. any infraction from a block height before the changeover, that is submitted after the changeover, will call the standalone staking keeper's slash method. Note that a changeover consumer's standalone staking keeper becomes a democracy module keeper, so it is possible for a governance token to be slashed.")),(0,r.kt)("h2",{id:"consequences"},"Consequences"),(0,r.kt)("h3",{id:"positive"},"Positive"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Existing cosmos chains are now able to onboard over to a consumer chain secured by a provider."),(0,r.kt)("li",{parentName:"ul"},"The previous staking keepers for such chains can be transitioned to democracy staking module keepers.")),(0,r.kt)("h3",{id:"negative"},"Negative"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"The delineation between different types of consumers in this repo becomes less clear. Ie. there is code in the ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/app/consumer-democracy/app.go"},"democracy consumer's app.go")," that only applies to a previously standalone chain, but that file also serves as the base for a normal democracy consumer launched with RS from genesis.")),(0,r.kt)("h2",{id:"references"},"References"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"EPIC: Standalone to Consumer Changeover ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/756"},"#756")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt"},"Changeover diagram from Stride"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/57203821.5604c344.js b/legacy/assets/js/57203821.5604c344.js new file mode 100644 index 0000000000..2e7dd82b17 --- /dev/null +++ b/legacy/assets/js/57203821.5604c344.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8646],{3905:(t,e,n)=>{n.d(e,{Zo:()=>p,kt:()=>g});var a=n(7294);function i(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function r(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,a)}return n}function l(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?r(Object(n),!0).forEach((function(e){i(t,e,n[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))}))}return t}function s(t,e){if(null==t)return{};var n,a,i=function(t,e){if(null==t)return{};var n,a,i={},r=Object.keys(t);for(a=0;a<r.length;a++)n=r[a],e.indexOf(n)>=0||(i[n]=t[n]);return i}(t,e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);for(a=0;a<r.length;a++)n=r[a],e.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(i[n]=t[n])}return i}var o=a.createContext({}),u=function(t){var e=a.useContext(o),n=e;return t&&(n="function"==typeof t?t(e):l(l({},e),t)),n},p=function(t){var e=u(t.components);return a.createElement(o.Provider,{value:e},t.children)},d="mdxType",c={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},m=a.forwardRef((function(t,e){var n=t.components,i=t.mdxType,r=t.originalType,o=t.parentName,p=s(t,["components","mdxType","originalType","parentName"]),d=u(n),m=i,g=d["".concat(o,".").concat(m)]||d[m]||c[m]||r;return n?a.createElement(g,l(l({ref:e},p),{},{components:n})):a.createElement(g,l({ref:e},p))}));function g(t,e){var n=arguments,i=e&&e.mdxType;if("string"==typeof t||i){var r=n.length,l=new Array(r);l[0]=m;var s={};for(var o in e)hasOwnProperty.call(e,o)&&(s[o]=e[o]);s.originalType=t,s[d]="string"==typeof t?t:i,l[1]=s;for(var u=2;u<r;u++)l[u]=n[u];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},5942:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>o,contentTitle:()=>l,default:()=>c,frontMatter:()=>r,metadata:()=>s,toc:()=>u});var a=n(7462),i=(n(7294),n(3905));const r={sidebar_position:12,title:"Improving testing and increasing confidence"},l="ADR 11: Improving testing and increasing confidence",s={unversionedId:"adrs/adr-011-improving-test-confidence",id:"version-v3.2.0/adrs/adr-011-improving-test-confidence",title:"Improving testing and increasing confidence",description:"Changelog",source:"@site/versioned_docs/version-v3.2.0/adrs/adr-011-improving-test-confidence.md",sourceDirName:"adrs",slug:"/adrs/adr-011-improving-test-confidence",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-011-improving-test-confidence",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:12,frontMatter:{sidebar_position:12,title:"Improving testing and increasing confidence"},sidebar:"tutorialSidebar",previous:{title:"Standalone to Consumer Changeover",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-010-standalone-changeover"},next:{title:"Separate Releasing",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-012-separate-releasing"}},o={},u=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Current state of testing",id:"current-state-of-testing",level:4},{value:"Unit testing",id:"unit-testing",level:3},{value:"Integration testing",id:"integration-testing",level:3},{value:"End-to-end testing",id:"end-to-end-testing",level:3},{value:"Decision",id:"decision",level:2},{value:"1. Connect specifications to code and tooling",id:"1-connect-specifications-to-code-and-tooling",level:3},{value:"Decision context and hypothesis",id:"decision-context-and-hypothesis",level:4},{value:"Main benefit",id:"main-benefit",level:4},{value:"2. Improve e2e tooling",id:"2-improve-e2e-tooling",level:3},{value:"Matrix tests",id:"matrix-tests",level:4},{value:"Introducing e2e regression testing",id:"introducing-e2e-regression-testing",level:4},{value:"Introducing e2e CometMock tests",id:"introducing-e2e-cometmock-tests",level:4},{value:"3. Introduce innovative testing approaches",id:"3-introduce-innovative-testing-approaches",level:3},{value:"Model",id:"model",level:4},{value:"Driver",id:"driver",level:4},{value:"Harness",id:"harness",level:4},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],p={toc:u},d="wrapper";function c(t){let{components:e,...r}=t;return(0,i.kt)(d,(0,a.Z)({},p,r,{components:e,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"adr-11-improving-testing-and-increasing-confidence"},"ADR 11: Improving testing and increasing confidence"),(0,i.kt)("h2",{id:"changelog"},"Changelog"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"2023-08-11: Proposed, first draft of ADR.")),(0,i.kt)("h2",{id:"status"},"Status"),(0,i.kt)("p",null,"Proposed"),(0,i.kt)("h2",{id:"context"},"Context"),(0,i.kt)("p",null,"Testing, QA, and maintenance of interchain-security libraries is an ever-evolving area of software engineering we have to keep incrementally improving. The purpose of the QA process is to catch bugs as early as possible. In an ideal development workflow a bug should never reach production. A bug found in the specification stage is a lot cheaper to resolve than a bug discovered in production (or even in testnet). Ideally, all bugs should be found during the CI execution, and we hope that no bugs will ever even reach the testnet (although nothing can replace actual system stress test under load interacting with users)."),(0,i.kt)("p",null,"During development and testnet operation the following types of bugs were the most commonly found:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"improper iterator usage"),(0,i.kt)("li",{parentName:"ul"},"unbounded array access/iteration"),(0,i.kt)("li",{parentName:"ul"},"improper input handling and validation"),(0,i.kt)("li",{parentName:"ul"},"improper cached context usage"),(0,i.kt)("li",{parentName:"ul"},"non-determinism check (improper use of maps in go, relying on random values)"),(0,i.kt)("li",{parentName:"ul"},"KV store management and/or how keys are defined"),(0,i.kt)("li",{parentName:"ul"},"deserialization issues arising from consumer/provider versioning mismatch")),(0,i.kt)("p",null,"Such bugs can be discovered earlier with better tooling. Some of these bugs can induce increases in block times, chain halts, state corruption, or introduce an attack surface which is difficult to remove if other systems have started depending on that behavior."),(0,i.kt)("h4",{id:"current-state-of-testing"},"Current state of testing"),(0,i.kt)("p",null,"Our testing suites consist of multiple parts, each with their own trade-offs and benefits with regards to code coverage, complexity and confidence they provide."),(0,i.kt)("h3",{id:"unit-testing"},"Unit testing"),(0,i.kt)("p",null,"Unit testing is employed mostly for testing single-module functionality. It is the first step in testing and often the most practical. While highly important, unit tests often ",(0,i.kt)("strong",{parentName:"p"},"test a single piece of code")," and don't test relationships between different moving parts, this makes them less valuable when dealing with multi-module interactions."),(0,i.kt)("p",null,"Unit tests often employ mocks to abstract parts of the system that are not under test. Mocks are not equivalent to actual models and should not be treated as such."),(0,i.kt)("p",null,"Out of all the approaches used, unit testing has the most tools available and the coverage can simply be displayed as % of code lines tested. Although this is a very nice and very easy to understand metric, it does not speak about the quality of the test coverage."),(0,i.kt)("p",null,"Since distributed systems testing is a lot more involved, unit tests are oftentimes not sufficient to cover complex interactions. Unit tests are still necessary and helpful, but in cases where unit tests are not helpful e2e or integration tests should be favored."),(0,i.kt)("h3",{id:"integration-testing"},"Integration testing"),(0,i.kt)("p",null,"With integration testing we ",(0,i.kt)("strong",{parentName:"p"},"test the multi-module interactions")," while isolating them from the remainder of the system.\nIntegration tests can uncover bugs that are often missed by unit tests."),(0,i.kt)("p",null,"It is very difficult to gauge the actual test coverage imparted by integration tests and the available tooling is limited.\nIn interchain-security we employ the ",(0,i.kt)("inlineCode",{parentName:"p"},"ibc-go/testing")," framework to test interactions in-memory."),(0,i.kt)("p",null,"At present, integration testing does not involve the consensus layer - it is only concerned with application level state and logic."),(0,i.kt)("h3",{id:"end-to-end-testing"},"End-to-end testing"),(0,i.kt)("p",null,"In our context end-to-end testing comprises of tests that use the actual application binaries in an isolated environment (e.g. docker container). During test execution the inputs are meant to simulate actual user interaction, either by submitting transactions/queries using the command line or using gRPC/REST APIs and checking for state changes after an action has been performed. With this testing strategy we also include the consensus layer in all of our runs. This is the closest we can get to testing user interactions without starting a full testnet."),(0,i.kt)("p",null,"End-to-end testing strategies vary between different teams and projects and we strive to unify our approach to the best of our ability (at least for ICS and gaia)."),(0,i.kt)("p",null,"The available tooling does not give us significant (or relevant) line of code coverage information since most of the tools are geared towards analyzing unit tests and simple code branch evaluation."),(0,i.kt)("p",null,"We aim to adapt our best practices by learning from other similar systems and projects such as cosmos-sdk, ibc-go and CometBFT."),(0,i.kt)("h2",{id:"decision"},"Decision"),(0,i.kt)("h3",{id:"1-connect-specifications-to-code-and-tooling"},"1. Connect specifications to code and tooling"),(0,i.kt)("p",null,"Oftentimes, specifications are disconnected from the development and QA processes. This gives rise to problems where the specification does not reflect the actual state of the system and vice-versa.\nUsually specifications are just text files that are rarely used and go unmaintained after a while, resulting in consistency issues and misleading instructions/expectations about system behavior."),(0,i.kt)("h4",{id:"decision-context-and-hypothesis"},"Decision context and hypothesis"),(0,i.kt)("p",null,"Specifications written in a dedicated and executable specification language are easier to maintain than the ones written entirely in text.\nAdditionally, we can create models based on the specification OR make the model equivalent to a specification."),(0,i.kt)("p",null,"Models do not care about the intricacies of implementation and neither do specifications. Since both models and specifications care about concisely and accurately describing a system (such as a finite state machine), we see a benefit of adding model based tools (such as ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/informalsystems/quint"},"quint"),") to our testing and development workflows."),(0,i.kt)("h4",{id:"main-benefit"},"Main benefit"),(0,i.kt)("p",null,"MBT tooling can be used to generate test traces that can be executed by multiple different testing setups."),(0,i.kt)("h3",{id:"2-improve-e2e-tooling"},"2. Improve e2e tooling"),(0,i.kt)("h4",{id:"matrix-tests"},"Matrix tests"),(0,i.kt)("p",null,"Instead of only running tests against current ",(0,i.kt)("inlineCode",{parentName:"p"},"main")," branch we should adopt an approach where we also:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"run regression tests against different released software versions")," (",(0,i.kt)("inlineCode",{parentName:"li"},"ICS v1 vs v2 vs v3"),")"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"run non-determinism tests to uncover issues quickly"))),(0,i.kt)("p",null,"Matrix tests can be implemented using ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/informalsystems/CometMock"},"CometMock")," and refactoring our current e2e CI setup."),(0,i.kt)("h4",{id:"introducing-e2e-regression-testing"},"Introducing e2e regression testing"),(0,i.kt)("p",null,"This e2e test suite would execute using a cronjob in our CI (nightly, multiple times a day etc.)"),(0,i.kt)("p",null,"Briefly, the same set of traces is run against different ",(0,i.kt)("strong",{parentName:"p"},"maintained")," versions of the software and the ",(0,i.kt)("inlineCode",{parentName:"p"},"main")," branch.\nThis would allow us to discover potential issues during development instead of in a testnet scenarios."),(0,i.kt)("p",null,"The most valuable issues that can be discovered in this way are ",(0,i.kt)("strong",{parentName:"p"},"state breaking changes"),", ",(0,i.kt)("strong",{parentName:"p"},"regressions")," and ",(0,i.kt)("strong",{parentName:"p"},"version incompatibilities"),"."),(0,i.kt)("p",null,"The setup is illustrated by the image below.\n",(0,i.kt)("img",{alt:"e2e matrix tests",src:n(1366).Z,width:"2170",height:"1624"})),(0,i.kt)("p",null,"This table explains which versions are tested against each other for the same set of test traces:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"\u2705 marks a passing test"),(0,i.kt)("li",{parentName:"ul"},"\u274c marks a failing test")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"USES: ICS v1 PROVIDER")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"start chain")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"add key")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"delegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"undelegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"redelegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"downtime")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"equivocation")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"stop chain")))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"v1 consumer (sdk45,ibc4.3)")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"v2 consumer (sdk45, ibc4.4)")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"v3 consumer (sdk47, ibc7)")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"main consumer")),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"neutron")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"stride")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c")))),(0,i.kt)("h4",{id:"introducing-e2e-cometmock-tests"},"Introducing e2e CometMock tests"),(0,i.kt)("p",null,"CometMock is a mock implementation of the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft"},"CometBFT")," consensus engine. It supports most operations performed by CometBFT while also being lightweight and relatively easy to use."),(0,i.kt)("p",null,'CometMock tests allow more nuanced control of test scenarios because CometMock can "fool" the blockchain app into thinking that a certain number of blocks had passed.\n',(0,i.kt)("strong",{parentName:"p"},"This allows us to test very nuanced scenarios, difficult edge cases and long-running operations (such as unbonding operations).")),(0,i.kt)("p",null,"Examples of tests made easier with CometMock are listed below:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"regression tests"),(0,i.kt)("li",{parentName:"ul"},"non-determinism tests"),(0,i.kt)("li",{parentName:"ul"},"upgrade tests"),(0,i.kt)("li",{parentName:"ul"},"state-breaking changes")),(0,i.kt)("p",null,"With CometMock, the ",(0,i.kt)("strong",{parentName:"p"},"matrix test")," approach can also be used. The image below illustrates a CometMock setup that can be used to discover non-deterministic behavior and state-breaking changes.\n",(0,i.kt)("img",{alt:"e2e matrix tests",src:n(3809).Z,width:"3714",height:"2082"})),(0,i.kt)("p",null,"This table explains which versions are tested against each other for the same set of test traces:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"\u2705 marks a passing test"),(0,i.kt)("li",{parentName:"ul"},"\u274c marks a failing test")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"SCENARIO")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"start chain")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"add key")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"delegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"undelegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"redelegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"downtime")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"equivocation")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"stop chain")))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"v3 provi + v3 consu")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"main provi + main consu")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"commit provi + commit consu")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c")))),(0,i.kt)("p",null,"Briefly; multiple versions of the application are run against the same CometMock instance and any deviations in app behavior would result in ",(0,i.kt)("inlineCode",{parentName:"p"},"app hash")," errors (the apps would be in different states after performing the same set of actions)."),(0,i.kt)("h3",{id:"3-introduce-innovative-testing-approaches"},"3. Introduce innovative testing approaches"),(0,i.kt)("p",null,"When discussing e2e testing, some very important patterns emerge - especially if test traces are used instead of ad-hoc tests written by hand."),(0,i.kt)("p",null,"We see a unique opportunity to clearly identify concerns and modularize the testing architecture. "),(0,i.kt)("p",null,"The e2e testing frameworks can be split into a ",(0,i.kt)("strong",{parentName:"p"},"pipeline consisting of 3 parts: model, driver and harness"),"."),(0,i.kt)("h4",{id:"model"},"Model"),(0,i.kt)("p",null,"Model is the part of the system that can emulate the behavior of the system under test.\nIdeally, it is very close to the specification and is written in a specification language such as quint, TLA+ or similar.\nOne of the purposes of the model is that it can be used to generate test traces. "),(0,i.kt)("h4",{id:"driver"},"Driver"),(0,i.kt)("p",null,"The purpose of the driver is to accept test traces (generated by the model or written by hand), process them and provide inputs to the next part of the pipeline."),(0,i.kt)("p",null,"Basically, the driver sits between the model and the actual infrastructure on which the test traces are being executed on."),(0,i.kt)("h4",{id:"harness"},"Harness"),(0,i.kt)("p",null,"Harness is the infrastructure layer of the pipeline that accepts inputs from the driver."),(0,i.kt)("p",null,"There can be multiple harnesses as long as they can perform four things:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"bootstrap a test execution environment (local, docker, k8s\u2026)"),(0,i.kt)("li",{parentName:"ul"},"accept inputs from drivers"),(0,i.kt)("li",{parentName:"ul"},"perform the action specified by the driver"),(0,i.kt)("li",{parentName:"ul"},"report results after performing actions")),(0,i.kt)("h2",{id:"consequences"},"Consequences"),(0,i.kt)("p",null,"The procedure outlined in this ADR is not an all-or-nothing approach. Concepts introduced here do not rely on each other, so this ADR may only be applied partially without negative impact on test coverage and code confidence."),(0,i.kt)("h3",{id:"positive"},"Positive"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"introduction of maintainable MBT solutions")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},'improvement over the current "difftest" setup that relies on an opinionated typescript model and go driver')),(0,i.kt)("ol",{start:2},(0,i.kt)("li",{parentName:"ol"},"increased code coverage and confidence")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"using CometMock allows us to run more tests in less time"),(0,i.kt)("li",{parentName:"ul"},"adding matrix e2e tests allows us to quickly pinpoint differences between code versions")),(0,i.kt)("h3",{id:"negative"},"Negative"),(0,i.kt)("p",null,"It might be easier to forgo the MBT tooling and instead focus on pure property based testing"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/667"},"PBT proof of concept")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/flyingmutant/rapid"},"property based testing in go"))),(0,i.kt)("p",null,'The solutions are potentially expensive if we increase usage of the CI pipeline - this is fixed by running "expensive" tests using a cronjob, instead of running them on every commit.'),(0,i.kt)("h3",{id:"neutral"},"Neutral"),(0,i.kt)("p",null,"The process of changing development and testing process is not something that can be thought of and delivered quickly. Luckily, the changes can be rolled out incrementally without impacting existing workflows."),(0,i.kt)("h2",{id:"references"},"References"),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/gaia/issues/2427"},"https://github.com/cosmos/gaia/issues/2427")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/gaia/issues/2420"},"https://github.com/cosmos/gaia/issues/2420")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/ibc-go/tree/main/e2e"},"ibc-go e2e tests"))))}c.isMDXComponent=!0},3809:(t,e,n)=>{n.d(e,{Z:()=>a});const a=n.p+"assets/images/cometmock_matrix_test-714f36252aff9df4214823e3145d0ef5.png"},1366:(t,e,n)=>{n.d(e,{Z:()=>a});const a=n.p+"assets/images/matrix_e2e_tests-30681305077301daaf3097e1952b54bb.png"}}]); \ No newline at end of file diff --git a/legacy/assets/js/578fb1aa.43e0b978.js b/legacy/assets/js/578fb1aa.43e0b978.js new file mode 100644 index 0000000000..91fe93a345 --- /dev/null +++ b/legacy/assets/js/578fb1aa.43e0b978.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2323],{3905:(e,r,t)=>{t.d(r,{Zo:()=>l,kt:()=>h});var n=t(7294);function i(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function o(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function a(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?o(Object(t),!0).forEach((function(r){i(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function s(e,r){if(null==e)return{};var t,n,i=function(e,r){if(null==e)return{};var t,n,i={},o=Object.keys(e);for(n=0;n<o.length;n++)t=o[n],r.indexOf(t)>=0||(i[t]=e[t]);return i}(e,r);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)t=o[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var d=n.createContext({}),c=function(e){var r=n.useContext(d),t=r;return e&&(t="function"==typeof e?e(r):a(a({},r),e)),t},l=function(e){var r=c(e.components);return n.createElement(d.Provider,{value:r},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},m=n.forwardRef((function(e,r){var t=e.components,i=e.mdxType,o=e.originalType,d=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=c(t),m=i,h=u["".concat(d,".").concat(m)]||u[m]||p[m]||o;return t?n.createElement(h,a(a({ref:r},l),{},{components:t})):n.createElement(h,a({ref:r},l))}));function h(e,r){var t=arguments,i=r&&r.mdxType;if("string"==typeof e||i){var o=t.length,a=new Array(o);a[0]=m;var s={};for(var d in r)hasOwnProperty.call(r,d)&&(s[d]=r[d]);s.originalType=e,s[u]="string"==typeof e?e:i,a[1]=s;for(var c=2;c<o;c++)a[c]=t[c];return n.createElement.apply(null,a)}return n.createElement.apply(null,t)}m.displayName="MDXCreateElement"},5790:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>d,contentTitle:()=>a,default:()=>p,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var n=t(7462),i=(t(7294),t(3905));const o={sidebar_position:2},a="Reward distribution",s={unversionedId:"features/reward-distribution",id:"features/reward-distribution",title:"Reward distribution",description:"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.",source:"@site/docs/features/reward-distribution.md",sourceDirName:"features",slug:"/features/reward-distribution",permalink:"/interchain-security/legacy/features/reward-distribution",draft:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/legacy/features/key-assignment"},next:{title:"ICS Provider Proposals",permalink:"/interchain-security/legacy/features/proposals"}},d={},c=[{value:"Note",id:"note",level:2},{value:"Instructions for adding a denom",id:"instructions-for-adding-a-denom",level:3},{value:"Parameters",id:"parameters",level:2},{value:"<code>consumer_redistribution_fraction</code>",id:"consumer_redistribution_fraction",level:3},{value:"<code>blocks_per_distribution_transmission</code>",id:"blocks_per_distribution_transmission",level:3},{value:"<code>transfer_timeout_period</code>",id:"transfer_timeout_period",level:3},{value:"<code>distribution_transmission_channel</code>",id:"distribution_transmission_channel",level:3},{value:"<code>provider_fee_pool_addr_str</code>",id:"provider_fee_pool_addr_str",level:3}],l={toc:c},u="wrapper";function p(e){let{components:r,...t}=e;return(0,i.kt)(u,(0,n.Z)({},l,t,{components:r,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"reward-distribution"},"Reward distribution"),(0,i.kt)("p",null,"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.\nIn replicated security block rewards and fees are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel that gets created during consumer chain initialization."),(0,i.kt)("p",null,"Reward distribution on the provider is handled by the distribution module - validators and delegators receive a fraction of the consumer chain tokens as staking rewards.\nThe distributed reward tokens are IBC tokens and therefore cannot be staked on the provider chain."),(0,i.kt)("p",null,"Sending and distributing rewards from consumer chains to provider chain is handled by the ",(0,i.kt)("inlineCode",{parentName:"p"},"Reward Distribution")," sub-protocol."),(0,i.kt)("h2",{id:"note"},"Note"),(0,i.kt)("p",null,"The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerRewardsPool"),".\nThere is a new transaction type called ",(0,i.kt)("inlineCode",{parentName:"p"},"RegisterConsumerRewardDenom"),". This transaction allows consumer chains to register denoms to be used as consumer chain rewards on the provider.\nThe cost to register a denom is configurable (",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerRewardDenomRegistrationFee")," chain param) and the full amount of this fee is transferred to the community pool of the provider chain. Only denoms registered through this transaction are then transferred from the ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerRewardsPool")," to the ",(0,i.kt)("inlineCode",{parentName:"p"},"FeePoolAddress"),", to be distributed out to delegators and validators."),(0,i.kt)("h3",{id:"instructions-for-adding-a-denom"},"Instructions for adding a denom"),(0,i.kt)("p",null,"The transaction must be carried out on the provider chain. Please use the ",(0,i.kt)("inlineCode",{parentName:"p"},"ibc/*")," denom trace format."),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre"},"# reward denoms must be registered on the provider chain (gaia in this example)\ngaiad tx provider register-consumer-reward-denom ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9 --from mykey\n"))),(0,i.kt)("h2",{id:"parameters"},"Parameters"),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"The following chain parameters dictate consumer chain distribution amount and frequency.\nThey are set at consumer genesis and ",(0,i.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction"),"\n",(0,i.kt)("inlineCode",{parentName:"p"},"transfer_timeout_period")," must be provided in every ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerChainAddition")," proposal.")),(0,i.kt)("h3",{id:"consumer_redistribution_fraction"},(0,i.kt)("inlineCode",{parentName:"h3"},"consumer_redistribution_fraction")),(0,i.kt)("p",null,'The fraction of tokens allocated to the consumer redistribution address during distribution events. The fraction is a string representing a decimal number. For example "0.75" would represent 75%.'),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"Example:"),(0,i.kt)("p",{parentName:"admonition"},"With ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction")," set to ",(0,i.kt)("inlineCode",{parentName:"p"},"0.75")," the consumer chain would send 75% of its block rewards and accumulated fees to the consumer redistribution address, and the remaining 25% to the provider chain every ",(0,i.kt)("inlineCode",{parentName:"p"},"n")," blocks where ",(0,i.kt)("inlineCode",{parentName:"p"},"n == blocks_per_distribution_transmission"),".")),(0,i.kt)("h3",{id:"blocks_per_distribution_transmission"},(0,i.kt)("inlineCode",{parentName:"h3"},"blocks_per_distribution_transmission")),(0,i.kt)("p",null,"The number of blocks between IBC token transfers from the consumer chain to the provider chain."),(0,i.kt)("h3",{id:"transfer_timeout_period"},(0,i.kt)("inlineCode",{parentName:"h3"},"transfer_timeout_period")),(0,i.kt)("p",null,"Timeout period for consumer chain reward distribution IBC packets."),(0,i.kt)("h3",{id:"distribution_transmission_channel"},(0,i.kt)("inlineCode",{parentName:"h3"},"distribution_transmission_channel")),(0,i.kt)("p",null,"Provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."),(0,i.kt)("h3",{id:"provider_fee_pool_addr_str"},(0,i.kt)("inlineCode",{parentName:"h3"},"provider_fee_pool_addr_str")),(0,i.kt)("p",null,"Provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/57c82761.afd24b48.js b/legacy/assets/js/57c82761.afd24b48.js new file mode 100644 index 0000000000..958c62e0c4 --- /dev/null +++ b/legacy/assets/js/57c82761.afd24b48.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3422],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=l(n),u=i,h=d["".concat(c,".").concat(u)]||d[u]||m[u]||o;return n?a.createElement(h,r(r({ref:t},p),{},{components:n})):a.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=u;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:i,r[1]=s;for(var l=2;l<o;l++)r[l]=n[l];return a.createElement.apply(null,r)}return a.createElement.apply(null,n)}u.displayName="MDXCreateElement"},8383:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>m,frontMatter:()=>o,metadata:()=>s,toc:()=>l});var a=n(7462),i=(n(7294),n(3905));const o={sidebar_position:4,title:"Onboarding Checklist"},r="Consumer Onboarding Checklist",s={unversionedId:"consumer-development/onboarding",id:"version-v3.1.0/consumer-development/onboarding",title:"Onboarding Checklist",description:"The following checklists will aid in onboarding a new consumer chain to replicated security.",source:"@site/versioned_docs/version-v3.1.0/consumer-development/onboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/onboarding",permalink:"/interchain-security/legacy/v3.1.0/consumer-development/onboarding",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Onboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Upgrading Consumer Chains",permalink:"/interchain-security/legacy/v3.1.0/consumer-development/consumer-chain-upgrade-procedure"},next:{title:"Offboarding Checklist",permalink:"/interchain-security/legacy/v3.1.0/consumer-development/offboarding"}},c={},l=[{value:"1. Complete testing & integration",id:"1-complete-testing--integration",level:2},{value:"2. Create an Onboarding Repository",id:"2-create-an-onboarding-repository",level:2},{value:"3. Submit a Governance Proposal",id:"3-submit-a-governance-proposal",level:2},{value:"4. Launch",id:"4-launch",level:2}],p={toc:l},d="wrapper";function m(e){let{components:t,...n}=e;return(0,i.kt)(d,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"consumer-onboarding-checklist"},"Consumer Onboarding Checklist"),(0,i.kt)("p",null,"The following checklists will aid in onboarding a new consumer chain to replicated security."),(0,i.kt)("p",null,"Additionally, you can check the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md"},"testnet repo")," for a comprehensive guide on preparing and launching consumer chains."),(0,i.kt)("h2",{id:"1-complete-testing--integration"},"1. Complete testing & integration"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test integration with gaia"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test your protocol with supported relayer versions (minimum hermes 1.4.1)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","reach out to the ICS team if you are facing issues")),(0,i.kt)("h2",{id:"2-create-an-onboarding-repository"},"2. Create an Onboarding Repository"),(0,i.kt)("p",null,"To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain."),(0,i.kt)("p",null,"This should include (at minimum):"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json witout CCV data (before the propsal passes)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json with CCV data (after spawn time passes)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","information about relevant seed/peer nodes you are running"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","relayer information (compatible versions)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","copy of your governance proposal (as JSON)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","a script showing how to start your chain and connect to peers (optional)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable")),(0,i.kt)("p",null,"Example of such a repository can be found ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyphacoop/ics-testnets/tree/main/game-of-chains-2022/sputnik"},"here"),"."),(0,i.kt)("h2",{id:"3-submit-a-governance-proposal"},"3. Submit a Governance Proposal"),(0,i.kt)("p",null,"Before you submit a ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerChainAddition")," proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch.\nIf possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues."),(0,i.kt)("p",null,"Additionally, reach out to the community via the ",(0,i.kt)("a",{parentName:"p",href:"https://forum.cosmos.network/"},"forum")," to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine your chain's spawn time"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine consumer chain parameters to be put in the proposal"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take note to include a link to your onboarding repository"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","describe the purpose and benefits of running your chain")),(0,i.kt)("p",null,"Example of a consumer chain addition proposal."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},'// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.\n// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.\n// It is recommended that spawn time occurs after the proposal end time.\n{\n // Title of the proposal\n "title": "Add consumer chain",\n // Description of the proposal\n // format the text as a .md file and include the file in your onboarding repository\n "description": ".md description of your chain and all other relevant information",\n // Proposed chain-id of the new consumer chain.\n // Must be unique from all other consumer chain ids of the executing provider chain.\n "chain_id": "newchain-1",\n // Initial height of new consumer chain.\n // For a completely new chain, this will be {0,1}.\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Hash of the consumer chain genesis state without the consumer CCV module genesis params.\n // It is used for off-chain confirmation of genesis.json validity by validators and other parties.\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n // Hash of the consumer chain binary that should be run by validators on chain initialization.\n // It is used for off-chain confirmation of binary validity by validators and other parties.\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n // Unbonding period for the consumer chain.\n // It should should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n // IBC transfer packets will timeout after this interval elapses.\n "transfer_timeout_period": 1800000000000,\n // The fraction of tokens allocated to the consumer redistribution address during distribution events.\n // The fraction is a string representing a decimal number. For example "0.75" would represent 75%.\n // The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.\n "consumer_redistribution_fraction": "0.75",\n // BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.\n // eg. send rewards to the provider every 1000 blocks\n "blocks_per_distribution_transmission": 1000,\n // The number of historical info entries to persist in store.\n // This param is a part of the cosmos sdk staking module. In the case of\n // a ccv enabled consumer chain, the ccv module acts as the staking module.\n "historical_entries": 10000,\n // The ID of a token transfer channel used for the Reward Distribution\n // sub-protocol. If DistributionTransmissionChannel == "", a new transfer\n // channel is created on top of the same connection as the CCV channel.\n // Note that transfer_channel_id is the ID of the channel end on the consumer chain.\n // it is most relevant for chains performing a sovereign to consumer changeover\n // in order to maintan the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123"\n}\n')),(0,i.kt)("h2",{id:"4-launch"},"4. Launch"),(0,i.kt)("p",null,"The consumer chain starts after at least 66.67% of all provider's voting power comes online. The consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","provide a repo with onboarding instructions for validators (it should already be listed in the proposal)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json with ccv data populated (MUST contain the initial validator set)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","have a block explorer in place to track chain activity & health")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/5f35bbec.c4fbb0a0.js b/legacy/assets/js/5f35bbec.c4fbb0a0.js new file mode 100644 index 0000000000..604889b34c --- /dev/null +++ b/legacy/assets/js/5f35bbec.c4fbb0a0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6322],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>p});var i=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,i)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){n(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,i,n=function(e,t){if(null==e)return{};var r,i,n={},o=Object.keys(e);for(i=0;i<o.length;i++)r=o[i],t.indexOf(r)>=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i<o.length;i++)r=o[i],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=i.createContext({}),l=function(e){var t=i.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},u=function(e){var t=l(e.components);return i.createElement(s.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},y=i.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),d=l(r),y=n,p=d["".concat(s,".").concat(y)]||d[y]||h[y]||o;return r?i.createElement(p,a(a({ref:t},u),{},{components:r})):i.createElement(p,a({ref:t},u))}));function p(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,a=new Array(o);a[0]=y;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[d]="string"==typeof e?e:n,a[1]=c;for(var l=2;l<o;l++)a[l]=r[l];return i.createElement.apply(null,a)}return i.createElement.apply(null,r)}y.displayName="MDXCreateElement"},117:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>c,toc:()=>l});var i=r(7462),n=(r(7294),r(3905));const o={sidebar_position:2},a="Terminology",c={unversionedId:"introduction/terminology",id:"version-v2.0.0/introduction/terminology",title:"Terminology",description:"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.",source:"@site/versioned_docs/version-v2.0.0/introduction/terminology.md",sourceDirName:"introduction",slug:"/introduction/terminology",permalink:"/interchain-security/legacy/v2.0.0/introduction/terminology",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/legacy/v2.0.0/introduction/overview"},next:{title:"Interchain Security Parameters",permalink:"/interchain-security/legacy/v2.0.0/introduction/params"}},s={},l=[{value:"Shared Security",id:"shared-security",level:2},{value:"Interchain Security",id:"interchain-security",level:2},{value:"Replicated Security",id:"replicated-security",level:2},{value:"Mesh security",id:"mesh-security",level:2}],u={toc:l},d="wrapper";function h(e){let{components:t,...r}=e;return(0,n.kt)(d,(0,i.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"terminology"},"Terminology"),(0,n.kt)("p",null,"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions."),(0,n.kt)("h2",{id:"shared-security"},"Shared Security"),(0,n.kt)("p",null,"Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share it's proof-of-stake security with another blockchain or off-chain process."),(0,n.kt)("h2",{id:"interchain-security"},"Interchain Security"),(0,n.kt)("p",null,"Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC."),(0,n.kt)("h2",{id:"replicated-security"},"Replicated Security"),(0,n.kt)("p",null,'A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC. Note this documentation is focused on explaining the concepts from replicated security.'),(0,n.kt)("h2",{id:"mesh-security"},"Mesh security"),(0,n.kt)("p",null,"A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see ",(0,n.kt)("a",{parentName:"p",href:"https://informal.systems/blog/replicated-vs-mesh-security"},"Replicated vs. Mesh Security on the Informal Blog"),"."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/5f3b723a.67a2780a.js b/legacy/assets/js/5f3b723a.67a2780a.js new file mode 100644 index 0000000000..eef8d14da8 --- /dev/null +++ b/legacy/assets/js/5f3b723a.67a2780a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1585],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>g});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function l(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function o(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),d=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},p=function(e){var t=d(e.components);return n.createElement(c.Provider,{value:t},e.children)},s="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),s=d(r),m=a,g=s["".concat(c,".").concat(m)]||s[m]||u[m]||i;return r?n.createElement(g,l(l({ref:t},p),{},{components:r})):n.createElement(g,l({ref:t},p))}));function g(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,l=new Array(i);l[0]=m;var o={};for(var c in t)hasOwnProperty.call(t,c)&&(o[c]=t[c]);o.originalType=e,o[s]="string"==typeof e?e:a,l[1]=o;for(var d=2;d<i;d++)l[d]=r[d];return n.createElement.apply(null,l)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},3263:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>l,default:()=>u,frontMatter:()=>i,metadata:()=>o,toc:()=>d});var n=r(7462),a=(r(7294),r(3905));const i={sidebar_position:1,title:"ADRs"},l="Architecture Decision Records (ADR)",o={unversionedId:"adrs/intro",id:"version-v3.3.1-lsm/adrs/intro",title:"ADRs",description:"This is a location to record all high-level architecture decisions in the Interchain Security project.",source:"@site/versioned_docs/version-v3.3.1-lsm/adrs/intro.md",sourceDirName:"adrs",slug:"/adrs/intro",permalink:"/interchain-security/legacy/adrs/intro",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:1,frontMatter:{sidebar_position:1,title:"ADRs"},sidebar:"tutorialSidebar",previous:{title:"Frequently Asked Questions",permalink:"/interchain-security/legacy/faq"},next:{title:"ADR Template",permalink:"/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop"}},c={},d=[{value:"Table of Contents",id:"table-of-contents",level:2}],p={toc:d},s="wrapper";function u(e){let{components:t,...r}=e;return(0,a.kt)(s,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"architecture-decision-records-adr"},"Architecture Decision Records (ADR)"),(0,a.kt)("p",null,"This is a location to record all high-level architecture decisions in the Interchain Security project."),(0,a.kt)("p",null,"You can read more about the ADR concept in this ",(0,a.kt)("a",{parentName:"p",href:"https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0#.78xhdix6t"},"blog post"),"."),(0,a.kt)("p",null,"An ADR should provide:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Context on the relevant goals and the current state"),(0,a.kt)("li",{parentName:"ul"},"Proposed changes to achieve the goals"),(0,a.kt)("li",{parentName:"ul"},"Summary of pros and cons"),(0,a.kt)("li",{parentName:"ul"},"References"),(0,a.kt)("li",{parentName:"ul"},"Changelog")),(0,a.kt)("p",null,"Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and\njustification for a change in architecture, or for the architecture of something\nnew. The spec is much more compressed and streamlined summary of everything as\nit is or should be."),(0,a.kt)("p",null,"If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match."),(0,a.kt)("p",null,"Note the context/background should be written in the present tense."),(0,a.kt)("p",null,"To suggest an ADR, please make use of the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/adrs/adr-template"},"ADR template")," provided."),(0,a.kt)("h2",{id:"table-of-contents"},"Table of Contents"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"ADR ","#"),(0,a.kt)("th",{parentName:"tr",align:null},"Description"),(0,a.kt)("th",{parentName:"tr",align:null},"Status"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-001-key-assignment"},"001")),(0,a.kt)("td",{parentName:"tr",align:null},"Consumer chain key assignment"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-002-throttle"},"002")),(0,a.kt)("td",{parentName:"tr",align:null},"Jail Throttling"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposal"},"003")),(0,a.kt)("td",{parentName:"tr",align:null},"Equivocation governance proposal"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"./adr-004-denom-dos-fixes"},"004")),(0,a.kt)("td",{parentName:"tr",align:null},"Denom DOS fixes"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification"},"005")),(0,a.kt)("td",{parentName:"tr",align:null},"Cryptographic verification of equivocation evidence"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, In-progress")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop"},"007")),(0,a.kt)("td",{parentName:"tr",align:null},"Pause validator unbonding during equivocation proposal"),(0,a.kt)("td",{parentName:"tr",align:null},"Proposed")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-008-throttle-retries"},"008")),(0,a.kt)("td",{parentName:"tr",align:null},"Throttle with retries"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, In-progress")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-009-soft-opt-out"},"009")),(0,a.kt)("td",{parentName:"tr",align:null},"Soft Opt-out"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-010-standalone-changeover"},"010")),(0,a.kt)("td",{parentName:"tr",align:null},"Standalone to Consumer Changeover"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-011-improving-test-confidence"},"011")),(0,a.kt)("td",{parentName:"tr",align:null},"Improving testing and increasing confidence"),(0,a.kt)("td",{parentName:"tr",align:null},"Proposed")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-012-separate-releasing"},"012")),(0,a.kt)("td",{parentName:"tr",align:null},"Separate Releasing"),(0,a.kt)("td",{parentName:"tr",align:null},"Proposed")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-013-equivocation-slashing"},"013")),(0,a.kt)("td",{parentName:"tr",align:null},"Slashing on the provider for consumer equivocation"),(0,a.kt)("td",{parentName:"tr",align:null},"Proposed")))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/5fdaaf8d.eb3bafef.js b/legacy/assets/js/5fdaaf8d.eb3bafef.js new file mode 100644 index 0000000000..941c189350 --- /dev/null +++ b/legacy/assets/js/5fdaaf8d.eb3bafef.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5685],{3905:(e,r,t)=>{t.d(r,{Zo:()=>c,kt:()=>w});var a=t(7294);function n(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);r&&(a=a.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?i(Object(t),!0).forEach((function(r){n(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function s(e,r){if(null==e)return{};var t,a,n=function(e,r){if(null==e)return{};var t,a,n={},i=Object.keys(e);for(a=0;a<i.length;a++)t=i[a],r.indexOf(t)>=0||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)t=i[a],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(n[t]=e[t])}return n}var l=a.createContext({}),d=function(e){var r=a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):o(o({},r),e)),t},c=function(e){var r=d(e.components);return a.createElement(l.Provider,{value:r},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var r=e.children;return a.createElement(a.Fragment,{},r)}},u=a.forwardRef((function(e,r){var t=e.components,n=e.mdxType,i=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=d(t),u=n,w=p["".concat(l,".").concat(u)]||p[u]||m[u]||i;return t?a.createElement(w,o(o({ref:r},c),{},{components:t})):a.createElement(w,o({ref:r},c))}));function w(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var i=t.length,o=new Array(i);o[0]=u;var s={};for(var l in r)hasOwnProperty.call(r,l)&&(s[l]=r[l]);s.originalType=e,s[p]="string"==typeof e?e:n,o[1]=s;for(var d=2;d<i;d++)o[d]=t[d];return a.createElement.apply(null,o)}return a.createElement.apply(null,t)}u.displayName="MDXCreateElement"},6896:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>l,contentTitle:()=>o,default:()=>m,frontMatter:()=>i,metadata:()=>s,toc:()=>d});var a=t(7462),n=(t(7294),t(3905));const i={sidebar_position:3},o="Withdrawing consumer chain validator rewards",s={unversionedId:"validators/withdraw_rewards",id:"version-v3.2.0/validators/withdraw_rewards",title:"Withdrawing consumer chain validator rewards",description:"Here are example steps for withdrawing rewards from consumer chains in the provider chain",source:"@site/versioned_docs/version-v3.2.0/validators/withdraw_rewards.md",sourceDirName:"validators",slug:"/validators/withdraw_rewards",permalink:"/interchain-security/legacy/v3.2.0/validators/withdraw_rewards",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Joining Replicated Security testnet",permalink:"/interchain-security/legacy/v3.2.0/validators/joining-testnet"},next:{title:"Validator instructions for Changeover Procedure",permalink:"/interchain-security/legacy/v3.2.0/validators/changeover-procedure"}},l={},d=[{value:"Querying validator rewards",id:"querying-validator-rewards",level:2},{value:"Withdrawing rewards and commission",id:"withdrawing-rewards-and-commission",level:2},{value:"1. Withdraw rewards",id:"1-withdraw-rewards",level:3},{value:"2. Confirm withdrawal",id:"2-confirm-withdrawal",level:3}],c={toc:d},p="wrapper";function m(e){let{components:r,...t}=e;return(0,n.kt)(p,(0,a.Z)({},c,t,{components:r,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"withdrawing-consumer-chain-validator-rewards"},"Withdrawing consumer chain validator rewards"),(0,n.kt)("p",null,"Here are example steps for withdrawing rewards from consumer chains in the provider chain"),(0,n.kt)("admonition",{type:"info"},(0,n.kt)("p",{parentName:"admonition"},"The examples used are from ",(0,n.kt)("inlineCode",{parentName:"p"},"rs-testnet"),", the replicated security persistent testnet."),(0,n.kt)("p",{parentName:"admonition"},"Validator operator address: ",(0,n.kt)("inlineCode",{parentName:"p"},"cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6"),"\nSelf-delegation address: ",(0,n.kt)("inlineCode",{parentName:"p"},"cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf"))),(0,n.kt)("p",null,"Prior to withdrawing rewards, query balances for self-delegation address:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "1000000000000"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n')),(0,n.kt)("h2",{id:"querying-validator-rewards"},"Querying validator rewards"),(0,n.kt)("p",null,"Query rewards for the validator address:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6\n\nrewards:\n- amount: "158.069895000000000000"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "841842390516.072526500000000000"\n denom: uatom\n')),(0,n.kt)("p",null,"The ",(0,n.kt)("inlineCode",{parentName:"p"},"ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD")," denom represents rewards from a consumer chain."),(0,n.kt)("h2",{id:"withdrawing-rewards-and-commission"},"Withdrawing rewards and commission"),(0,n.kt)("h3",{id:"1-withdraw-rewards"},"1. Withdraw rewards"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y\n\ntxhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A\n")),(0,n.kt)("h3",{id:"2-confirm-withdrawal"},"2. Confirm withdrawal"),(0,n.kt)("p",null,"After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "216"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "2233766225342"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/609d3cd8.d053c91e.js b/legacy/assets/js/609d3cd8.d053c91e.js new file mode 100644 index 0000000000..6e914b8e74 --- /dev/null +++ b/legacy/assets/js/609d3cd8.d053c91e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4675],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=l(n),u=i,h=d["".concat(c,".").concat(u)]||d[u]||m[u]||o;return n?a.createElement(h,r(r({ref:t},p),{},{components:n})):a.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=u;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:i,r[1]=s;for(var l=2;l<o;l++)r[l]=n[l];return a.createElement.apply(null,r)}return a.createElement.apply(null,n)}u.displayName="MDXCreateElement"},4635:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>m,frontMatter:()=>o,metadata:()=>s,toc:()=>l});var a=n(7462),i=(n(7294),n(3905));const o={sidebar_position:3,title:"Onboarding Checklist"},r="Consumer Onboarding Checklist",s={unversionedId:"consumer-development/onboarding",id:"version-v3.3.1-lsm/consumer-development/onboarding",title:"Onboarding Checklist",description:"The following checklists will aid in onboarding a new consumer chain to replicated security.",source:"@site/versioned_docs/version-v3.3.1-lsm/consumer-development/onboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/onboarding",permalink:"/interchain-security/legacy/consumer-development/onboarding",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Onboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Consumer Chain Governance",permalink:"/interchain-security/legacy/consumer-development/consumer-chain-governance"},next:{title:"Offboarding Checklist",permalink:"/interchain-security/legacy/consumer-development/offboarding"}},c={},l=[{value:"1. Complete testing & integration",id:"1-complete-testing--integration",level:2},{value:"2. Create an Onboarding Repository",id:"2-create-an-onboarding-repository",level:2},{value:"3. Submit a Governance Proposal",id:"3-submit-a-governance-proposal",level:2},{value:"4. Launch",id:"4-launch",level:2}],p={toc:l},d="wrapper";function m(e){let{components:t,...n}=e;return(0,i.kt)(d,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"consumer-onboarding-checklist"},"Consumer Onboarding Checklist"),(0,i.kt)("p",null,"The following checklists will aid in onboarding a new consumer chain to replicated security."),(0,i.kt)("p",null,"Additionally, you can check the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md"},"testnet repo")," for a comprehensive guide on preparing and launching consumer chains."),(0,i.kt)("h2",{id:"1-complete-testing--integration"},"1. Complete testing & integration"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test integration with gaia"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test your protocol with supported relayer versions (minimum hermes 1.4.1)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","reach out to the ICS team if you are facing issues")),(0,i.kt)("h2",{id:"2-create-an-onboarding-repository"},"2. Create an Onboarding Repository"),(0,i.kt)("p",null,"To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain."),(0,i.kt)("p",null,"This should include (at minimum):"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json without CCV data (before the proposal passes)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see ",(0,i.kt)("a",{parentName:"li",href:"/interchain-security/legacy/consumer-development/consumer-genesis-transformation"},"Transform Consumer Genesis"),")"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","information about relevant seed/peer nodes you are running"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","relayer information (compatible versions)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","copy of your governance proposal (as JSON)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","a script showing how to start your chain and connect to peers (optional)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable")),(0,i.kt)("p",null,"Example of such a repository can be found ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyphacoop/ics-testnets/tree/main/game-of-chains-2022/sputnik"},"here"),"."),(0,i.kt)("h2",{id:"3-submit-a-governance-proposal"},"3. Submit a Governance Proposal"),(0,i.kt)("p",null,"Before you submit a ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerChainAddition")," proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch.\nIf possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues."),(0,i.kt)("p",null,"Additionally, reach out to the community via the ",(0,i.kt)("a",{parentName:"p",href:"https://forum.cosmos.network/"},"forum")," to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine your chain's spawn time"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine consumer chain parameters to be put in the proposal"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take note to include a link to your onboarding repository"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","describe the purpose and benefits of running your chain")),(0,i.kt)("p",null,"Example of a consumer chain addition proposal."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},'// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.\n// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.\n// It is recommended that spawn time occurs after the proposal end time.\n{\n // Title of the proposal\n "title": "Add consumer chain",\n // Description of the proposal\n // format the text as a .md file and include the file in your onboarding repository\n "description": ".md description of your chain and all other relevant information",\n // Proposed chain-id of the new consumer chain.\n // Must be unique from all other consumer chain ids of the executing provider chain.\n "chain_id": "newchain-1",\n // Initial height of new consumer chain.\n // For a completely new chain, this will be {0,1}.\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Hash of the consumer chain genesis state without the consumer CCV module genesis params.\n // It is used for off-chain confirmation of genesis.json validity by validators and other parties.\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n // Hash of the consumer chain binary that should be run by validators on chain initialization.\n // It is used for off-chain confirmation of binary validity by validators and other parties.\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n // Unbonding period for the consumer chain.\n // It should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n // IBC transfer packets will timeout after this interval elapses.\n "transfer_timeout_period": 1800000000000,\n // The fraction of tokens allocated to the consumer redistribution address during distribution events.\n // The fraction is a string representing a decimal number. For example "0.75" would represent 75%.\n // The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.\n "consumer_redistribution_fraction": "0.75",\n // BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.\n // eg. send rewards to the provider every 1000 blocks\n "blocks_per_distribution_transmission": 1000,\n // The number of historical info entries to persist in store.\n // This param is a part of the cosmos sdk staking module. In the case of\n // a ccv enabled consumer chain, the ccv module acts as the staking module.\n "historical_entries": 10000,\n // The ID of a token transfer channel used for the Reward Distribution\n // sub-protocol. If DistributionTransmissionChannel == "", a new transfer\n // channel is created on top of the same connection as the CCV channel.\n // Note that transfer_channel_id is the ID of the channel end on the consumer chain.\n // it is most relevant for chains performing a sovereign to consumer changeover\n // in order to maintain the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123"\n}\n')),(0,i.kt)("h2",{id:"4-launch"},"4. Launch"),(0,i.kt)("p",null,"The consumer chain starts after at least 66.67% of all provider's voting power comes online. The consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","provide a repo with onboarding instructions for validators (it should already be listed in the proposal)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json with ccv data populated (MUST contain the initial validator set)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","have a block explorer in place to track chain activity & health")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/62a5ef54.698335d4.js b/legacy/assets/js/62a5ef54.698335d4.js new file mode 100644 index 0000000000..7fd891b4c0 --- /dev/null +++ b/legacy/assets/js/62a5ef54.698335d4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6501],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var i=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,i,r=function(e,t){if(null==e)return{};var n,i,r={},o=Object.keys(e);for(i=0;i<o.length;i++)n=o[i],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i<o.length;i++)n=o[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=i.createContext({}),d=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=d(e.components);return i.createElement(l.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},m=i.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),c=d(n),m=r,h=c["".concat(l,".").concat(m)]||c[m]||u[m]||o;return n?i.createElement(h,a(a({ref:t},p),{},{components:n})):i.createElement(h,a({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,a=new Array(o);a[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:r,a[1]=s;for(var d=2;d<o;d++)a[d]=n[d];return i.createElement.apply(null,a)}return i.createElement.apply(null,n)}m.displayName="MDXCreateElement"},5242:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var i=n(7462),r=(n(7294),n(3905));const o={sidebar_position:3},a="Interchain Security Parameters",s={unversionedId:"introduction/params",id:"version-v3.2.0/introduction/params",title:"Interchain Security Parameters",description:"The parameters necessary for Interchain Security (ICS) are defined in",source:"@site/versioned_docs/version-v3.2.0/introduction/params.md",sourceDirName:"introduction",slug:"/introduction/params",permalink:"/interchain-security/legacy/v3.2.0/introduction/params",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Terminology",permalink:"/interchain-security/legacy/v3.2.0/introduction/terminology"},next:{title:"Technical Specification",permalink:"/interchain-security/legacy/v3.2.0/introduction/technical-specification"}},l={},d=[{value:"Time-based parameters",id:"time-based-parameters",level:2},{value:"ProviderUnbondingPeriod",id:"providerunbondingperiod",level:3},{value:"ConsumerUnbondingPeriod",id:"consumerunbondingperiod",level:3},{value:"TrustingPeriodFraction",id:"trustingperiodfraction",level:3},{value:"CCVTimeoutPeriod",id:"ccvtimeoutperiod",level:3},{value:"InitTimeoutPeriod",id:"inittimeoutperiod",level:3},{value:"<code>VscTimeoutPeriod</code>",id:"vsctimeoutperiod",level:3},{value:"BlocksPerDistributionTransmission",id:"blocksperdistributiontransmission",level:3},{value:"TransferPeriodTimeout",id:"transferperiodtimeout",level:3},{value:"Slash Throttle Parameters",id:"slash-throttle-parameters",level:2},{value:"SlashMeterReplenishPeriod",id:"slashmeterreplenishperiod",level:3},{value:"SlashMeterReplenishFraction",id:"slashmeterreplenishfraction",level:3},{value:"MaxThrottledPackets",id:"maxthrottledpackets",level:3}],p={toc:d},c="wrapper";function u(e){let{components:t,...n}=e;return(0,r.kt)(c,(0,i.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"interchain-security-parameters"},"Interchain Security Parameters"),(0,r.kt)("p",null,"The parameters necessary for Interchain Security (ICS) are defined in "),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"the ",(0,r.kt)("inlineCode",{parentName:"li"},"Params")," structure in ",(0,r.kt)("inlineCode",{parentName:"li"},"proto/interchain_security/ccv/provider/v1/provider.proto")," for the provider;"),(0,r.kt)("li",{parentName:"ul"},"the ",(0,r.kt)("inlineCode",{parentName:"li"},"Params")," structure in ",(0,r.kt)("inlineCode",{parentName:"li"},"proto/interchain_security/ccv/consumer/v1/consumer.proto")," for the consumer.")),(0,r.kt)("h2",{id:"time-based-parameters"},"Time-based parameters"),(0,r.kt)("p",null,"ICS relies on the following time-based parameters."),(0,r.kt)("h3",{id:"providerunbondingperiod"},"ProviderUnbondingPeriod"),(0,r.kt)("p",null,"is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance."),(0,r.kt)("h3",{id:"consumerunbondingperiod"},"ConsumerUnbondingPeriod"),(0,r.kt)("p",null,"is the unbonding period on the consumer chain."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerUnbondingPeriod")," is set via the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," governance proposal to add a new consumer chain.\nIt is recommended that every consumer chain set and unbonding period shorter than ",(0,r.kt)("inlineCode",{parentName:"p"},"ProviderUnbondingPeriod")),(0,r.kt)("br",null),(0,r.kt)("p",{parentName:"admonition"},"Example:"),(0,r.kt)("pre",{parentName:"admonition"},(0,r.kt)("code",{parentName:"pre"},"ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day\n"))),(0,r.kt)("p",null,"Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer."),(0,r.kt)("h3",{id:"trustingperiodfraction"},"TrustingPeriodFraction"),(0,r.kt)("p",null,"is used to calculate the ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriod")," of created IBC clients on both provider and consumer chains. "),(0,r.kt)("p",null,"Setting ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriodFraction")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"0.5")," would result in the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"TrustingPeriodFraction = 0.5\nProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5\nConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5\n")),(0,r.kt)("p",null,"Note that a light clients must be updated within the ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriod")," in order to avoid being frozen."),(0,r.kt)("p",null,"For more details, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/client/ics-007-tendermint-client/README.md"},"IBC specification of Tendermint clients"),"."),(0,r.kt)("h3",{id:"ccvtimeoutperiod"},"CCVTimeoutPeriod"),(0,r.kt)("p",null,"is the period used to compute the timeout timestamp when sending IBC packets. "),(0,r.kt)("p",null,"For more details, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/core/ics-004-channel-and-packet-semantics/README.md#sending-packets"},"IBC specification of Channel & Packet Semantics"),"."),(0,r.kt)("admonition",{type:"warning"},(0,r.kt)("p",{parentName:"admonition"},"If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed.")),(0,r.kt)("p",null,"CCVTimeoutPeriod may have different values on the provider and consumer chains."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"CCVTimeoutPeriod")," on the provider ",(0,r.kt)("strong",{parentName:"li"},"must")," be larger than ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerUnbondingPeriod")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"CCVTimeoutPeriod")," on the consumer is initial set via the ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal"))),(0,r.kt)("h3",{id:"inittimeoutperiod"},"InitTimeoutPeriod"),(0,r.kt)("p",null,"is the maximum allowed duration for CCV channel initialization to execute."),(0,r.kt)("p",null,"For any consumer chain, if the CCV channel is not established within ",(0,r.kt)("inlineCode",{parentName:"p"},"InitTimeoutPeriod")," then the consumer chain will be removed and therefore will not be secured by the provider chain."),(0,r.kt)("p",null,"The countdown starts when the ",(0,r.kt)("inlineCode",{parentName:"p"},"spawn_time")," specified in the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," is reached."),(0,r.kt)("h3",{id:"vsctimeoutperiod"},(0,r.kt)("inlineCode",{parentName:"h3"},"VscTimeoutPeriod")),(0,r.kt)("p",null,"is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live.\nIf the ",(0,r.kt)("inlineCode",{parentName:"p"},"VscTimeoutPeriod")," is ever reached for a consumer chain that chain will be considered not live and removed from interchain security."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"VscTimeoutPeriod")," MUST be larger than the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerUnbondingPeriod"),".")),(0,r.kt)("h3",{id:"blocksperdistributiontransmission"},"BlocksPerDistributionTransmission"),(0,r.kt)("p",null,"is the number of blocks between rewards transfers from the consumer to the provider."),(0,r.kt)("h3",{id:"transferperiodtimeout"},"TransferPeriodTimeout"),(0,r.kt)("p",null,"is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider."),(0,r.kt)("p",null,"If this timeout expires, then the transfer is attempted again after ",(0,r.kt)("inlineCode",{parentName:"p"},"BlocksPerDistributionTransmission")," blocks."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"TransferPeriodTimeout")," on the consumer is initial set via the ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal")," gov proposal to add the consumer"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"TransferPeriodTimeout")," should be smaller than ",(0,r.kt)("inlineCode",{parentName:"li"},"BlocksPerDistributionTransmission x avg_block_time"))),(0,r.kt)("h2",{id:"slash-throttle-parameters"},"Slash Throttle Parameters"),(0,r.kt)("h3",{id:"slashmeterreplenishperiod"},"SlashMeterReplenishPeriod"),(0,r.kt)("p",null,"exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed."),(0,r.kt)("p",null,"The meter is replenished to an amount equal to the slash meter allowance for that block, or ",(0,r.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction * CurrentTotalVotingPower"),"."),(0,r.kt)("h3",{id:"slashmeterreplenishfraction"},"SlashMeterReplenishFraction"),(0,r.kt)("p",null,"exists on the provider as the portion (in range ","[0, 1]",") of total voting power that is replenished to the slash meter when a replenishment occurs."),(0,r.kt)("p",null,"This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a ",(0,r.kt)("inlineCode",{parentName:"p"},"sdk.Dec")," when used."),(0,r.kt)("h3",{id:"maxthrottledpackets"},"MaxThrottledPackets"),(0,r.kt)("p",null,"exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value."),(0,r.kt)("p",null,"This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/6441912e.ca22e873.js b/legacy/assets/js/6441912e.ca22e873.js new file mode 100644 index 0000000000..481c3f2a7c --- /dev/null +++ b/legacy/assets/js/6441912e.ca22e873.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1849],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),c=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),m=a,h=u["".concat(l,".").concat(m)]||u[m]||d[m]||i;return n?o.createElement(h,r(r({ref:t},p),{},{components:n})):o.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,r=new Array(i);r[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,r[1]=s;for(var c=2;c<i;c++)r[c]=n[c];return o.createElement.apply(null,r)}return o.createElement.apply(null,n)}m.displayName="MDXCreateElement"},3170:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var o=n(7462),a=(n(7294),n(3905));const i={sidebar_position:4,title:"Equivocation governance proposal"},r="ADR 003: Equivocation governance proposal",s={unversionedId:"adrs/adr-003-equivocation-gov-proposal",id:"version-v2.0.0/adrs/adr-003-equivocation-gov-proposal",title:"Equivocation governance proposal",description:"Changelog",source:"@site/versioned_docs/version-v2.0.0/adrs/adr-003-equivocation-gov-proposal.md",sourceDirName:"adrs",slug:"/adrs/adr-003-equivocation-gov-proposal",permalink:"/interchain-security/legacy/v2.0.0/adrs/adr-003-equivocation-gov-proposal",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Equivocation governance proposal"},sidebar:"tutorialSidebar",previous:{title:"Jail Throttling",permalink:"/interchain-security/legacy/v2.0.0/adrs/adr-002-throttle"}},l={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],p={toc:c},u="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-003-equivocation-governance-proposal"},"ADR 003: Equivocation governance proposal"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"2023-02-06: Initial draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain."),(0,a.kt)("p",null,"For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain."),(0,a.kt)("p",null,"A new kind of governance proposal is added to the ",(0,a.kt)("inlineCode",{parentName:"p"},"provider")," module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain."),(0,a.kt)("p",null,"If such proposal passes, the proposal handler delegates to the ",(0,a.kt)("inlineCode",{parentName:"p"},"evidence")," module to process the equivocation. This module ensures the evidence isn\u2019t too old, or else ignores it (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/21021b837882d1d40f1d79bcbc4fad2e79a3fefe/x/evidence/keeper/infraction.go#L54-L62"},"code"),"). ",(0,a.kt)("em",{parentName:"p"},"Too old")," is determined by 2 consensus params : "),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"evidence.max_age_duration")," number of nanoseconds before an evidence is considered too old"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"evidence.max_age_numblocks")," number of blocks before an evidence is considered too old.")),(0,a.kt)("p",null,"On the hub, those parameters are equals to "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682\n(...)\n"evidence": {\n "max_age_num_blocks": "1000000",\n "max_age_duration": "172800000000000",\n (...)\n},\n(...)\n')),(0,a.kt)("p",null,"A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the ",(0,a.kt)("inlineCode",{parentName:"p"},"evidence")," module when the proposal passes and is handled by the hub."),(0,a.kt)("p",null,"For ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks=1M"),", the parameter is big enough if we consider the hub produces 12k blocks per day (",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_year/365 = 436,0000/365"),"). The evidence can be up to 83 days old (",(0,a.kt)("inlineCode",{parentName:"p"},"1,000,000/12,000"),") and not be ignored."),(0,a.kt)("p",null,"For ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_duration=172,800,000,000,000"),", the parameter is too low, because the value is in nanoseconds so it\u2019s 2 days. Fortunately the condition that checks those 2 parameters uses a ",(0,a.kt)("strong",{parentName:"p"},"AND"),", so if ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks")," condition passes, the evidence won\u2019t be ignored."),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Remove the possibility from a malicious consumer chain to \u201cattack\u201d the provider chain by slashing/jailing validators."),(0,a.kt)("li",{parentName:"ul"},"Provide a more acceptable implementation for the validator community.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Punishment action of double-signing isn\u2019t \u201cautomated\u201d, a governance proposal is required which takes more time."),(0,a.kt)("li",{parentName:"ul"},"You need to pay 250ATOM to submit an equivocation evidence.")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"PR that ignores non downtime slash packet : ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/692"},"https://github.com/cosmos/interchain-security/pull/692")),(0,a.kt)("li",{parentName:"ul"},"PR that adds the governance slash proposal: ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/703"},"https://github.com/cosmos/interchain-security/pull/703"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/65076e0d.34ce332b.js b/legacy/assets/js/65076e0d.34ce332b.js new file mode 100644 index 0000000000..d023389d97 --- /dev/null +++ b/legacy/assets/js/65076e0d.34ce332b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2589],{3905:(e,n,t)=>{t.d(n,{Zo:()=>m,kt:()=>d});var r=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function c(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function i(e,n){if(null==e)return{};var t,r,o=function(e,n){if(null==e)return{};var t,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var s=r.createContext({}),l=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):c(c({},n),e)),t},m=function(e){var n=l(e.components);return r.createElement(s.Provider,{value:n},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},p=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,m=i(e,["components","mdxType","originalType","parentName"]),u=l(t),p=o,d=u["".concat(s,".").concat(p)]||u[p]||h[p]||a;return t?r.createElement(d,c(c({ref:n},m),{},{components:t})):r.createElement(d,c({ref:n},m))}));function d(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,c=new Array(a);c[0]=p;var i={};for(var s in n)hasOwnProperty.call(n,s)&&(i[s]=n[s]);i.originalType=e,i[u]="string"==typeof e?e:o,c[1]=i;for(var l=2;l<a;l++)c[l]=t[l];return r.createElement.apply(null,c)}return r.createElement.apply(null,t)}p.displayName="MDXCreateElement"},5603:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>c,default:()=>h,frontMatter:()=>a,metadata:()=>i,toc:()=>l});var r=t(7462),o=(t(7294),t(3905));const a={sidebar_position:2},c="Consumer Chain Governance",i={unversionedId:"consumer-development/consumer-chain-governance",id:"version-v2.4.0-lsm/consumer-development/consumer-chain-governance",title:"Consumer Chain Governance",description:'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.',source:"@site/versioned_docs/version-v2.4.0-lsm/consumer-development/consumer-chain-governance.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-chain-governance",permalink:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/consumer-chain-governance",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/app-integration"},next:{title:"Upgrading Consumer Chains",permalink:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/consumer-chain-upgrade-procedure"}},s={},l=[{value:"Democracy module",id:"democracy-module",level:2},{value:"CosmWasm",id:"cosmwasm",level:2},{value:"The Whitelist",id:"the-whitelist",level:2}],m={toc:l},u="wrapper";function h(e){let{components:n,...t}=e;return(0,o.kt)(u,(0,r.Z)({},m,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-chain-governance"},"Consumer Chain Governance"),(0,o.kt)("p",null,'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.'),(0,o.kt)("h2",{id:"democracy-module"},"Democracy module"),(0,o.kt)("p",null,"The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy."),(0,o.kt)("p",null,"Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus."),(0,o.kt)("p",null,"For an example, see the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy"},"Democracy Consumer")),(0,o.kt)("h2",{id:"cosmwasm"},"CosmWasm"),(0,o.kt)("p",null,"There several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain."),(0,o.kt)("p",null,"For an example, see ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/neutron-org/neutron/"},"Neutron"),"."),(0,o.kt)("h2",{id:"the-whitelist"},"The Whitelist"),(0,o.kt)("p",null,"Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/neutron-org/neutron/blob/main/app/proposals_allowlisting.go"},"Neutron's")," whitelist."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/665374cc.fbe2de3b.js b/legacy/assets/js/665374cc.fbe2de3b.js new file mode 100644 index 0000000000..b381ef8142 --- /dev/null +++ b/legacy/assets/js/665374cc.fbe2de3b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2384],{3905:(e,t,i)=>{i.d(t,{Zo:()=>h,kt:()=>m});var n=i(7294);function a(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}function o(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function s(e){for(var t=1;t<arguments.length;t++){var i=null!=arguments[t]?arguments[t]:{};t%2?o(Object(i),!0).forEach((function(t){a(e,t,i[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(i)):o(Object(i)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(i,t))}))}return e}function r(e,t){if(null==e)return{};var i,n,a=function(e,t){if(null==e)return{};var i,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)i=o[n],t.indexOf(i)>=0||(a[i]=e[i]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)i=o[n],t.indexOf(i)>=0||Object.prototype.propertyIsEnumerable.call(e,i)&&(a[i]=e[i])}return a}var c=n.createContext({}),l=function(e){var t=n.useContext(c),i=t;return e&&(i="function"==typeof e?e(t):s(s({},t),e)),i},h=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var i=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,h=r(e,["components","mdxType","originalType","parentName"]),d=l(i),p=a,m=d["".concat(c,".").concat(p)]||d[p]||u[p]||o;return i?n.createElement(m,s(s({ref:t},h),{},{components:i})):n.createElement(m,s({ref:t},h))}));function m(e,t){var i=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=i.length,s=new Array(o);s[0]=p;var r={};for(var c in t)hasOwnProperty.call(t,c)&&(r[c]=t[c]);r.originalType=e,r[d]="string"==typeof e?e:a,s[1]=r;for(var l=2;l<o;l++)s[l]=i[l];return n.createElement.apply(null,s)}return n.createElement.apply(null,i)}p.displayName="MDXCreateElement"},6741:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>u,frontMatter:()=>o,metadata:()=>r,toc:()=>l});var n=i(7462),a=(i(7294),i(3905));const o={sidebar_position:4,title:"Cryptographic verification of equivocation evidence"},s="ADR 005: Cryptographic verification of equivocation evidence",r={unversionedId:"adrs/adr-005-cryptographic-equivocation-verification",id:"version-v3.3.1-lsm/adrs/adr-005-cryptographic-equivocation-verification",title:"Cryptographic verification of equivocation evidence",description:"Changelog",source:"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-005-cryptographic-equivocation-verification.md",sourceDirName:"adrs",slug:"/adrs/adr-005-cryptographic-equivocation-verification",permalink:"/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Cryptographic verification of equivocation evidence"},sidebar:"tutorialSidebar",previous:{title:"Equivocation governance proposal",permalink:"/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposal"},next:{title:"Throttle with retries",permalink:"/interchain-security/legacy/adrs/adr-008-throttle-retries"}},c={},l=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Light Client Attack",id:"light-client-attack",level:3},{value:"Double Signing Attack",id:"double-signing-attack",level:3},{value:"Decision",id:"decision",level:2},{value:"Light Client Attack",id:"light-client-attack-1",level:3},{value:"Double Signing Attack",id:"double-signing-attack-1",level:3},{value:"Current limitations:",id:"current-limitations",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}],h={toc:l},d="wrapper";function u(e){let{components:t,...i}=e;return(0,a.kt)(d,(0,n.Z)({},h,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-005-cryptographic-verification-of-equivocation-evidence"},"ADR 005: Cryptographic verification of equivocation evidence"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"5/1/2023: First draft"),(0,a.kt)("li",{parentName:"ul"},"7/23/2023: Add light client attacks handling"),(0,a.kt)("li",{parentName:"ul"},"9/6/2023: Add double signing attacks handling"),(0,a.kt)("li",{parentName:"ul"},"11/3/2023: Update limitations to clarify amnesia attacks are ignored")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"Currently, we use a governance proposal to slash validators for equivocation (double signing and light client attacks).\nEvery proposal needs to go through a (two weeks) voting period before it can be approved.\nGiven a three-week unbonding period, this means that an equivocation proposal needs to be submitted within one week since the infraction occurred."),(0,a.kt)("p",null,"This ADR proposes a system to slash validators automatically for equivocation, immediately upon the provider chain's receipt of the evidence. Another thing to note is that we intend to introduce this system in stages, since even the partial ability to slash and/or tombstone is a strict improvement in security.\nThe feature is implemented in two parts, each with its dedicated endpoint. One endpoint handles light client attacks, while the other handles double signing attacks."),(0,a.kt)("h3",{id:"light-client-attack"},"Light Client Attack"),(0,a.kt)("p",null,"In a nutshell, the light client is a process that solely verifies a specific state machine's\nconsensus without executing the transactions. The light clients get new headers by querying\nmultiple nodes, called primary and witness nodes."),(0,a.kt)("p",null,"Light clients download new headers committed on chain from a primary. Headers can be verified in two ways: sequentially,\nwhere the block height of headers is serial, or using skipping. This second verification method allows light clients to download headers\nwith nonconsecutive block height, where some intermediate headers are skipped (see ",(0,a.kt)("a",{parentName:"p",href:"https://arxiv.org/pdf/2010.07031.pdf"},"Tendermint Light Client, Figure 1 and Figure 3"),").\nAdditionally, light clients are cross-checking new headers obtained from a primary with witnesses to ensure all nodes share the same state."),(0,a.kt)("p",null,"A light client attack occurs when a Byzantine validator sends invalid headers to a light client.\nAs the light client doesn't execute transactions, it can be deceived into trusting corrupted application state transitions.\nFor instance, if a light client receives header ",(0,a.kt)("inlineCode",{parentName:"p"},"A")," from the primary and header ",(0,a.kt)("inlineCode",{parentName:"p"},"B")," from a witness for the same block height ",(0,a.kt)("inlineCode",{parentName:"p"},"H"),",\nand both headers are successfully verified, it indicates a light client attack.\nNote that in this case, either the primary or the witness or both are malicious."),(0,a.kt)("p",null,"The types of light client attacks are defined by analyzing the differences between the conflicting headers.\nThere are three types of light client attacks: lunatic attack, equivocation attack, and amnesia attack.\nFor details, see the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/main/spec/light-client/attacks/notes-on-evidence-handling.md#evidence-handling"},"CometBFT specification"),"."),(0,a.kt)("p",null,"When a light client agent detects two conflicting headers, it will initially verify their traces (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/light/detector.go#L28"},"cometBFT detector"),") using its primary and witness nodes.\nIf these headers pass successful verification, the Byzantine validators will be identified based on the header's commit signatures\nand the type of light client attack. The agent will then transmit this information to its nodes using a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#light-client-attacks"},(0,a.kt)("inlineCode",{parentName:"a"},"LightClientAttackEvidence"))," evidence to be eventually voted on and added to a block.\nNote that from a light client agent perspective, it is not possible to establish whether a primary or a witness node, or both, are malicious.\nTherefore, it will create and send two evidences: one against the primary (sent to the witness), and one against the witness (sent to the primary).\nBoth nodes will then verify it before broadcasting it and adding it to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/evidence/pool.go#L28"},"evidence pool"),".\nIf an evidence is finally committed to a block, the chain's evidence module will execute it, resulting in the jailing and the slashing of the validators responsible for the light client attack."),(0,a.kt)("p",null,"Light clients are a core component of IBC. In the event of a light client attack, IBC relayers notify the affected chains by submitting an ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/v4.4.2/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79"},"IBC misbehavior message"),".\nA misbehavior message includes the conflicting headers that constitute a light client attack evidence. Upon receiving such a message,\na chain will first verify whether these headers would have convinced its light client. This verification is achieved by checking\nthe header states against the light client consensus states (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/v4.4.2/modules/light-clients/07-tendermint/types/misbehaviour_handle.go#L24"},"IBC misbehaviour handler"),'). If the misbehaviour is successfully verified, the chain will then "freeze" the\nlight client, halting any further trust in or updating of its states.'),(0,a.kt)("h3",{id:"double-signing-attack"},"Double Signing Attack"),(0,a.kt)("p",null,"A double signing attack, also known as equivocation,\noccurs when a validator votes for two different blocks in the same round of the CometBFT consensus.\nThis consensus mechanism operates with multiple voting rounds at each block height,\nand it strictly prohibits sending two votes of the same type during a round\n(see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/consensus.md#state-machine-overview"},"CometBFT State Machine Overview"),")."),(0,a.kt)("p",null,"When a node observes two votes from the same peer, it will use these two votes to create\na ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/types/evidence.go#L35"},(0,a.kt)("inlineCode",{parentName:"a"},"DuplicateVoteEvidence")),"\nevidence and gossip it to the other nodes in the network\n(see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#detection"},"CometBFT equivocation detection"),").\nEach node will then verify the evidence according to the CometBFT rules that define a valid double signing infraction, and based on this verification, they will decide whether to add the evidence to a block.\nDuring the evidence verification process, the signatures of the conflicting votes must be verified successfully.\nNote that this is achieved using the public key of the misbehaving validator, along with the chain ID of the chain where the infraction occurred (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#verification"},"CometBFT equivocation verification"),")."),(0,a.kt)("p",null,"Once a double signing evidence is committed to a block, the consensus layer will report the equivocation to the evidence module of the Cosmos SDK application layer.\nThe application will, in turn, punish the malicious validator through jailing, tombstoning and slashing\n(see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/evidence/keeper/infraction.go#L263"},"handleEquivocationEvidence"),")."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("h3",{id:"light-client-attack-1"},"Light Client Attack"),(0,a.kt)("p",null,"In the first part of the feature, we introduce a new endpoint: ",(0,a.kt)("inlineCode",{parentName:"p"},"HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour)"),".\nThe main idea is to leverage the current IBC misbehaviour handling and update it to solely jail and slash the validators that\nperformed a light client attack. Note that in this context, we assume that chains connected via a light client\nshare the same validator set, as is the case with Replicated Security."),(0,a.kt)("p",null,"This endpoint reuses the IBC client libraries to verify that the misbehaviour headers would have fooled the light client.\nAdditionally, it\u2019s crucial that the endpoint logic results in the slashing and jailing of validators under the same conditions\nas a light client agent detector. Therefore, the endpoint ensures that the two conditions are met:\nthe headers in the misbehaviour message have the same block height, and\nthe light client isn\u2019t expired."),(0,a.kt)("p",null,"After having successfully verified a misbehaviour, the endpoint executes the jailing and slashing of the malicious validators similarly as in the evidence module."),(0,a.kt)("h3",{id:"double-signing-attack-1"},"Double Signing Attack"),(0,a.kt)("p",null,"In the second part of the feature, we introduce a new endpoint ",(0,a.kt)("inlineCode",{parentName:"p"},"HandleConsumerDoubleVoting(\nctx sdk.Context, evidence *tmtypes.DuplicateVoteEvidence, chainID string, pubkey cryptotypes.PubKey)"),".\nSimply put, the handling logic verifies a double signing evidence against a provided\npublic key and chain ID and, if successful, executes the jailing of the malicious validator who double voted."),(0,a.kt)("p",null,"We define a new\n",(0,a.kt)("inlineCode",{parentName:"p"},"MsgSubmitConsumerDoubleVoting")," message to report a double voting evidence observed\non a consumer chain to the endpoint of the provider chain. This message contains two fields:\na double signing evidence\n",(0,a.kt)("inlineCode",{parentName:"p"},"duplicate_vote_evidence")," and a light client header for the infraction block height,\nreferred to as ",(0,a.kt)("inlineCode",{parentName:"p"},"infraction_block_header"),".\nThe latter provides the malicious validator's public key and the chain ID required to verify the signature of the votes contained in the evidence."),(0,a.kt)("p",null,"Note that double signing evidence is not verified using the same conditions as in the implementation CometBFT (see\n",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/evidence/verify.go#L19"},(0,a.kt)("inlineCode",{parentName:"a"},"verify(evidence types.Evidence)"))," method). Specifically, we do not check that the evidence hasn't expired.\nMore details can be found in the ",(0,a.kt)("a",{parentName:"p",href:"#current-limitations"},'"Current limitations"')," section below."),(0,a.kt)("p",null,"Upon a successful equivocation verification, the misbehaving validator is jailed for the maximum time\n(see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/evidence/types/params.go#L11"},"DoubleSignJailEndTime"),"\nin the SDK evidence module)."),(0,a.kt)("h3",{id:"current-limitations"},"Current limitations:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"We cannot derive an infraction height from the evidence, so it is only possible to jail validators, not actually slash them.\nTo explain the technical reasons behind this limitation, let's recap the initial consumer initiated slashing logic.\nIn a nutshell, consumer heights are mapped to provider heights through VSCPackets, namely through the so called vscIDs.\nWhen an infraction occurs on the consumer, a SlashPacket containing the vscID obtained from mapping the consumer infraction height\nis sent to the provider. Upon receiving the packet, the provider maps the consumer infraction height to a local infraction height,\nwhich is used to slash the misbehaving validator. In the context of untrusted consumer chains, all their states, including vscIDs,\ncould be corrupted and therefore cannot be used for slashing purposes.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"For the same reasons explained above, the age of a consumer double signing evidence can't be verified,\neither using its infraction height or its unsigned timestamp. Note that changes the jailing behaviour, potentially leading to a validator's jailing based on some \"old\" evidence from a consumer, which wouldn't occur if the consumer were a standalone chain.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"In the first stage of this feature, validators are jailed indefinitely without being tombstoned.\nThe underlying reason is that a malicious validator could take advantage of getting tombstoned\nto avoid being slashed on the provider (",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232#issuecomment-1693127641"},"see comment"),").")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Currently, the endpoint can only handle ",(0,a.kt)("em",{parentName:"p"},"equivocation")," light client attacks. This is because the ",(0,a.kt)("em",{parentName:"p"},"lunatic")," attacks require the endpoint to possess the ability to dissociate which header is conflicted or trusted upon receiving a misbehavior message. Without this information, it's not possible to extract the Byzantine validators from the conflicting headers (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/826#discussion_r1268668684"},"comment"),'). In addition, "amnesia" attacks are ignored, similar to CometBFT (see ',(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/main/docs/references/architecture/tendermint-core/adr-056-light-client-amnesia-attacks.md#decision"},"ADR-056"),")."))),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"It is now possible for the provider chain to jail validators who committed\nlight client or double signing attacks on a consumer chain.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"N/A")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/826"},"ICS misbehaviour handling PR")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/1232"},"Consumer double voting handler PR")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://docs.google.com/document/d/1fe1uSJl1ZIYWXoME3Yf4Aodvz7V597Ric875JH-rigM/edit#heading=h.rv4t8i6d6jfn"},"Architectural diagrams")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-013-equivocation-slashing.md"},"ADR on equivocation slashing"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/6700d82f.6e956d4b.js b/legacy/assets/js/6700d82f.6e956d4b.js new file mode 100644 index 0000000000..136c347dcc --- /dev/null +++ b/legacy/assets/js/6700d82f.6e956d4b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8055],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=p(n),m=r,h=d["".concat(s,".").concat(m)]||d[m]||c[m]||i;return n?a.createElement(h,o(o({ref:t},u),{},{components:n})):a.createElement(h,o({ref:t},u))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:r,o[1]=l;for(var p=2;p<i;p++)o[p]=n[p];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},1813:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=n(7462),r=(n(7294),n(3905));const i={sidebar_position:13,title:"Separate Releasing"},o="ADR 012: Separate Releasing",l={unversionedId:"adrs/adr-012-separate-releasing",id:"version-v3.3.1-lsm/adrs/adr-012-separate-releasing",title:"Separate Releasing",description:"Changelog",source:"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-012-separate-releasing.md",sourceDirName:"adrs",slug:"/adrs/adr-012-separate-releasing",permalink:"/interchain-security/legacy/adrs/adr-012-separate-releasing",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:13,frontMatter:{sidebar_position:13,title:"Separate Releasing"},sidebar:"tutorialSidebar",previous:{title:"Improving testing and increasing confidence",permalink:"/interchain-security/legacy/adrs/adr-011-improving-test-confidence"},next:{title:"Slashing on the provider for consumer equivocation",permalink:"/interchain-security/legacy/adrs/adr-013-equivocation-slashing"}},s={},p=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Spike results",id:"spike-results",level:3},{value:"Why go.mod split is not the way to go",id:"why-gomod-split-is-not-the-way-to-go",level:3},{value:"Why separate repos is cool but also not the way to go",id:"why-separate-repos-is-cool-but-also-not-the-way-to-go",level:3},{value:"Decision",id:"decision",level:2},{value:"Example release flow",id:"example-release-flow",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],u={toc:p},d="wrapper";function c(e){let{components:t,...n}=e;return(0,r.kt)(d,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"adr-012-separate-releasing"},"ADR 012: Separate Releasing"),(0,r.kt)("h2",{id:"changelog"},"Changelog"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"{8/18/22}: Initial draft of idea in ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/801"},"#801")),(0,r.kt)("li",{parentName:"ul"},"{8/22/22}: Put idea in this ADR"),(0,r.kt)("li",{parentName:"ul"},"{11/10/22}: Reject this ADR")),(0,r.kt)("h2",{id:"status"},"Status"),(0,r.kt)("p",null,"Rejected"),(0,r.kt)("h2",{id:"context"},"Context"),(0,r.kt)("h3",{id:"spike-results"},"Spike results"),(0,r.kt)("p",null,"I explored the idea of ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/issues/801"},"#801")," with this ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/shawn%2Fgo-mod-split-aug-spike"},"spike branch"),". Here's my conclusions:"),(0,r.kt)("p",null,"Splitting this repo to have multiple go.mods is possible. However there are various intricacies involved in decoupling the package hierarchy to have ",(0,r.kt)("inlineCode",{parentName:"p"},"x/ccv/types")," as the lowest level dep, with ",(0,r.kt)("inlineCode",{parentName:"p"},"x/ccv/consumer")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"x/ccv/provider")," being one dep layer above, with high-level tests depending on all three of the mentioned packages. I'd estimate this decoupling would take 2-5 workdays to finish, and require significant review effort."),(0,r.kt)("h3",{id:"why-gomod-split-is-not-the-way-to-go"},"Why go.mod split is not the way to go"),(0,r.kt)("p",null,"Let's take a step back and remember the issue we're trying to solve - ",(0,r.kt)("strong",{parentName:"p"},"We need a clean way to decouple semver/releasing for the consumer and provider modules"),". After more consideration, splitting up go.mods gives us little benefit in achieving this. Reasons:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"go.mod")," dependency system is tied to git tags for the entire repo (ex: ",(0,r.kt)("inlineCode",{parentName:"li"},"require github.com/cometbft/cometbft v0.37.2")," refers to a historical tag for the entire cometbft repo)."),(0,r.kt)("li",{parentName:"ul"},"It'd be an odd dev experience to allow modules to reference past releases of other modules in the same repo. When would we ever want the consumer module to reference a past release of the types module for example?"),(0,r.kt)("li",{parentName:"ul"},"If we allow for ",(0,r.kt)("inlineCode",{parentName:"li"},"go.mod")," replace statements to build from local source code, why split up the package deps at all?"),(0,r.kt)("li",{parentName:"ul"},"Splitting go.mods adds a bunch of complexity with ",(0,r.kt)("inlineCode",{parentName:"li"},"go.work")," files and all that shiz. VSCode does not play well with multiple module repos either.")),(0,r.kt)("h3",{id:"why-separate-repos-is-cool-but-also-not-the-way-to-go"},"Why separate repos is cool but also not the way to go"),(0,r.kt)("p",null,"All this considered, the cleanest solution to decoupling semver/releasing for the consumer and provider modules would be to have multiple repos, each with their own go.mod (3-4 repos total including high level tests). With this scheme we could separately tag each repo as changes are merged, they could share some code from ",(0,r.kt)("inlineCode",{parentName:"p"},"types")," being an external dep, etc."),(0,r.kt)("p",null,"I don't think any of us want to split up the monorepo, that's a lot of work and seems like bikeshedding. There's another solution that's very simple.. "),(0,r.kt)("h2",{id:"decision"},"Decision"),(0,r.kt)("p",null,"Slightly adapting ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/cca008d856e3ffc60ec1a486871d0faa702abe26/CONTRIBUTING.md#semantic-versioning"},"the current semver ruleset"),":"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"A library API breaking change to EITHER the provider or consumer module will result in an increase of the MAJOR version number for BOTH modules (X.y.z-provider AND X.y.z-consumer)."),(0,r.kt)("li",{parentName:"ul"},"A state breaking change (change requiring coordinated upgrade and/or state migration) will result in an increase of the MINOR version number for the AFFECTED module(s) (x.Y.z-provider AND/OR x.Y.z-consumer)."),(0,r.kt)("li",{parentName:"ul"},"Any other changes (including node API breaking changes) will result in an increase of the PATCH version number for the AFFECTED module(s) (x.y.Z-provider AND/OR x.y.Z-consumer).")),(0,r.kt)("h3",{id:"example-release-flow"},"Example release flow"),(0,r.kt)("p",null,"We upgrade ",(0,r.kt)("inlineCode",{parentName:"p"},"main")," to use a new version of SDK. This is a major version bump, triggering a new release for both the provider and consumer modules, ",(0,r.kt)("inlineCode",{parentName:"p"},"v5.0.0-provider")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"v5.0.0-consumer"),"."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"A state breaking change is merged to ",(0,r.kt)("inlineCode",{parentName:"li"},"main")," for the provider module. We release only a ",(0,r.kt)("inlineCode",{parentName:"li"},"v5.1.0-provider")," off main."),(0,r.kt)("li",{parentName:"ul"},"Another state breaking change is merged to ",(0,r.kt)("inlineCode",{parentName:"li"},"main")," for the provider module. We release only a ",(0,r.kt)("inlineCode",{parentName:"li"},"v5.2.0-provider")," off main."),(0,r.kt)("li",{parentName:"ul"},"At this point, the latest consumer version is still ",(0,r.kt)("inlineCode",{parentName:"li"},"v5.0.0-consumer"),". We now merge a state breaking change for the consumer module to ",(0,r.kt)("inlineCode",{parentName:"li"},"main"),", and consequently release ",(0,r.kt)("inlineCode",{parentName:"li"},"v5.1.0-consumer"),". Note that ",(0,r.kt)("inlineCode",{parentName:"li"},"v5.1.0-consumer")," is tagged off a LATER commit from main than ",(0,r.kt)("inlineCode",{parentName:"li"},"v5.2.0-provider"),". This is fine, as the consumer module should not be affected by the provider module's state breaking changes."),(0,r.kt)("li",{parentName:"ul"},"Once either module sees a library API breaking change, we bump the major version for both modules. For example, we merge a library API breaking change to ",(0,r.kt)("inlineCode",{parentName:"li"},"main")," for the provider module. We release ",(0,r.kt)("inlineCode",{parentName:"li"},"v6.0.0-provider")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"v6.0.0-consumer")," off main. Note that most often, a library API breaking change will affect both modules simultaneously (example being bumping sdk version).")),(0,r.kt)("h2",{id:"consequences"},"Consequences"),(0,r.kt)("h3",{id:"positive"},"Positive"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Consumer repos have clear communication of what tagged versions are relevant to them. Consumer devs should know to never reference an ICS version that starts with ",(0,r.kt)("inlineCode",{parentName:"li"},"provider"),", even if it'd technically build."),(0,r.kt)("li",{parentName:"ul"},"Consumer and provider modules do not deviate as long as we continually release off a shared main branch. Backporting remains relatively unchanged besides being explicit about what module(s) your changes should affect."),(0,r.kt)("li",{parentName:"ul"},"No code changes, just changes in process. Very simple.")),(0,r.kt)("h3",{id:"negative"},"Negative"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("del",{parentName:"li"},"Slightly more complexity."),"Considerably more complex to manage the ICS library.\nThis is because ICS needs to support multiple versions of SDK (e.g., 0.45, 0.47, 0.50).\nIn addition, ICS needs to support a special fork of SDK (with LSM included) for the Cosmos Hub.\nThis means that instead of focusing on main the development team needs to manage multiple release\nbranches with different dependency trees. "),(0,r.kt)("li",{parentName:"ul"},"This solution does not allow having provider and consumer on separate versions of e.g. the Cosmos SDK.")),(0,r.kt)("h3",{id:"neutral"},"Neutral"),(0,r.kt)("h2",{id:"references"},"References"),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/801"},"#801")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/801#issuecomment-1683349298"},"#801 comment"))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/67f96001.79e68eb4.js b/legacy/assets/js/67f96001.79e68eb4.js new file mode 100644 index 0000000000..318fb20f72 --- /dev/null +++ b/legacy/assets/js/67f96001.79e68eb4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6938],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>m});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=c(n),h=a,m=d["".concat(s,".").concat(h)]||d[h]||p[h]||o;return n?r.createElement(m,i(i({ref:t},u),{},{components:n})):r.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,i[1]=l;for(var c=2;c<o;c++)i[c]=n[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}h.displayName="MDXCreateElement"},7874:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const o={sidebar_position:2,title:"ADR Template"},i="ADR {ADR-NUMBER}:",l={unversionedId:"adrs/adr-template",id:"version-v3.1.0/adrs/adr-template",title:"ADR Template",description:"Changelog",source:"@site/versioned_docs/version-v3.1.0/adrs/adr-template.md",sourceDirName:"adrs",slug:"/adrs/adr-template",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-template",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"ADR Template"},sidebar:"tutorialSidebar",previous:{title:"ADR Template",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-prop"},next:{title:"Key Assignment",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-001-key-assignment"}},s={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],u={toc:c},d="wrapper";function p(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-adr-number-title"},"ADR {ADR-NUMBER}: {TITLE}"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"{date}: {changelog}")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},'A decision may be "proposed" if it hasn\'t been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement.')),(0,a.kt)("p",null,"{Deprecated|Proposed|Accepted}"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution. ")),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"This section explains all of the details of the proposed solution, including implementation details.\nIt should also describe affects / corollary items that may need to be changed as a part of this.\nIf the proposed change will be large, please also indicate a way to do the change to maximize ease of review.\n(e.g. the optimal split of things to do between separate PR's)")),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},'This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones.')),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Are there any relevant PR comments, issues that led up to this, or articles referrenced for why we made the given design choice? If so link them here!")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"{reference link}")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/68191a78.0ac8aa89.js b/legacy/assets/js/68191a78.0ac8aa89.js new file mode 100644 index 0000000000..a4672778ab --- /dev/null +++ b/legacy/assets/js/68191a78.0ac8aa89.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4438],{3905:(t,e,n)=>{n.d(e,{Zo:()=>p,kt:()=>g});var a=n(7294);function i(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function r(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,a)}return n}function l(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?r(Object(n),!0).forEach((function(e){i(t,e,n[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))}))}return t}function s(t,e){if(null==t)return{};var n,a,i=function(t,e){if(null==t)return{};var n,a,i={},r=Object.keys(t);for(a=0;a<r.length;a++)n=r[a],e.indexOf(n)>=0||(i[n]=t[n]);return i}(t,e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);for(a=0;a<r.length;a++)n=r[a],e.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(i[n]=t[n])}return i}var o=a.createContext({}),u=function(t){var e=a.useContext(o),n=e;return t&&(n="function"==typeof t?t(e):l(l({},e),t)),n},p=function(t){var e=u(t.components);return a.createElement(o.Provider,{value:e},t.children)},d="mdxType",c={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},m=a.forwardRef((function(t,e){var n=t.components,i=t.mdxType,r=t.originalType,o=t.parentName,p=s(t,["components","mdxType","originalType","parentName"]),d=u(n),m=i,g=d["".concat(o,".").concat(m)]||d[m]||c[m]||r;return n?a.createElement(g,l(l({ref:e},p),{},{components:n})):a.createElement(g,l({ref:e},p))}));function g(t,e){var n=arguments,i=e&&e.mdxType;if("string"==typeof t||i){var r=n.length,l=new Array(r);l[0]=m;var s={};for(var o in e)hasOwnProperty.call(e,o)&&(s[o]=e[o]);s.originalType=t,s[d]="string"==typeof t?t:i,l[1]=s;for(var u=2;u<r;u++)l[u]=n[u];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},7277:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>o,contentTitle:()=>l,default:()=>c,frontMatter:()=>r,metadata:()=>s,toc:()=>u});var a=n(7462),i=(n(7294),n(3905));const r={sidebar_position:12,title:"Improving testing and increasing confidence"},l="ADR 11: Improving testing and increasing confidence",s={unversionedId:"adrs/adr-011-improving-test-confidence",id:"adrs/adr-011-improving-test-confidence",title:"Improving testing and increasing confidence",description:"Changelog",source:"@site/docs/adrs/adr-011-improving-test-confidence.md",sourceDirName:"adrs",slug:"/adrs/adr-011-improving-test-confidence",permalink:"/interchain-security/legacy/adrs/adr-011-improving-test-confidence",draft:!1,tags:[],version:"current",sidebarPosition:12,frontMatter:{sidebar_position:12,title:"Improving testing and increasing confidence"},sidebar:"tutorialSidebar",previous:{title:"Standalone to Consumer Changeover",permalink:"/interchain-security/legacy/adrs/adr-010-standalone-changeover"},next:{title:"Separate Releasing",permalink:"/interchain-security/legacy/adrs/adr-012-separate-releasing"}},o={},u=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Current state of testing",id:"current-state-of-testing",level:4},{value:"Unit testing",id:"unit-testing",level:3},{value:"Integration testing",id:"integration-testing",level:3},{value:"End-to-end testing",id:"end-to-end-testing",level:3},{value:"Decision",id:"decision",level:2},{value:"1. Connect specifications to code and tooling",id:"1-connect-specifications-to-code-and-tooling",level:3},{value:"Decision context and hypothesis",id:"decision-context-and-hypothesis",level:4},{value:"Main benefit",id:"main-benefit",level:4},{value:"2. Improve e2e tooling",id:"2-improve-e2e-tooling",level:3},{value:"Matrix tests",id:"matrix-tests",level:4},{value:"Introducing e2e regression testing",id:"introducing-e2e-regression-testing",level:4},{value:"Introducing e2e CometMock tests",id:"introducing-e2e-cometmock-tests",level:4},{value:"3. Introduce innovative testing approaches",id:"3-introduce-innovative-testing-approaches",level:3},{value:"Model",id:"model",level:4},{value:"Driver",id:"driver",level:4},{value:"Harness",id:"harness",level:4},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],p={toc:u},d="wrapper";function c(t){let{components:e,...r}=t;return(0,i.kt)(d,(0,a.Z)({},p,r,{components:e,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"adr-11-improving-testing-and-increasing-confidence"},"ADR 11: Improving testing and increasing confidence"),(0,i.kt)("h2",{id:"changelog"},"Changelog"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"2023-08-11: Proposed, first draft of ADR.")),(0,i.kt)("h2",{id:"status"},"Status"),(0,i.kt)("p",null,"Proposed"),(0,i.kt)("h2",{id:"context"},"Context"),(0,i.kt)("p",null,"Testing, QA, and maintenance of interchain-security libraries is an ever-evolving area of software engineering we have to keep incrementally improving. The purpose of the QA process is to catch bugs as early as possible. In an ideal development workflow a bug should never reach production. A bug found in the specification stage is a lot cheaper to resolve than a bug discovered in production (or even in testnet). Ideally, all bugs should be found during the CI execution, and we hope that no bugs will ever even reach the testnet (although nothing can replace actual system stress test under load interacting with users)."),(0,i.kt)("p",null,"During development and testnet operation the following types of bugs were the most commonly found:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"improper iterator usage"),(0,i.kt)("li",{parentName:"ul"},"unbounded array access/iteration"),(0,i.kt)("li",{parentName:"ul"},"improper input handling and validation"),(0,i.kt)("li",{parentName:"ul"},"improper cached context usage"),(0,i.kt)("li",{parentName:"ul"},"non-determinism check (improper use of maps in go, relying on random values)"),(0,i.kt)("li",{parentName:"ul"},"KV store management and/or how keys are defined"),(0,i.kt)("li",{parentName:"ul"},"deserialization issues arising from consumer/provider versioning mismatch")),(0,i.kt)("p",null,"Such bugs can be discovered earlier with better tooling. Some of these bugs can induce increases in block times, chain halts, state corruption, or introduce an attack surface which is difficult to remove if other systems have started depending on that behavior."),(0,i.kt)("h4",{id:"current-state-of-testing"},"Current state of testing"),(0,i.kt)("p",null,"Our testing suites consist of multiple parts, each with their own trade-offs and benefits with regards to code coverage, complexity and confidence they provide."),(0,i.kt)("h3",{id:"unit-testing"},"Unit testing"),(0,i.kt)("p",null,"Unit testing is employed mostly for testing single-module functionality. It is the first step in testing and often the most practical. While highly important, unit tests often ",(0,i.kt)("strong",{parentName:"p"},"test a single piece of code")," and don't test relationships between different moving parts, this makes them less valuable when dealing with multi-module interactions."),(0,i.kt)("p",null,"Unit tests often employ mocks to abstract parts of the system that are not under test. Mocks are not equivalent to actual models and should not be treated as such."),(0,i.kt)("p",null,"Out of all the approaches used, unit testing has the most tools available and the coverage can simply be displayed as % of code lines tested. Although this is a very nice and very easy to understand metric, it does not speak about the quality of the test coverage."),(0,i.kt)("p",null,"Since distributed systems testing is a lot more involved, unit tests are oftentimes not sufficient to cover complex interactions. Unit tests are still necessary and helpful, but in cases where unit tests are not helpful e2e or integration tests should be favored."),(0,i.kt)("h3",{id:"integration-testing"},"Integration testing"),(0,i.kt)("p",null,"With integration testing we ",(0,i.kt)("strong",{parentName:"p"},"test the multi-module interactions")," while isolating them from the remainder of the system.\nIntegration tests can uncover bugs that are often missed by unit tests."),(0,i.kt)("p",null,"It is very difficult to gauge the actual test coverage imparted by integration tests and the available tooling is limited.\nIn interchain-security we employ the ",(0,i.kt)("inlineCode",{parentName:"p"},"ibc-go/testing")," framework to test interactions in-memory."),(0,i.kt)("p",null,"At present, integration testing does not involve the consensus layer - it is only concerned with application level state and logic."),(0,i.kt)("h3",{id:"end-to-end-testing"},"End-to-end testing"),(0,i.kt)("p",null,"In our context end-to-end testing comprises of tests that use the actual application binaries in an isolated environment (e.g. docker container). During test execution the inputs are meant to simulate actual user interaction, either by submitting transactions/queries using the command line or using gRPC/REST APIs and checking for state changes after an action has been performed. With this testing strategy we also include the consensus layer in all of our runs. This is the closest we can get to testing user interactions without starting a full testnet."),(0,i.kt)("p",null,"End-to-end testing strategies vary between different teams and projects and we strive to unify our approach to the best of our ability (at least for ICS and gaia)."),(0,i.kt)("p",null,"The available tooling does not give us significant (or relevant) line of code coverage information since most of the tools are geared towards analyzing unit tests and simple code branch evaluation."),(0,i.kt)("p",null,"We aim to adapt our best practices by learning from other similar systems and projects such as cosmos-sdk, ibc-go and CometBFT."),(0,i.kt)("h2",{id:"decision"},"Decision"),(0,i.kt)("h3",{id:"1-connect-specifications-to-code-and-tooling"},"1. Connect specifications to code and tooling"),(0,i.kt)("p",null,"Oftentimes, specifications are disconnected from the development and QA processes. This gives rise to problems where the specification does not reflect the actual state of the system and vice-versa.\nUsually specifications are just text files that are rarely used and go unmaintained after a while, resulting in consistency issues and misleading instructions/expectations about system behavior."),(0,i.kt)("h4",{id:"decision-context-and-hypothesis"},"Decision context and hypothesis"),(0,i.kt)("p",null,"Specifications written in a dedicated and executable specification language are easier to maintain than the ones written entirely in text.\nAdditionally, we can create models based on the specification OR make the model equivalent to a specification."),(0,i.kt)("p",null,"Models do not care about the intricacies of implementation and neither do specifications. Since both models and specifications care about concisely and accurately describing a system (such as a finite state machine), we see a benefit of adding model based tools (such as ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/informalsystems/quint"},"quint"),") to our testing and development workflows."),(0,i.kt)("h4",{id:"main-benefit"},"Main benefit"),(0,i.kt)("p",null,"MBT tooling can be used to generate test traces that can be executed by multiple different testing setups."),(0,i.kt)("h3",{id:"2-improve-e2e-tooling"},"2. Improve e2e tooling"),(0,i.kt)("h4",{id:"matrix-tests"},"Matrix tests"),(0,i.kt)("p",null,"Instead of only running tests against current ",(0,i.kt)("inlineCode",{parentName:"p"},"main")," branch we should adopt an approach where we also:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"run regression tests against different released software versions")," (",(0,i.kt)("inlineCode",{parentName:"li"},"ICS v1 vs v2 vs v3"),")"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"run non-determinism tests to uncover issues quickly"))),(0,i.kt)("p",null,"Matrix tests can be implemented using ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/informalsystems/CometMock"},"CometMock")," and refactoring our current e2e CI setup."),(0,i.kt)("h4",{id:"introducing-e2e-regression-testing"},"Introducing e2e regression testing"),(0,i.kt)("p",null,"This e2e test suite would execute using a cronjob in our CI (nightly, multiple times a day etc.)"),(0,i.kt)("p",null,"Briefly, the same set of traces is run against different ",(0,i.kt)("strong",{parentName:"p"},"maintained")," versions of the software and the ",(0,i.kt)("inlineCode",{parentName:"p"},"main")," branch.\nThis would allow us to discover potential issues during development instead of in a testnet scenarios."),(0,i.kt)("p",null,"The most valuable issues that can be discovered in this way are ",(0,i.kt)("strong",{parentName:"p"},"state breaking changes"),", ",(0,i.kt)("strong",{parentName:"p"},"regressions")," and ",(0,i.kt)("strong",{parentName:"p"},"version incompatibilities"),"."),(0,i.kt)("p",null,"The setup is illustrated by the image below.\n",(0,i.kt)("img",{alt:"e2e matrix tests",src:n(997).Z,width:"2170",height:"1624"})),(0,i.kt)("p",null,"This table explains which versions are tested against each other for the same set of test traces:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"\u2705 marks a passing test"),(0,i.kt)("li",{parentName:"ul"},"\u274c marks a failing test")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"USES: ICS v1 PROVIDER")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"start chain")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"add key")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"delegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"undelegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"redelegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"downtime")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"equivocation")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"stop chain")))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"v1 consumer (sdk45,ibc4.3)")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"v2 consumer (sdk45, ibc4.4)")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"v3 consumer (sdk47, ibc7)")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"main consumer")),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"neutron")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"stride")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c")))),(0,i.kt)("h4",{id:"introducing-e2e-cometmock-tests"},"Introducing e2e CometMock tests"),(0,i.kt)("p",null,"CometMock is a mock implementation of the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft"},"CometBFT")," consensus engine. It supports most operations performed by CometBFT while also being lightweight and relatively easy to use."),(0,i.kt)("p",null,'CometMock tests allow more nuanced control of test scenarios because CometMock can "fool" the blockchain app into thinking that a certain number of blocks had passed.\n',(0,i.kt)("strong",{parentName:"p"},"This allows us to test very nuanced scenarios, difficult edge cases and long-running operations (such as unbonding operations).")),(0,i.kt)("p",null,"Examples of tests made easier with CometMock are listed below:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"regression tests"),(0,i.kt)("li",{parentName:"ul"},"non-determinism tests"),(0,i.kt)("li",{parentName:"ul"},"upgrade tests"),(0,i.kt)("li",{parentName:"ul"},"state-breaking changes")),(0,i.kt)("p",null,"With CometMock, the ",(0,i.kt)("strong",{parentName:"p"},"matrix test")," approach can also be used. The image below illustrates a CometMock setup that can be used to discover non-deterministic behavior and state-breaking changes.\n",(0,i.kt)("img",{alt:"e2e matrix tests",src:n(1655).Z,width:"3714",height:"2082"})),(0,i.kt)("p",null,"This table explains which versions are tested against each other for the same set of test traces:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"\u2705 marks a passing test"),(0,i.kt)("li",{parentName:"ul"},"\u274c marks a failing test")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"SCENARIO")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"start chain")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"add key")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"delegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"undelegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"redelegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"downtime")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"equivocation")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"stop chain")))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"v3 provi + v3 consu")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"main provi + main consu")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"commit provi + commit consu")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c")))),(0,i.kt)("p",null,"Briefly; multiple versions of the application are run against the same CometMock instance and any deviations in app behavior would result in ",(0,i.kt)("inlineCode",{parentName:"p"},"app hash")," errors (the apps would be in different states after performing the same set of actions)."),(0,i.kt)("h3",{id:"3-introduce-innovative-testing-approaches"},"3. Introduce innovative testing approaches"),(0,i.kt)("p",null,"When discussing e2e testing, some very important patterns emerge - especially if test traces are used instead of ad-hoc tests written by hand."),(0,i.kt)("p",null,"We see a unique opportunity to clearly identify concerns and modularize the testing architecture. "),(0,i.kt)("p",null,"The e2e testing frameworks can be split into a ",(0,i.kt)("strong",{parentName:"p"},"pipeline consisting of 3 parts: model, driver and harness"),"."),(0,i.kt)("h4",{id:"model"},"Model"),(0,i.kt)("p",null,"Model is the part of the system that can emulate the behavior of the system under test.\nIdeally, it is very close to the specification and is written in a specification language such as quint, TLA+ or similar.\nOne of the purposes of the model is that it can be used to generate test traces. "),(0,i.kt)("h4",{id:"driver"},"Driver"),(0,i.kt)("p",null,"The purpose of the driver is to accept test traces (generated by the model or written by hand), process them and provide inputs to the next part of the pipeline."),(0,i.kt)("p",null,"Basically, the driver sits between the model and the actual infrastructure on which the test traces are being executed on."),(0,i.kt)("h4",{id:"harness"},"Harness"),(0,i.kt)("p",null,"Harness is the infrastructure layer of the pipeline that accepts inputs from the driver."),(0,i.kt)("p",null,"There can be multiple harnesses as long as they can perform four things:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"bootstrap a test execution environment (local, docker, k8s\u2026)"),(0,i.kt)("li",{parentName:"ul"},"accept inputs from drivers"),(0,i.kt)("li",{parentName:"ul"},"perform the action specified by the driver"),(0,i.kt)("li",{parentName:"ul"},"report results after performing actions")),(0,i.kt)("h2",{id:"consequences"},"Consequences"),(0,i.kt)("p",null,"The procedure outlined in this ADR is not an all-or-nothing approach. Concepts introduced here do not rely on each other, so this ADR may only be applied partially without negative impact on test coverage and code confidence."),(0,i.kt)("h3",{id:"positive"},"Positive"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"introduction of maintainable MBT solutions")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},'improvement over the current "difftest" setup that relies on an opinionated typescript model and go driver')),(0,i.kt)("ol",{start:2},(0,i.kt)("li",{parentName:"ol"},"increased code coverage and confidence")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"using CometMock allows us to run more tests in less time"),(0,i.kt)("li",{parentName:"ul"},"adding matrix e2e tests allows us to quickly pinpoint differences between code versions")),(0,i.kt)("h3",{id:"negative"},"Negative"),(0,i.kt)("p",null,"It might be easier to forgo the MBT tooling and instead focus on pure property based testing"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/667"},"PBT proof of concept")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/flyingmutant/rapid"},"property based testing in go"))),(0,i.kt)("p",null,'The solutions are potentially expensive if we increase usage of the CI pipeline - this is fixed by running "expensive" tests using a cronjob, instead of running them on every commit.'),(0,i.kt)("h3",{id:"neutral"},"Neutral"),(0,i.kt)("p",null,"The process of changing development and testing process is not something that can be thought of and delivered quickly. Luckily, the changes can be rolled out incrementally without impacting existing workflows."),(0,i.kt)("h2",{id:"references"},"References"),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/gaia/issues/2427"},"https://github.com/cosmos/gaia/issues/2427")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/gaia/issues/2420"},"https://github.com/cosmos/gaia/issues/2420")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/ibc-go/tree/main/e2e"},"ibc-go e2e tests"))))}c.isMDXComponent=!0},1655:(t,e,n)=>{n.d(e,{Z:()=>a});const a=n.p+"assets/images/cometmock_matrix_test-714f36252aff9df4214823e3145d0ef5.png"},997:(t,e,n)=>{n.d(e,{Z:()=>a});const a=n.p+"assets/images/matrix_e2e_tests-30681305077301daaf3097e1952b54bb.png"}}]); \ No newline at end of file diff --git a/legacy/assets/js/681cd12f.dfc08d34.js b/legacy/assets/js/681cd12f.dfc08d34.js new file mode 100644 index 0000000000..5ad8130130 --- /dev/null +++ b/legacy/assets/js/681cd12f.dfc08d34.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7443],{3905:(e,t,i)=>{i.d(t,{Zo:()=>h,kt:()=>m});var n=i(7294);function a(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}function o(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function s(e){for(var t=1;t<arguments.length;t++){var i=null!=arguments[t]?arguments[t]:{};t%2?o(Object(i),!0).forEach((function(t){a(e,t,i[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(i)):o(Object(i)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(i,t))}))}return e}function r(e,t){if(null==e)return{};var i,n,a=function(e,t){if(null==e)return{};var i,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)i=o[n],t.indexOf(i)>=0||(a[i]=e[i]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)i=o[n],t.indexOf(i)>=0||Object.prototype.propertyIsEnumerable.call(e,i)&&(a[i]=e[i])}return a}var c=n.createContext({}),l=function(e){var t=n.useContext(c),i=t;return e&&(i="function"==typeof e?e(t):s(s({},t),e)),i},h=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var i=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,h=r(e,["components","mdxType","originalType","parentName"]),d=l(i),p=a,m=d["".concat(c,".").concat(p)]||d[p]||u[p]||o;return i?n.createElement(m,s(s({ref:t},h),{},{components:i})):n.createElement(m,s({ref:t},h))}));function m(e,t){var i=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=i.length,s=new Array(o);s[0]=p;var r={};for(var c in t)hasOwnProperty.call(t,c)&&(r[c]=t[c]);r.originalType=e,r[d]="string"==typeof e?e:a,s[1]=r;for(var l=2;l<o;l++)s[l]=i[l];return n.createElement.apply(null,s)}return n.createElement.apply(null,i)}p.displayName="MDXCreateElement"},8013:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>u,frontMatter:()=>o,metadata:()=>r,toc:()=>l});var n=i(7462),a=(i(7294),i(3905));const o={sidebar_position:4,title:"Cryptographic verification of equivocation evidence"},s="ADR 005: Cryptographic verification of equivocation evidence",r={unversionedId:"adrs/adr-005-cryptographic-equivocation-verification",id:"version-v3.3.0/adrs/adr-005-cryptographic-equivocation-verification",title:"Cryptographic verification of equivocation evidence",description:"Changelog",source:"@site/versioned_docs/version-v3.3.0/adrs/adr-005-cryptographic-equivocation-verification.md",sourceDirName:"adrs",slug:"/adrs/adr-005-cryptographic-equivocation-verification",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-005-cryptographic-equivocation-verification",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Cryptographic verification of equivocation evidence"},sidebar:"tutorialSidebar",previous:{title:"Equivocation governance proposal",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-003-equivocation-gov-proposal"},next:{title:"Throttle with retries",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-008-throttle-retries"}},c={},l=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Light Client Attack",id:"light-client-attack",level:3},{value:"Double Signing Attack",id:"double-signing-attack",level:3},{value:"Decision",id:"decision",level:2},{value:"Light Client Attack",id:"light-client-attack-1",level:3},{value:"Double Signing Attack",id:"double-signing-attack-1",level:3},{value:"Current limitations:",id:"current-limitations",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}],h={toc:l},d="wrapper";function u(e){let{components:t,...i}=e;return(0,a.kt)(d,(0,n.Z)({},h,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-005-cryptographic-verification-of-equivocation-evidence"},"ADR 005: Cryptographic verification of equivocation evidence"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"5/1/2023: First draft"),(0,a.kt)("li",{parentName:"ul"},"7/23/2023: Add light client attacks handling"),(0,a.kt)("li",{parentName:"ul"},"9/6/2023: Add double signing attacks handling"),(0,a.kt)("li",{parentName:"ul"},"11/3/2023: Update limitations to clarify amnesia attacks are ignored")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"Currently, we use a governance proposal to slash validators for equivocation (double signing and light client attacks).\nEvery proposal needs to go through a (two weeks) voting period before it can be approved.\nGiven a three-week unbonding period, this means that an equivocation proposal needs to be submitted within one week since the infraction occurred."),(0,a.kt)("p",null,"This ADR proposes a system to slash validators automatically for equivocation, immediately upon the provider chain's receipt of the evidence. Another thing to note is that we intend to introduce this system in stages, since even the partial ability to slash and/or tombstone is a strict improvement in security.\nThe feature is implemented in two parts, each with its dedicated endpoint. One endpoint handles light client attacks, while the other handles double signing attacks."),(0,a.kt)("h3",{id:"light-client-attack"},"Light Client Attack"),(0,a.kt)("p",null,"In a nutshell, the light client is a process that solely verifies a specific state machine's\nconsensus without executing the transactions. The light clients get new headers by querying\nmultiple nodes, called primary and witness nodes. "),(0,a.kt)("p",null,"Light clients download new headers committed on chain from a primary. Headers can be verified in two ways: sequentially,\nwhere the block height of headers is serial, or using skipping. This second verification method allows light clients to download headers\nwith nonconsecutive block height, where some intermediate headers are skipped (see ",(0,a.kt)("a",{parentName:"p",href:"https://arxiv.org/pdf/2010.07031.pdf"},"Tendermint Light Client, Figure 1 and Figure 3"),").\nAdditionally, light clients are cross-checking new headers obtained from a primary with witnesses to ensure all nodes share the same state."),(0,a.kt)("p",null,"A light client attack occurs when a Byzantine validator sends invalid headers to a light client.\nAs the light client doesn't execute transactions, it can be deceived into trusting corrupted application state transitions.\nFor instance, if a light client receives header ",(0,a.kt)("inlineCode",{parentName:"p"},"A")," from the primary and header ",(0,a.kt)("inlineCode",{parentName:"p"},"B")," from a witness for the same block height ",(0,a.kt)("inlineCode",{parentName:"p"},"H"),",\nand both headers are successfully verified, it indicates a light client attack.\nNote that in this case, either the primary or the witness or both are malicious."),(0,a.kt)("p",null,"The types of light client attacks are defined by analyzing the differences between the conflicting headers.\nThere are three types of light client attacks: lunatic attack, equivocation attack, and amnesia attack.\nFor details, see the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/main/spec/light-client/attacks/notes-on-evidence-handling.md#evidence-handling"},"CometBFT specification"),"."),(0,a.kt)("p",null,"When a light client agent detects two conflicting headers, it will initially verify their traces (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/light/detector.go#L28"},"cometBFT detector"),") using its primary and witness nodes.\nIf these headers pass successful verification, the Byzantine validators will be identified based on the header's commit signatures\nand the type of light client attack. The agent will then transmit this information to its nodes using a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#light-client-attacks"},(0,a.kt)("inlineCode",{parentName:"a"},"LightClientAttackEvidence"))," evidence to be eventually voted on and added to a block.\nNote that from a light client agent perspective, it is not possible to establish whether a primary or a witness node, or both, are malicious.\nTherefore, it will create and send two evidences: one against the primary (sent to the witness), and one against the witness (sent to the primary).\nBoth nodes will then verify it before broadcasting it and adding it to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/evidence/pool.go#L28"},"evidence pool"),".\nIf an evidence is finally committed to a block, the chain's evidence module will execute it, resulting in the jailing and the slashing of the validators responsible for the light client attack."),(0,a.kt)("p",null,"Light clients are a core component of IBC. In the event of a light client attack, IBC relayers notify the affected chains by submitting an ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/v4.4.2/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79"},"IBC misbehavior message"),".\nA misbehavior message includes the conflicting headers that constitute a light client attack evidence. Upon receiving such a message,\na chain will first verify whether these headers would have convinced its light client. This verification is achieved by checking\nthe header states against the light client consensus states (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/v4.4.2/modules/light-clients/07-tendermint/types/misbehaviour_handle.go#L24"},"IBC misbehaviour handler"),'). If the misbehaviour is successfully verified, the chain will then "freeze" the\nlight client, halting any further trust in or updating of its states.'),(0,a.kt)("h3",{id:"double-signing-attack"},"Double Signing Attack"),(0,a.kt)("p",null,"A double signing attack, also known as equivocation,\noccurs when a validator votes for two different blocks in the same round of the CometBFT consensus.\nThis consensus mechanism operates with multiple voting rounds at each block height,\nand it strictly prohibits sending two votes of the same type during a round\n(see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/consensus.md#state-machine-overview"},"CometBFT State Machine Overview"),")."),(0,a.kt)("p",null,"When a node observes two votes from the same peer, it will use these two votes to create\na ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/types/evidence.go#L35"},(0,a.kt)("inlineCode",{parentName:"a"},"DuplicateVoteEvidence")),"\nevidence and gossip it to the other nodes in the network\n(see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#detection"},"CometBFT equivocation detection"),").\nEach node will then verify the evidence according to the CometBFT rules that define a valid double signing infraction, and based on this verification, they will decide whether to add the evidence to a block.\nDuring the evidence verification process, the signatures of the conflicting votes must be verified successfully.\nNote that this is achieved using the public key of the misbehaving validator, along with the chain ID of the chain where the infraction occurred (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#verification"},"CometBFT equivocation verification"),")."),(0,a.kt)("p",null,"Once a double signing evidence is committed to a block, the consensus layer will report the equivocation to the evidence module of the Cosmos SDK application layer.\nThe application will, in turn, punish the malicious validator through jailing, tombstoning and slashing\n(see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/evidence/keeper/infraction.go#L263"},"handleEquivocationEvidence"),")."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("h3",{id:"light-client-attack-1"},"Light Client Attack"),(0,a.kt)("p",null,"In the first part of the feature, we introduce a new endpoint: ",(0,a.kt)("inlineCode",{parentName:"p"},"HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour)"),".\nThe main idea is to leverage the current IBC misbehaviour handling and update it to solely jail and slash the validators that\nperformed a light client attack. Note that in this context, we assume that chains connected via a light client\nshare the same validator set, as is the case with Replicated Security. "),(0,a.kt)("p",null,"This endpoint reuses the IBC client libraries to verify that the misbehaviour headers would have fooled the light client.\nAdditionally, it\u2019s crucial that the endpoint logic results in the slashing and jailing of validators under the same conditions\nas a light client agent detector. Therefore, the endpoint ensures that the two conditions are met:\nthe headers in the misbehaviour message have the same block height, and\nthe light client isn\u2019t expired."),(0,a.kt)("p",null,"After having successfully verified a misbehaviour, the endpoint executes the jailing and slashing of the malicious validators similarly as in the evidence module. "),(0,a.kt)("h3",{id:"double-signing-attack-1"},"Double Signing Attack"),(0,a.kt)("p",null,"In the second part of the feature, we introduce a new endpoint ",(0,a.kt)("inlineCode",{parentName:"p"},"HandleConsumerDoubleVoting(\nctx sdk.Context, evidence *tmtypes.DuplicateVoteEvidence, chainID string, pubkey cryptotypes.PubKey)"),".\nSimply put, the handling logic verifies a double signing evidence against a provided\npublic key and chain ID and, if successful, executes the jailing of the malicious validator who double voted."),(0,a.kt)("p",null,"We define a new\n",(0,a.kt)("inlineCode",{parentName:"p"},"MsgSubmitConsumerDoubleVoting")," message to report a double voting evidence observed\non a consumer chain to the endpoint of the provider chain. This message contains two fields:\na double signing evidence\n",(0,a.kt)("inlineCode",{parentName:"p"},"duplicate_vote_evidence")," and a light client header for the infraction block height,\nreferred to as ",(0,a.kt)("inlineCode",{parentName:"p"},"infraction_block_header"),".\nThe latter provides the malicious validator's public key and the chain ID required to verify the signature of the votes contained in the evidence."),(0,a.kt)("p",null,"Note that double signing evidence is not verified using the same conditions as in the implementation CometBFT (see\n",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.34.28/evidence/verify.go#L19"},(0,a.kt)("inlineCode",{parentName:"a"},"verify(evidence types.Evidence)"))," method). Specifically, we do not check that the evidence hasn't expired.\nMore details can be found in the ",(0,a.kt)("a",{parentName:"p",href:"#current-limitations"},'"Current limitations"')," section below. "),(0,a.kt)("p",null,"Upon a successful equivocation verification, the misbehaving validator is jailed for the maximum time\n(see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/evidence/types/params.go#L11"},"DoubleSignJailEndTime"),"\nin the SDK evidence module)."),(0,a.kt)("h3",{id:"current-limitations"},"Current limitations:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"We cannot derive an infraction height from the evidence, so it is only possible to jail validators, not actually slash them.\nTo explain the technical reasons behind this limitation, let's recap the initial consumer initiated slashing logic.\nIn a nutshell, consumer heights are mapped to provider heights through VSCPackets, namely through the so called vscIDs.\nWhen an infraction occurs on the consumer, a SlashPacket containing the vscID obtained from mapping the consumer infraction height\nis sent to the provider. Upon receiving the packet, the provider maps the consumer infraction height to a local infraction height,\nwhich is used to slash the misbehaving validator. In the context of untrusted consumer chains, all their states, including vscIDs,\ncould be corrupted and therefore cannot be used for slashing purposes.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"For the same reasons explained above, the age of a consumer double signing evidence can't be verified,\neither using its infraction height or its unsigned timestamp. Note that changes the jailing behaviour, potentially leading to a validator's jailing based on some \"old\" evidence from a consumer, which wouldn't occur if the consumer were a standalone chain.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"In the first stage of this feature, validators are jailed indefinitely without being tombstoned.\nThe underlying reason is that a malicious validator could take advantage of getting tombstoned\nto avoid being slashed on the provider (",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232#issuecomment-1693127641"},"see comment"),"). ")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Currently, the endpoint can only handle ",(0,a.kt)("em",{parentName:"p"},"equivocation")," light client attacks. This is because the ",(0,a.kt)("em",{parentName:"p"},"lunatic")," attacks require the endpoint to possess the ability to dissociate which header is conflicted or trusted upon receiving a misbehavior message. Without this information, it's not possible to extract the Byzantine validators from the conflicting headers (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/826#discussion_r1268668684"},"comment"),'). In addition, "amnesia" attacks are ignored, similar to CometBFT (see ',(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/main/docs/architecture/tendermint-core/adr-056-light-client-amnesia-attacks.md#decision"},"ADR-056"),")."))),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"It is now possible for the provider chain to jail validators who committed\nlight client or double signing attacks on a consumer chain.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"N/A")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/826"},"ICS misbehaviour handling PR")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/1232"},"Consumer double voting handler PR")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://docs.google.com/document/d/1fe1uSJl1ZIYWXoME3Yf4Aodvz7V597Ric875JH-rigM/edit#heading=h.rv4t8i6d6jfn"},"Architectural diagrams")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-013-equivocation-slashing.md"},"ADR on equivocation slashing"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/6a7358b5.5cf848d2.js b/legacy/assets/js/6a7358b5.5cf848d2.js new file mode 100644 index 0000000000..1bbd841f2f --- /dev/null +++ b/legacy/assets/js/6a7358b5.5cf848d2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9743],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var i=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,i,r=function(e,t){if(null==e)return{};var n,i,r={},o=Object.keys(e);for(i=0;i<o.length;i++)n=o[i],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i<o.length;i++)n=o[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=i.createContext({}),d=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=d(e.components);return i.createElement(l.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},m=i.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),c=d(n),m=r,h=c["".concat(l,".").concat(m)]||c[m]||u[m]||o;return n?i.createElement(h,a(a({ref:t},p),{},{components:n})):i.createElement(h,a({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,a=new Array(o);a[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:r,a[1]=s;for(var d=2;d<o;d++)a[d]=n[d];return i.createElement.apply(null,a)}return i.createElement.apply(null,n)}m.displayName="MDXCreateElement"},3356:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var i=n(7462),r=(n(7294),n(3905));const o={sidebar_position:3},a="Interchain Security Parameters",s={unversionedId:"introduction/params",id:"version-v2.0.0/introduction/params",title:"Interchain Security Parameters",description:"The parameters necessary for Interchain Security (ICS) are defined in",source:"@site/versioned_docs/version-v2.0.0/introduction/params.md",sourceDirName:"introduction",slug:"/introduction/params",permalink:"/interchain-security/legacy/v2.0.0/introduction/params",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Terminology",permalink:"/interchain-security/legacy/v2.0.0/introduction/terminology"},next:{title:"Technical Specification",permalink:"/interchain-security/legacy/v2.0.0/introduction/technical-specification"}},l={},d=[{value:"Time-based parameters",id:"time-based-parameters",level:2},{value:"ProviderUnbondingPeriod",id:"providerunbondingperiod",level:3},{value:"ConsumerUnbondingPeriod",id:"consumerunbondingperiod",level:3},{value:"TrustingPeriodFraction",id:"trustingperiodfraction",level:3},{value:"CCVTimeoutPeriod",id:"ccvtimeoutperiod",level:3},{value:"InitTimeoutPeriod",id:"inittimeoutperiod",level:3},{value:"<code>VscTimeoutPeriod</code>",id:"vsctimeoutperiod",level:3},{value:"BlocksPerDistributionTransmission",id:"blocksperdistributiontransmission",level:3},{value:"TransferPeriodTimeout",id:"transferperiodtimeout",level:3},{value:"Slash Throttle Parameters",id:"slash-throttle-parameters",level:2},{value:"SlashMeterReplenishPeriod",id:"slashmeterreplenishperiod",level:3},{value:"SlashMeterReplenishFraction",id:"slashmeterreplenishfraction",level:3},{value:"MaxThrottledPackets",id:"maxthrottledpackets",level:3}],p={toc:d},c="wrapper";function u(e){let{components:t,...n}=e;return(0,r.kt)(c,(0,i.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"interchain-security-parameters"},"Interchain Security Parameters"),(0,r.kt)("p",null,"The parameters necessary for Interchain Security (ICS) are defined in "),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"the ",(0,r.kt)("inlineCode",{parentName:"li"},"Params")," structure in ",(0,r.kt)("inlineCode",{parentName:"li"},"proto/interchain_security/ccv/provider/v1/provider.proto")," for the provider;"),(0,r.kt)("li",{parentName:"ul"},"the ",(0,r.kt)("inlineCode",{parentName:"li"},"Params")," structure in ",(0,r.kt)("inlineCode",{parentName:"li"},"proto/interchain_security/ccv/consumer/v1/consumer.proto")," for the consumer.")),(0,r.kt)("h2",{id:"time-based-parameters"},"Time-based parameters"),(0,r.kt)("p",null,"ICS relies on the following time-based parameters."),(0,r.kt)("h3",{id:"providerunbondingperiod"},"ProviderUnbondingPeriod"),(0,r.kt)("p",null,"is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance."),(0,r.kt)("h3",{id:"consumerunbondingperiod"},"ConsumerUnbondingPeriod"),(0,r.kt)("p",null,"is the unbonding period on the consumer chain."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerUnbondingPeriod")," is set via the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," governance proposal to add a new consumer chain.\nIt is recommended that every consumer chain set and unbonding period shorter than ",(0,r.kt)("inlineCode",{parentName:"p"},"ProviderUnbondingPeriod")),(0,r.kt)("br",null),(0,r.kt)("p",{parentName:"admonition"},"Example:"),(0,r.kt)("pre",{parentName:"admonition"},(0,r.kt)("code",{parentName:"pre"},"ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day\n"))),(0,r.kt)("p",null,"Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer."),(0,r.kt)("h3",{id:"trustingperiodfraction"},"TrustingPeriodFraction"),(0,r.kt)("p",null,"is used to calculate the ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriod")," of created IBC clients on both provider and consumer chains. "),(0,r.kt)("p",null,"Setting ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriodFraction")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"0.5")," would result in the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"TrustingPeriodFraction = 0.5\nProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5\nConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5\n")),(0,r.kt)("p",null,"Note that a light clients must be updated within the ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriod")," in order to avoid being frozen."),(0,r.kt)("p",null,"For more details, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/client/ics-007-tendermint-client/README.md"},"IBC specification of Tendermint clients"),"."),(0,r.kt)("h3",{id:"ccvtimeoutperiod"},"CCVTimeoutPeriod"),(0,r.kt)("p",null,"is the period used to compute the timeout timestamp when sending IBC packets. "),(0,r.kt)("p",null,"For more details, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/core/ics-004-channel-and-packet-semantics/README.md#sending-packets"},"IBC specification of Channel & Packet Semantics"),"."),(0,r.kt)("admonition",{type:"warning"},(0,r.kt)("p",{parentName:"admonition"},"If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed.")),(0,r.kt)("p",null,"CCVTimeoutPeriod may have different values on the provider and consumer chains."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"CCVTimeoutPeriod")," on the provider ",(0,r.kt)("strong",{parentName:"li"},"must")," be larger than ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerUnbondingPeriod")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"CCVTimeoutPeriod")," on the consumer is initial set via the ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal"))),(0,r.kt)("h3",{id:"inittimeoutperiod"},"InitTimeoutPeriod"),(0,r.kt)("p",null,"is the maximum allowed duration for CCV channel initialization to execute."),(0,r.kt)("p",null,"For any consumer chain, if the CCV channel is not established within ",(0,r.kt)("inlineCode",{parentName:"p"},"InitTimeoutPeriod")," then the consumer chain will be removed and therefore will not be secured by the provider chain."),(0,r.kt)("p",null,"The countdown starts when the ",(0,r.kt)("inlineCode",{parentName:"p"},"spawn_time")," specified in the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," is reached."),(0,r.kt)("h3",{id:"vsctimeoutperiod"},(0,r.kt)("inlineCode",{parentName:"h3"},"VscTimeoutPeriod")),(0,r.kt)("p",null,"is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live.\nIf the ",(0,r.kt)("inlineCode",{parentName:"p"},"VscTimeoutPeriod")," is ever reached for a consumer chain that chain will be considered not live and removed from interchain security."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"VscTimeoutPeriod")," MUST be larger than the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerUnbondingPeriod"),".")),(0,r.kt)("h3",{id:"blocksperdistributiontransmission"},"BlocksPerDistributionTransmission"),(0,r.kt)("p",null,"is the number of blocks between rewards transfers from the consumer to the provider."),(0,r.kt)("h3",{id:"transferperiodtimeout"},"TransferPeriodTimeout"),(0,r.kt)("p",null,"is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider."),(0,r.kt)("p",null,"If this timeout expires, then the transfer is attempted again after ",(0,r.kt)("inlineCode",{parentName:"p"},"BlocksPerDistributionTransmission")," blocks."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"TransferPeriodTimeout")," on the consumer is initial set via the ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal")," gov proposal to add the consumer"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"TransferPeriodTimeout")," should be smaller than ",(0,r.kt)("inlineCode",{parentName:"li"},"BlocksPerDistributionTransmission x avg_block_time"))),(0,r.kt)("h2",{id:"slash-throttle-parameters"},"Slash Throttle Parameters"),(0,r.kt)("h3",{id:"slashmeterreplenishperiod"},"SlashMeterReplenishPeriod"),(0,r.kt)("p",null,"exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed."),(0,r.kt)("p",null,"The meter is replenished to an amount equal to the slash meter allowance for that block, or ",(0,r.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction * CurrentTotalVotingPower"),"."),(0,r.kt)("h3",{id:"slashmeterreplenishfraction"},"SlashMeterReplenishFraction"),(0,r.kt)("p",null,"exists on the provider as the portion (in range ","[0, 1]",") of total voting power that is replenished to the slash meter when a replenishment occurs."),(0,r.kt)("p",null,"This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a ",(0,r.kt)("inlineCode",{parentName:"p"},"sdk.Dec")," when used."),(0,r.kt)("h3",{id:"maxthrottledpackets"},"MaxThrottledPackets"),(0,r.kt)("p",null,"exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value."),(0,r.kt)("p",null,"This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/6c7cd03d.695e3b04.js b/legacy/assets/js/6c7cd03d.695e3b04.js new file mode 100644 index 0000000000..03bf8f529c --- /dev/null +++ b/legacy/assets/js/6c7cd03d.695e3b04.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[379],{2780:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"v2.4.0-lsm","label":"v2.4.0-lsm","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-v2.4.0-lsm","isLast":false,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Interchain Security Docs","href":"/interchain-security/legacy/v2.4.0-lsm/","docId":"index"},{"type":"category","label":"Introduction","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/legacy/v2.4.0-lsm/introduction/overview","docId":"introduction/overview"},{"type":"link","label":"Terminology","href":"/interchain-security/legacy/v2.4.0-lsm/introduction/terminology","docId":"introduction/terminology"},{"type":"link","label":"Interchain Security Parameters","href":"/interchain-security/legacy/v2.4.0-lsm/introduction/params","docId":"introduction/params"},{"type":"link","label":"Technical Specification","href":"/interchain-security/legacy/v2.4.0-lsm/introduction/technical-specification","docId":"introduction/technical-specification"}]},{"type":"category","label":"Features","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Key Assignment","href":"/interchain-security/legacy/v2.4.0-lsm/features/key-assignment","docId":"features/key-assignment"},{"type":"link","label":"Reward distribution","href":"/interchain-security/legacy/v2.4.0-lsm/features/reward-distribution","docId":"features/reward-distribution"},{"type":"link","label":"ICS Provider Proposals","href":"/interchain-security/legacy/v2.4.0-lsm/features/proposals","docId":"features/proposals"},{"type":"link","label":"Consumer Initiated Slashing","href":"/interchain-security/legacy/v2.4.0-lsm/features/slashing","docId":"features/slashing"}]},{"type":"category","label":"Consumer Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Developing an ICS consumer chain","href":"/interchain-security/legacy/v2.4.0-lsm/consumer-development/app-integration","docId":"consumer-development/app-integration"},{"type":"link","label":"Consumer Chain Governance","href":"/interchain-security/legacy/v2.4.0-lsm/consumer-development/consumer-chain-governance","docId":"consumer-development/consumer-chain-governance"},{"type":"link","label":"Upgrading Consumer Chains","href":"/interchain-security/legacy/v2.4.0-lsm/consumer-development/consumer-chain-upgrade-procedure","docId":"consumer-development/consumer-chain-upgrade-procedure"},{"type":"link","label":"Onboarding Checklist","href":"/interchain-security/legacy/v2.4.0-lsm/consumer-development/onboarding","docId":"consumer-development/onboarding"},{"type":"link","label":"Offboarding Checklist","href":"/interchain-security/legacy/v2.4.0-lsm/consumer-development/offboarding","docId":"consumer-development/offboarding"}]},{"type":"category","label":"Validators Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/legacy/v2.4.0-lsm/validators/overview","docId":"validators/overview"},{"type":"link","label":"Joining Replicated Security testnet","href":"/interchain-security/legacy/v2.4.0-lsm/validators/joining-testnet","docId":"validators/joining-testnet"},{"type":"link","label":"Withdrawing consumer chain validator rewards","href":"/interchain-security/legacy/v2.4.0-lsm/validators/withdraw_rewards","docId":"validators/withdraw_rewards"}]},{"type":"link","label":"Frequently Asked Questions","href":"/interchain-security/legacy/v2.4.0-lsm/faq","docId":"frequently-asked-questions"},{"type":"category","label":"ADRs","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"ADRs","href":"/interchain-security/legacy/v2.4.0-lsm/adrs/intro","docId":"adrs/intro"},{"type":"link","label":"ADR Template","href":"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-template","docId":"adrs/adr-template"},{"type":"link","label":"Key Assignment","href":"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-001-key-assignment","docId":"adrs/adr-001-key-assignment"},{"type":"link","label":"Jail Throttling","href":"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-002-throttle","docId":"adrs/adr-002-throttle"},{"type":"link","label":"Equivocation governance proposal","href":"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposal","docId":"adrs/adr-003-equivocation-gov-proposal"},{"type":"link","label":"Cryptographic verification of equivocation evidence","href":"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verification","docId":"adrs/adr-005-cryptographic-equivocation-verification"},{"type":"link","label":"Slashing on the provider for consumer equivocation","href":"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-013-equivocation-slashing","docId":"adrs/adr-013-equivocation-slashing"}]}]},"docs":{"adrs/adr-001-key-assignment":{"id":"adrs/adr-001-key-assignment","title":"Key Assignment","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-002-throttle":{"id":"adrs/adr-002-throttle","title":"Jail Throttling","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-003-equivocation-gov-proposal":{"id":"adrs/adr-003-equivocation-gov-proposal","title":"Equivocation governance proposal","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-005-cryptographic-equivocation-verification":{"id":"adrs/adr-005-cryptographic-equivocation-verification","title":"Cryptographic verification of equivocation evidence","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-013-equivocation-slashing":{"id":"adrs/adr-013-equivocation-slashing","title":"Slashing on the provider for consumer equivocation","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-template":{"id":"adrs/adr-template","title":"ADR Template","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/intro":{"id":"adrs/intro","title":"ADRs","description":"This is a location to record all high-level architecture decisions in the Interchain Security project.","sidebar":"tutorialSidebar"},"consumer-development/app-integration":{"id":"consumer-development/app-integration","title":"Developing an ICS consumer chain","description":"When developing an ICS consumer chain, besides just focusing on your chain\'s logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.","sidebar":"tutorialSidebar"},"consumer-development/consumer-chain-governance":{"id":"consumer-development/consumer-chain-governance","title":"Consumer Chain Governance","description":"Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the \\"Whitelist\\" section below.","sidebar":"tutorialSidebar"},"consumer-development/consumer-chain-upgrade-procedure":{"id":"consumer-development/consumer-chain-upgrade-procedure","title":"Upgrading Consumer Chains","description":"","sidebar":"tutorialSidebar"},"consumer-development/offboarding":{"id":"consumer-development/offboarding","title":"Offboarding Checklist","description":"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).","sidebar":"tutorialSidebar"},"consumer-development/onboarding":{"id":"consumer-development/onboarding","title":"Onboarding Checklist","description":"The following checklists will aid in onboarding a new consumer chain to replicated security.","sidebar":"tutorialSidebar"},"features/key-assignment":{"id":"features/key-assignment","title":"Key Assignment","description":"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.","sidebar":"tutorialSidebar"},"features/proposals":{"id":"features/proposals","title":"ICS Provider Proposals","description":"Interchain security module introduces 3 new proposal types to the provider.","sidebar":"tutorialSidebar"},"features/reward-distribution":{"id":"features/reward-distribution","title":"Reward distribution","description":"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.","sidebar":"tutorialSidebar"},"features/slashing":{"id":"features/slashing","title":"Consumer Initiated Slashing","description":"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.","sidebar":"tutorialSidebar"},"frequently-asked-questions":{"id":"frequently-asked-questions","title":"Frequently Asked Questions","description":"What is the meaning of Validator Set Replication?","sidebar":"tutorialSidebar"},"index":{"id":"index","title":"Interchain Security Docs","description":"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.","sidebar":"tutorialSidebar"},"introduction/overview":{"id":"introduction/overview","title":"Overview","description":"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.","sidebar":"tutorialSidebar"},"introduction/params":{"id":"introduction/params","title":"Interchain Security Parameters","description":"The parameters necessary for Interchain Security (ICS) are defined in","sidebar":"tutorialSidebar"},"introduction/technical-specification":{"id":"introduction/technical-specification","title":"Technical Specification","description":"For a technical deep dive into the replicated security protocol, see the specification.","sidebar":"tutorialSidebar"},"introduction/terminology":{"id":"introduction/terminology","title":"Terminology","description":"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.","sidebar":"tutorialSidebar"},"validators/joining-testnet":{"id":"validators/joining-testnet","title":"Joining Replicated Security testnet","description":"This short guide will teach you how to join the Replicated Security testnet.","sidebar":"tutorialSidebar"},"validators/overview":{"id":"validators/overview","title":"Overview","description":"We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.","sidebar":"tutorialSidebar"},"validators/withdraw_rewards":{"id":"validators/withdraw_rewards","title":"Withdrawing consumer chain validator rewards","description":"Here are example steps for withdrawing rewards from consumer chains in the provider chain","sidebar":"tutorialSidebar"}}}')}}]); \ No newline at end of file diff --git a/legacy/assets/js/6f71328c.b0a51530.js b/legacy/assets/js/6f71328c.b0a51530.js new file mode 100644 index 0000000000..7acffb8b7a --- /dev/null +++ b/legacy/assets/js/6f71328c.b0a51530.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8560],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>g});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),h=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=h(e.components);return o.createElement(l.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),c=h(n),u=a,g=c["".concat(l,".").concat(u)]||c[u]||p[u]||i;return n?o.createElement(g,r(r({ref:t},d),{},{components:n})):o.createElement(g,r({ref:t},d))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,r=new Array(i);r[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:a,r[1]=s;for(var h=2;h<i;h++)r[h]=n[h];return o.createElement.apply(null,r)}return o.createElement.apply(null,n)}u.displayName="MDXCreateElement"},9108:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>h});var o=n(7462),a=(n(7294),n(3905));const i={sidebar_position:14,title:"Slashing on the provider for consumer equivocation"},r="ADR 013: Slashing on the provider for consumer equivocation",s={unversionedId:"adrs/adr-013-equivocation-slashing",id:"adrs/adr-013-equivocation-slashing",title:"Slashing on the provider for consumer equivocation",description:"Changelog",source:"@site/docs/adrs/adr-013-equivocation-slashing.md",sourceDirName:"adrs",slug:"/adrs/adr-013-equivocation-slashing",permalink:"/interchain-security/legacy/adrs/adr-013-equivocation-slashing",draft:!1,tags:[],version:"current",sidebarPosition:14,frontMatter:{sidebar_position:14,title:"Slashing on the provider for consumer equivocation"},sidebar:"tutorialSidebar",previous:{title:"Separate Releasing",permalink:"/interchain-security/legacy/adrs/adr-012-separate-releasing"}},l={},h=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Single-chain slashing",id:"single-chain-slashing",level:3},{value:"Slashing undelegations and redelegations",id:"slashing-undelegations-and-redelegations",level:4},{value:"Slashing delegations",id:"slashing-delegations",level:4},{value:"Old evidence",id:"old-evidence",level:4},{value:"Slashing for equivocation on the consumer",id:"slashing-for-equivocation-on-the-consumer",level:3},{value:"Proposed solution",id:"proposed-solution",level:2},{value:"Implementation",id:"implementation",level:3},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}],d={toc:h},c="wrapper";function p(e){let{components:t,...n}=e;return(0,a.kt)(c,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-013-slashing-on-the-provider-for-consumer-equivocation"},"ADR 013: Slashing on the provider for consumer equivocation"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"1st Sept. 2023: Initial draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Proposed"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"This ADR presents some approaches on how to slash on the provider chain validators that performed equivocations on consumer chains.\nCurrently, the provider chain can ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232"},"receive and verify evidence of equivocation"),", but it cannot slash the misbehaving validator."),(0,a.kt)("p",null,"In the remainder of this section, we explain how slashing is performed on a single chain and show why slashing on the provider for equivocation on the consumer is challenging."),(0,a.kt)("p",null,"Note that future versions of the Cosmos SDK, CometBFT, and ibc-go could modify the way we slash, etc. Therefore, a future reader of this ADR, should note that when we refer to Cosmos SDK, CometBFT, and ibc-go we specifically refer to their ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/intro/overview"},"v0.47"),", ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cometbft.com/v0.37/"},"v0.37")," and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/v7.3.0"},"v7.3.0")," versions respectively."),(0,a.kt)("h3",{id:"single-chain-slashing"},"Single-chain slashing"),(0,a.kt)("p",null,"Slashing is implemented across the ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/slashing"},"slashing"),"\nand ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/staking"},"staking")," modules.\nThe slashing module's keeper calls the staking module's ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash()")," method, passing among others, the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," (i.e., the height when the equivocation occurred), the validator's ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," at the infraction height, and the ",(0,a.kt)("inlineCode",{parentName:"p"},"slashFactor")," (currently set to ",(0,a.kt)("inlineCode",{parentName:"p"},"5%")," in case of equivocation on the Cosmos Hub)."),(0,a.kt)("h4",{id:"slashing-undelegations-and-redelegations"},"Slashing undelegations and redelegations"),(0,a.kt)("p",null,"To slash undelegations, ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash")," goes through all undelegations and checks whether they started before or after the infraction occurred. If an undelegation started before the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight"),", then it is ",(0,a.kt)("strong",{parentName:"p"},"not")," slashed, otherwise it is slashed by ",(0,a.kt)("inlineCode",{parentName:"p"},"slashFactor"),"."),(0,a.kt)("p",null,"The slashing of redelegations happens in a similar way, meaning that ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash")," goes through all redelegations and checks whether the redelegations started before or after the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight"),"."),(0,a.kt)("h4",{id:"slashing-delegations"},"Slashing delegations"),(0,a.kt)("p",null,"Besides undelegations and redelegations, the validator's delegations need to also be slashed.\nThis is performed by deducting the appropriate amount of tokens from the validator. Note that this deduction is computed based on the voting ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," the misbehaving validator had at the height of the equivocation. As a result of the tokens deduction,\nthe ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/staking#delegator-shares"},"tokens per share"),"\nreduce and hence later on, when delegators undelegate or redelegate, the delegators retrieve back less\ntokens, effectively having their tokens slashed. The rationale behind this slashing mechanism, as mentioned in the ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/staking#delegator-shares"},"Cosmos SDK documentation")," "),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"[...]"," is to simplify the accounting around slashing. Rather than iteratively slashing the tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, effectively reducing the value of each issued delegator share.")),(0,a.kt)("p",null,"This approach of slashing delegations does not utilize the\n",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," in any way and hence the following scenario could occur:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"a validator ",(0,a.kt)("inlineCode",{parentName:"li"},"V")," performs an equivocation at a height ",(0,a.kt)("inlineCode",{parentName:"li"},"Hi")),(0,a.kt)("li",{parentName:"ol"},"a new delegator ",(0,a.kt)("inlineCode",{parentName:"li"},"D")," delegates to ",(0,a.kt)("inlineCode",{parentName:"li"},"V")," after height ",(0,a.kt)("inlineCode",{parentName:"li"},"Hi")),(0,a.kt)("li",{parentName:"ol"},"evidence of the equivocation by validator ",(0,a.kt)("inlineCode",{parentName:"li"},"V")," is received"),(0,a.kt)("li",{parentName:"ol"},"the tokens of delegator ",(0,a.kt)("inlineCode",{parentName:"li"},"D")," are slashed")),(0,a.kt)("p",null,"In the above scenario, delegator ",(0,a.kt)("inlineCode",{parentName:"p"},"D")," is slashed, even though ",(0,a.kt)("inlineCode",{parentName:"p"},"D"),"'s voting power did not contribute to the infraction. "),(0,a.kt)("h4",{id:"old-evidence"},"Old evidence"),(0,a.kt)("p",null,"In the single-chain case, old evidence (e.g., from 3 years ago) is ignored. This is achieved through\n",(0,a.kt)("a",{parentName:"p",href:"https://docs.cometbft.com/v0.37/spec/consensus/evidence"},"CometBFT")," that ignores old evidence based on the parameters ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeNumBlocks")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeDuration")," (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.37.0/evidence/pool.go#271"},"here"),").\nAdditionally, note that when the evidence is sent by CometBFT to the application, the evidence is rechecked in the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L54"},"evidence module")," of Cosmos SDK and if it is old, the evidence is ignored.\nIn Cosmos Hub, the ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeNumBlocks")," is set to 1000000 (i.e., ~70 days if we assume we need ~6 sec per block) and ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeDuration")," is set to 172800000000000 ns (i.e., 2 days). Because of this check, we can easily exclude old evidence."),(0,a.kt)("h3",{id:"slashing-for-equivocation-on-the-consumer"},"Slashing for equivocation on the consumer"),(0,a.kt)("p",null,"In the single-chain case, slashing requires both the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and the voting ",(0,a.kt)("inlineCode",{parentName:"p"},"power"),".\nIn order to slash on the provider for an equivocation on a consumer, we need to have both the provider's ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and voting ",(0,a.kt)("inlineCode",{parentName:"p"},"power"),".\nNote that the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," on the consumer chain must be mapped to a height on the provider chain.\nUnless we have a way to find the corresponding ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," on the provider chain, we cannot slash for equivocation on the consumer in the same way as we would slash in the single-chain case."),(0,a.kt)("p",null,"The challenge of figuring out the corresponding ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," values on the provider chain is due to the following trust assumption:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"We trust the consensus layer and validator set of the consumer chains, ",(0,a.kt)("em",{parentName:"li"},"but we do not trust the application layer"),".")),(0,a.kt)("p",null,"As a result, we cannot trust anything that stems from the ",(0,a.kt)("em",{parentName:"p"},"application state")," of a consumer chain."),(0,a.kt)("p",null,"Note that when a relayer or a user sends evidence through a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232"},"MsgSubmitConsumerDoubleVoting")," message, the provider gets access to ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.37.0/types/evidence.go#L35"},"DuplicateVoteEvidence"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-protobuf"},'type DuplicateVoteEvidence struct {\n VoteA *Vote `json:"vote_a"`\n VoteB *Vote `json:"vote_b"`\n\n // abci specific information\n TotalVotingPower int64\n ValidatorPower int64\n Timestamp time.Time\n}\n')),(0,a.kt)("p",null,'The "abci specific information" fields cannot be trusted because they are not signed. Therefore,\nwe can use neither ',(0,a.kt)("inlineCode",{parentName:"p"},"ValidatorPower")," for slashing on the provider chain, nor the ",(0,a.kt)("inlineCode",{parentName:"p"},"Timestamp")," to check the evidence age. We can get the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," from the votes, but this ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," corresponds to the infraction height on the consumer and ",(0,a.kt)("strong",{parentName:"p"},"not")," on the provider chain.\nSimilarly, when a relayer or a user sends evidence through a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/826"},"MsgSubmitConsumerMisbehaviour")," message, the provider gets access to ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/v7.3.0/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79"},"Misbehaviour")," that we cannot use to extract the infraction height, power, or the time on the provider chain."),(0,a.kt)("h2",{id:"proposed-solution"},"Proposed solution"),(0,a.kt)("p",null,"As a first iteration, we propose the following approach. At the moment the provider receives evidence of equivocation on a consumer:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"slash all the undelegations and redelegations using ",(0,a.kt)("inlineCode",{parentName:"li"},"slashFactor"),";"),(0,a.kt)("li",{parentName:"ol"},"slash all delegations using as voting ",(0,a.kt)("inlineCode",{parentName:"li"},"power")," the sum of the voting power of the misbehaving validator and the power of all the ongoing undelegations and redelegations.")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Evidence expiration:")," Additionally, because we cannot infer the actual time of the evidence (i.e., the timestamp of the evidence cannot be trusted), we do not consider ",(0,a.kt)("em",{parentName:"p"},"evidence expiration")," and hence old evidence is never ignored (e.g., the provider would act on 3 year-old evidence of equivocation on a consumer).\nAdditionally, we do not need to store equivocation evidence to avoid slashing a validator more than once, because we ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L94"},"do not slash")," tombstoned validators and we ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L138"},"tombstone")," a validator when slashed."),(0,a.kt)("p",null,"We do not act on evidence that was signed by a validator ",(0,a.kt)("a",{parentName:"p",href:"https://tutorials.cosmos.network/tutorials/9-path-to-prod/3-keys.html#what-validator-keys"},"consensus key")," that is ",(0,a.kt)("em",{parentName:"p"},"pruned")," when we receive the evidence. We prune a validator's consensus key if the validator has assigned a new consumer key (using ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey"),") and an unbonding period on the consumer chain has elapsed (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-001-key-assignment.md"},"key assignment ADR"),"). Note that the provider chain is informed that the unbonding period has elapsed on the consumer when the provider receives a ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCMaturedPacket")," and because of this, if the consumer delays the sending of a ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCMaturedPacket"),", we would delay the pruning of the key as well."),(0,a.kt)("h3",{id:"implementation"},"Implementation"),(0,a.kt)("p",null,"The following logic needs to be added to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232"},"HandleConsumerDoubleVoting")," and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/826"},"HandleConsumerMisbehaviour")," methods:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-go"},"undelegationsInTokens := sdk.NewInt(0)\nfor _, v := range k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validatorAddress) {\n for _, entry := range v.Entries {\n if entry.IsMature(now) && !entry.OnHold() {\n // undelegation no longer eligible for slashing, skip it\n continue\n }\n undelegationsInTokens = undelegationsInTokens.Add(entry.InitialBalance)\n }\n}\n\nredelegationsInTokens := sdk.NewInt(0)\nfor _, v := range k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validatorAddress) {\n for _, entry := range v.Entries {\n if entry.IsMature(now) && !entry.OnHold() {\n // redelegation no longer eligible for slashing, skip it\n continue\n }\n redelegationsInTokens = redelegationsInTokens.Add(entry.InitialBalance)\n }\n}\n\ninfractionHeight := 0\nundelegationsAndRedelegationsInPower = sdk.TokensToConsensusPower(undelegationsInTokens.Add(redelegationsInTokens))\ntotalPower := validator's voting power + undelegationsAndRedelegationsInPower\nslashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)\n\nk.stakingKeeper.Slash(ctx, validatorConsAddress, infractionHeight, totalPower, slashFraction, DoubleSign)\n")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Infraction height:")," We provide a zero ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L33"},"Slash")," method in order to slash all ongoing undelegations and redelegations (see checks in ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L92"},"Slash"),", ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L195"},"SlashUnbondingDelegation"),", and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L249"},"SlashRedelegation"),")."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Power:")," We pass the sum of the voting power of the misbehaving validator when the evidence was received (i.e., at evidence height) and the power of all the ongoing undelegations and redelegations.\nIf we assume that the ",(0,a.kt)("inlineCode",{parentName:"p"},"slashFactor")," is ",(0,a.kt)("inlineCode",{parentName:"p"},"5%"),", then the voting power we pass is ",(0,a.kt)("inlineCode",{parentName:"p"},"power + totalPower(undelegations) + totalPower(redelegations)"),".\nHence, when the ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash")," method slashes all the undelegations and redelegations it would end up with ",(0,a.kt)("inlineCode",{parentName:"p"},"0.05 * power + 0.05 * totalPower(undelegations) + 0.05 * totalPower(redelegations) - 0.05 * totalPower(undelegations) - 0.05 * totalPower(redelegations) = 0.05 * power")," and hence it would slash ",(0,a.kt)("inlineCode",{parentName:"p"},"5%")," of the validator's power when the evidence is received."),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("p",null,"With the proposed approach we can quickly implement slashing functionality on the provider chain for consumer chain equivocations.\nThis approach does not need to change the staking module and therefore does not change in any way how slashing is performed today for a single chain."),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"We ",(0,a.kt)("em",{parentName:"li"},"definitely")," slash more when it comes to undelegations and redelegations because we slash for all of them without considering an ",(0,a.kt)("inlineCode",{parentName:"li"},"infractionHeight"),"."),(0,a.kt)("li",{parentName:"ul"},"We ",(0,a.kt)("em",{parentName:"li"},"potentially")," slash more than what we would have slashed if we knew the voting ",(0,a.kt)("inlineCode",{parentName:"li"},"power")," at the corresponding ",(0,a.kt)("inlineCode",{parentName:"li"},"infractionHeight")," in the provider chain."),(0,a.kt)("li",{parentName:"ul"},"We slash on old evidence of equivocation on a consumer.")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md"},"ADR 005: Cryptographic verification of equivocation evidence")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/732"},"EPIC tracking cryptographic equivocation feature")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://forum.cosmos.network/t/cryptographic-equivocation-slashing-design/11400"},"Cosmos Hub Forum discussion on cryptographic equivocation slashing"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/70938a03.227a4d05.js b/legacy/assets/js/70938a03.227a4d05.js new file mode 100644 index 0000000000..bffe36f679 --- /dev/null +++ b/legacy/assets/js/70938a03.227a4d05.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5457],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>u});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(n),m=i,u=d["".concat(l,".").concat(m)]||d[m]||h[m]||o;return n?a.createElement(u,r(r({ref:t},p),{},{components:n})):a.createElement(u,r({ref:t},p))}));function u(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:i,r[1]=s;for(var c=2;c<o;c++)r[c]=n[c];return a.createElement.apply(null,r)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},8818:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var a=n(7462),i=(n(7294),n(3905));const o={sidebar_position:5},r="Changeover Procedure",s={unversionedId:"consumer-development/changeover-procedure",id:"consumer-development/changeover-procedure",title:"Changeover Procedure",description:"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.",source:"@site/docs/consumer-development/changeover-procedure.md",sourceDirName:"consumer-development",slug:"/consumer-development/changeover-procedure",permalink:"/interchain-security/legacy/consumer-development/changeover-procedure",draft:!1,tags:[],version:"current",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Offboarding Checklist",permalink:"/interchain-security/legacy/consumer-development/offboarding"},next:{title:"Consumer Genesis Transformation",permalink:"/interchain-security/legacy/consumer-development/consumer-genesis-transformation"}},l={},c=[{value:"Overview",id:"overview",level:2},{value:"1. ConsumerAddition proposal submitted to the <code>provider</code> chain",id:"1-consumeraddition-proposal-submitted-to-the-provider-chain",level:3},{value:"2. upgrade proposal on standalone chain",id:"2-upgrade-proposal-on-standalone-chain",level:3},{value:"3. spawn time is reached",id:"3-spawn-time-is-reached",level:3},{value:"4. standalone chain upgrade",id:"4-standalone-chain-upgrade",level:3},{value:"Notes",id:"notes",level:4},{value:"Onboarding Checklist",id:"onboarding-checklist",level:2},{value:"1. Complete testing & integration",id:"1-complete-testing--integration",level:2},{value:"2. Create an Onboarding Repository",id:"2-create-an-onboarding-repository",level:2},{value:"3. Submit a ConsumerChainAddition Governance Proposal to the provider",id:"3-submit-a-consumerchainaddition-governance-proposal-to-the-provider",level:2},{value:"3. Submit an Upgrade Proposal & Prepare for Changeover",id:"3-submit-an-upgrade-proposal--prepare-for-changeover",level:2},{value:"4. Upgrade time \ud83d\ude80",id:"4-upgrade-time-",level:2}],p={toc:c},d="wrapper";function h(e){let{components:t,...n}=e;return(0,i.kt)(d,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"changeover-procedure"},"Changeover Procedure"),(0,i.kt)("p",null,"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the ",(0,i.kt)("strong",{parentName:"p"},"changeover procedure")," and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain."),(0,i.kt)("p",null,"The relevant protocol specifications are available below:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md#channel-initialization-existing-chains"},"ICS-28 with existing chains"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/interchain-security/legacy/adrs/adr-010-standalone-changeover"},"ADR in ICS repo"))),(0,i.kt)("h2",{id:"overview"},"Overview"),(0,i.kt)("p",null,"Standalone to consumer changeover procedure can rougly be separated into 4 parts:"),(0,i.kt)("h3",{id:"1-consumeraddition-proposal-submitted-to-the-provider-chain"},"1. ConsumerAddition proposal submitted to the ",(0,i.kt)("inlineCode",{parentName:"h3"},"provider")," chain"),(0,i.kt)("p",null,'The proposal is equivalent to the "normal" ConsumerAddition proposal submitted by new consumer chains.'),(0,i.kt)("p",null,"However, here are the most important notes and differences between a new consumer chain and a standalone chain performing a changeover:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"chain_id")," must be equal to the standalone chain id"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"initial_height")," field has additional rules to abide by:")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre"},'{\n...\n "initial_height" : {\n // must correspond to current revision number of standalone chain\n // e.g. stride-1 => "revision_number": 1\n "revision_number": 1,\n\n // must correspond to a height that is at least 1 block after the upgrade\n // that will add the `consumer` module to the standalone chain\n // e.g. "upgrade_height": 100 => "revision_height": 101\n "revision_height": 1,\n },\n...\n}\n')),(0,i.kt)("p",{parentName:"admonition"},"RevisionNumber: 0, RevisionHeight: 111")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"genesis_hash")," can be safely ignored because the chain is already running. A hash of the standalone chain's initial genesis may be used")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"binary_hash")," may not be available ahead of time. All chains performing the changeover go through rigorous testing - if bugs are caught and fixed the hash listed in the proposal may not be the most recent one.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," listed in the proposal MUST be before the ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height")," listed in the the upgrade proposal on the standalone chain."),(0,i.kt)("admonition",{parentName:"li",type:"caution"},(0,i.kt)("p",{parentName:"admonition"},(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," must occur before the ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height")," on the standalone chain is reached because the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider")," chain must generate the ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerGenesis")," that contains the ",(0,i.kt)("strong",{parentName:"p"},"validator set")," that will be used after the changeover."))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"unbonding_period")," must correspond to the value used on the standalone chain. Otherwise, the clients used for the ccv protocol may be incorrectly initialized.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"distribution_transmission_channel")," ",(0,i.kt)("strong",{parentName:"p"},"should be set"),"."))),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"Populating ",(0,i.kt)("inlineCode",{parentName:"p"},"distribution_transmission_channel")," will enable the standalone chain to re-use one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ",(0,i.kt)("inlineCode",{parentName:"p"},"ibc denom")," that may already be in use."),(0,i.kt)("p",{parentName:"admonition"},"If the parameter is not set, a new channel will be created.")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"ccv_timeout_period")," has no important notes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"transfer_timeout_period")," has no important notes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction")," has no important notes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission")," has no important notes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"historical_entries")," has no important notes"))),(0,i.kt)("h3",{id:"2-upgrade-proposal-on-standalone-chain"},"2. upgrade proposal on standalone chain"),(0,i.kt)("p",null,"The standalone chain creates an upgrade proposal to include the ",(0,i.kt)("inlineCode",{parentName:"p"},"interchain-security/x/ccv/consumer")," module."),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"The upgrade height in the proposal should correspond to a height that is after the ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," in the consumer addition proposal submitted to the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider")," chain.")),(0,i.kt)("p",null,"Otherwise, the upgrade is indistinguishable from a regular on-chain upgrade proposal."),(0,i.kt)("h3",{id:"3-spawn-time-is-reached"},"3. spawn time is reached"),(0,i.kt)("p",null,"When the ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," is reached on the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider")," it will generate a ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerGenesis")," that contains the validator set that will supercede the ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," validator set."),(0,i.kt)("p",null,"This ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerGenesis")," must be available on the standalone chain during the on-chain upgrade."),(0,i.kt)("h3",{id:"4-standalone-chain-upgrade"},"4. standalone chain upgrade"),(0,i.kt)("p",null,"Performing the on-chain upgrade on the standalone chain will add the ",(0,i.kt)("inlineCode",{parentName:"p"},"ccv/consumer")," module and allow the chain to become a ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer")," of replicated security."),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerGenesis")," must be exported to a file and placed in the correct folder on the standalone chain before the upgade."),(0,i.kt)("p",{parentName:"admonition"},"The file must be placed at the exact specified location, otherwise the upgrade will not be executed correctly."),(0,i.kt)("p",{parentName:"admonition"},"Usually the file is placed in ",(0,i.kt)("inlineCode",{parentName:"p"},"$NODE_HOME/config"),", but the file name and the exact directory is dictated by the upgrade code on the ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," chain."),(0,i.kt)("ul",{parentName:"admonition"},(0,i.kt)("li",{parentName:"ul"},"please check exact instructions provided by the ",(0,i.kt)("inlineCode",{parentName:"li"},"standalone")," chain team"))),(0,i.kt)("p",null,"After the ",(0,i.kt)("inlineCode",{parentName:"p"},"genesis.json")," file has been made available, the process is equivalent to a normal on-chain upgrade. The standalone validator set will sign the next couple of blocks before transferring control to ",(0,i.kt)("inlineCode",{parentName:"p"},"provider")," validator set."),(0,i.kt)("p",null,"The standalone validator set can still be slashed for any infractions if evidence is submitted within the ",(0,i.kt)("inlineCode",{parentName:"p"},"unboding_period"),"."),(0,i.kt)("h4",{id:"notes"},"Notes"),(0,i.kt)("p",null,"The changeover procedure may be updated in the future to create a seamless way of providing the validator set information to the standalone chain."),(0,i.kt)("h2",{id:"onboarding-checklist"},"Onboarding Checklist"),(0,i.kt)("p",null,"This onboarding checklist is slightly different from the one under ",(0,i.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/onboarding"},"Onboarding")),(0,i.kt)("p",null,"Additionally, you can check the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md"},"testnet repo")," for a comprehensive guide on preparing and launching consumer chains."),(0,i.kt)("h2",{id:"1-complete-testing--integration"},"1. Complete testing & integration"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test integration with gaia"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test your protocol with supported relayer versions (minimum hermes 1.4.1)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test the changeover procedure"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","reach out to the ICS team if you are facing issues")),(0,i.kt)("h2",{id:"2-create-an-onboarding-repository"},"2. Create an Onboarding Repository"),(0,i.kt)("p",null,"To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain."),(0,i.kt)("p",null,"This should include (at minimum):"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see ",(0,i.kt)("a",{parentName:"li",href:"/interchain-security/legacy/consumer-development/consumer-genesis-transformation"},"Transform Consumer Genesis"),")"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","information about relevant seed/peer nodes you are running"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","relayer information (compatible versions)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","copy of your governance proposal (as JSON)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","a script showing how to start your chain and connect to peers (optional)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable")),(0,i.kt)("p",null,"Example of such a repository can be found ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyphacoop/ics-testnets/tree/main/game-of-chains-2022/sputnik"},"here"),"."),(0,i.kt)("h2",{id:"3-submit-a-consumerchainaddition-governance-proposal-to-the-provider"},"3. Submit a ConsumerChainAddition Governance Proposal to the provider"),(0,i.kt)("p",null,"Before you submit a ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerChainAddition")," proposal, please provide a ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," that is ",(0,i.kt)("strong",{parentName:"p"},"before")," the the ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height")," of the upgrade that will introduce the ",(0,i.kt)("inlineCode",{parentName:"p"},"ccv module")," to your chain."),(0,i.kt)("admonition",{type:"danger"},(0,i.kt)("p",{parentName:"admonition"},"If the ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," happens after your ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height")," the provider will not be able to communicate the new validator set to be used after the changeover.")),(0,i.kt)("p",null,"Additionally, reach out to the community via the ",(0,i.kt)("a",{parentName:"p",href:"https://forum.cosmos.network/"},"forum")," to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine your chain's spawn time"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine consumer chain parameters to be put in the proposal"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take note to include a link to your onboarding repository")),(0,i.kt)("p",null,"Example of a consumer chain addition proposal."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},'// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain or add a standalone chain.\n// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.\n// It is recommended that spawn time occurs after the proposal end time and that it is scheduled to happen before the standalone chain upgrade\n// that sill introduce the ccv module.\n{\n // Title of the proposal\n "title": "Changeover Standalone chain",\n // Description of the proposal\n // format the text as a .md file and include the file in your onboarding repository\n "description": ".md description of your chain and all other relevant information",\n // Proposed chain-id of the new consumer chain.\n // Must be unique from all other consumer chain ids of the executing provider chain.\n "chain_id": "standalone-1",\n // Initial height of new consumer chain.\n // For a completely new chain, this will be {0,1}.\n "initial_height" : {\n // must correspond to current revision number of standalone chain\n // e.g. standalone-1 => "revision_number": 1\n "revision_number": 1,\n\n // must correspond to a height that is at least 1 block after the upgrade\n // that will add the `consumer` module to the standalone chain\n // e.g. "upgrade_height": 100 => "revision_height": 101\n "revision_number": 1,\n },\n // Hash of the consumer chain genesis state without the consumer CCV module genesis params.\n // => not relevant for changeover procedure\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n // Hash of the consumer chain binary that should be run by validators on standalone chain upgrade\n // => not relevant for changeover procedure as it may become stale\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n // Unbonding period for the consumer chain.\n // It should should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n // IBC transfer packets will timeout after this interval elapses.\n "transfer_timeout_period": 1800000000000,\n // The fraction of tokens allocated to the consumer redistribution address during distribution events.\n // The fraction is a string representing a decimal number. For example "0.75" would represent 75%.\n // The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.\n "consumer_redistribution_fraction": "0.75",\n // BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.\n // eg. send rewards to the provider every 1000 blocks\n "blocks_per_distribution_transmission": 1000,\n // The number of historical info entries to persist in store.\n // This param is a part of the cosmos sdk staking module. In the case of\n // a ccv enabled consumer chain, the ccv module acts as the staking module.\n "historical_entries": 10000,\n // The ID of a token transfer channel used for the Reward Distribution\n // sub-protocol. If DistributionTransmissionChannel == "", a new transfer\n // channel is created on top of the same connection as the CCV channel.\n // Note that transfer_channel_id is the ID of the channel end on the consumer chain.\n // it is most relevant for chains performing a standalone to consumer changeover\n // in order to maintan the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123" // NOTE: use existing transfer channel if available\n}\n')),(0,i.kt)("h2",{id:"3-submit-an-upgrade-proposal--prepare-for-changeover"},"3. Submit an Upgrade Proposal & Prepare for Changeover"),(0,i.kt)("p",null,"This proposal should add the ccv ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer")," module to your chain."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","proposal ",(0,i.kt)("inlineCode",{parentName:"li"},"upgrade_height")," must happen after ",(0,i.kt)("inlineCode",{parentName:"li"},"spawn_time")," in the ",(0,i.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal")),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","advise validators about the exact procedure for your chain and point them to your onboarding repository")),(0,i.kt)("h2",{id:"4-upgrade-time-"},"4. Upgrade time \ud83d\ude80"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","after ",(0,i.kt)("inlineCode",{parentName:"li"},"spawn_time"),", request ",(0,i.kt)("inlineCode",{parentName:"li"},"ConsumerGenesis")," from the ",(0,i.kt)("inlineCode",{parentName:"li"},"provider")," and place it in ",(0,i.kt)("inlineCode",{parentName:"li"},"<CURRENT_USER_HOME_DIR>/.sovereign/config/genesis.json")),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","upgrade the binary to the one listed in your ",(0,i.kt)("inlineCode",{parentName:"li"},"UpgradeProposal"))),(0,i.kt)("p",null,'The chain starts after at least 66.67% of standalone voting power comes online. The consumer chain is considered interchain secured once the "old" validator set signs a couple of blocks and transfers control to the ',(0,i.kt)("inlineCode",{parentName:"p"},"provider")," validator set."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","provide a repo with onboarding instructions for validators (it should already be listed in the proposal)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json after ",(0,i.kt)("inlineCode",{parentName:"li"},"spawn_time")," obtained from ",(0,i.kt)("inlineCode",{parentName:"li"},"provider")," (MUST contain the initial validator set)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/75331c0b.8235ad0a.js b/legacy/assets/js/75331c0b.8235ad0a.js new file mode 100644 index 0000000000..ebfb0d42da --- /dev/null +++ b/legacy/assets/js/75331c0b.8235ad0a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2745],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=p(n),m=r,h=d["".concat(s,".").concat(m)]||d[m]||c[m]||i;return n?a.createElement(h,o(o({ref:t},u),{},{components:n})):a.createElement(h,o({ref:t},u))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:r,o[1]=l;for(var p=2;p<i;p++)o[p]=n[p];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},9305:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=n(7462),r=(n(7294),n(3905));const i={sidebar_position:13,title:"Separate Releasing"},o="ADR 012: Separate Releasing",l={unversionedId:"adrs/adr-012-separate-releasing",id:"version-v3.3.0/adrs/adr-012-separate-releasing",title:"Separate Releasing",description:"Changelog",source:"@site/versioned_docs/version-v3.3.0/adrs/adr-012-separate-releasing.md",sourceDirName:"adrs",slug:"/adrs/adr-012-separate-releasing",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-012-separate-releasing",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:13,frontMatter:{sidebar_position:13,title:"Separate Releasing"},sidebar:"tutorialSidebar",previous:{title:"Improving testing and increasing confidence",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-011-improving-test-confidence"},next:{title:"Slashing on the provider for consumer equivocation",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-013-equivocation-slashing"}},s={},p=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Spike results",id:"spike-results",level:3},{value:"Why go.mod split is not the way to go",id:"why-gomod-split-is-not-the-way-to-go",level:3},{value:"Why separate repos is cool but also not the way to go",id:"why-separate-repos-is-cool-but-also-not-the-way-to-go",level:3},{value:"Decision",id:"decision",level:2},{value:"Example release flow",id:"example-release-flow",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],u={toc:p},d="wrapper";function c(e){let{components:t,...n}=e;return(0,r.kt)(d,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"adr-012-separate-releasing"},"ADR 012: Separate Releasing"),(0,r.kt)("h2",{id:"changelog"},"Changelog"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"{8/18/22}: Initial draft of idea in ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/801"},"#801")),(0,r.kt)("li",{parentName:"ul"},"{8/22/22}: Put idea in this ADR"),(0,r.kt)("li",{parentName:"ul"},"{11/10/22}: Reject this ADR")),(0,r.kt)("h2",{id:"status"},"Status"),(0,r.kt)("p",null,"Rejected"),(0,r.kt)("h2",{id:"context"},"Context"),(0,r.kt)("h3",{id:"spike-results"},"Spike results"),(0,r.kt)("p",null,"I explored the idea of ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/issues/801"},"#801")," with this ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/shawn%2Fgo-mod-split-aug-spike"},"spike branch"),". Here's my conclusions:"),(0,r.kt)("p",null,"Splitting this repo to have multiple go.mods is possible. However there are various intricacies involved in decoupling the package hierarchy to have ",(0,r.kt)("inlineCode",{parentName:"p"},"x/ccv/types")," as the lowest level dep, with ",(0,r.kt)("inlineCode",{parentName:"p"},"x/ccv/consumer")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"x/ccv/provider")," being one dep layer above, with high-level tests depending on all three of the mentioned packages. I'd estimate this decoupling would take 2-5 workdays to finish, and require significant review effort."),(0,r.kt)("h3",{id:"why-gomod-split-is-not-the-way-to-go"},"Why go.mod split is not the way to go"),(0,r.kt)("p",null,"Let's take a step back and remember the issue we're trying to solve - ",(0,r.kt)("strong",{parentName:"p"},"We need a clean way to decouple semver/releasing for the consumer and provider modules"),". After more consideration, splitting up go.mods gives us little benefit in achieving this. Reasons:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"go.mod")," dependency system is tied to git tags for the entire repo (ex: ",(0,r.kt)("inlineCode",{parentName:"li"},"require github.com/cometbft/cometbft v0.37.2")," refers to a historical tag for the entire cometbft repo)."),(0,r.kt)("li",{parentName:"ul"},"It'd be an odd dev experience to allow modules to reference past releases of other modules in the same repo. When would we ever want the consumer module to reference a past release of the types module for example?"),(0,r.kt)("li",{parentName:"ul"},"If we allow for ",(0,r.kt)("inlineCode",{parentName:"li"},"go.mod")," replace statements to build from local source code, why split up the package deps at all?"),(0,r.kt)("li",{parentName:"ul"},"Splitting go.mods adds a bunch of complexity with ",(0,r.kt)("inlineCode",{parentName:"li"},"go.work")," files and all that shiz. VSCode does not play well with multiple module repos either.")),(0,r.kt)("h3",{id:"why-separate-repos-is-cool-but-also-not-the-way-to-go"},"Why separate repos is cool but also not the way to go"),(0,r.kt)("p",null,"All this considered, the cleanest solution to decoupling semver/releasing for the consumer and provider modules would be to have multiple repos, each with their own go.mod (3-4 repos total including high level tests). With this scheme we could separately tag each repo as changes are merged, they could share some code from ",(0,r.kt)("inlineCode",{parentName:"p"},"types")," being an external dep, etc."),(0,r.kt)("p",null,"I don't think any of us want to split up the monorepo, that's a lot of work and seems like bikeshedding. There's another solution that's very simple.. "),(0,r.kt)("h2",{id:"decision"},"Decision"),(0,r.kt)("p",null,"Slightly adapting ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/cca008d856e3ffc60ec1a486871d0faa702abe26/CONTRIBUTING.md#semantic-versioning"},"the current semver ruleset"),":"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"A library API breaking change to EITHER the provider or consumer module will result in an increase of the MAJOR version number for BOTH modules (X.y.z-provider AND X.y.z-consumer)."),(0,r.kt)("li",{parentName:"ul"},"A state breaking change (change requiring coordinated upgrade and/or state migration) will result in an increase of the MINOR version number for the AFFECTED module(s) (x.Y.z-provider AND/OR x.Y.z-consumer)."),(0,r.kt)("li",{parentName:"ul"},"Any other changes (including node API breaking changes) will result in an increase of the PATCH version number for the AFFECTED module(s) (x.y.Z-provider AND/OR x.y.Z-consumer).")),(0,r.kt)("h3",{id:"example-release-flow"},"Example release flow"),(0,r.kt)("p",null,"We upgrade ",(0,r.kt)("inlineCode",{parentName:"p"},"main")," to use a new version of SDK. This is a major version bump, triggering a new release for both the provider and consumer modules, ",(0,r.kt)("inlineCode",{parentName:"p"},"v5.0.0-provider")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"v5.0.0-consumer"),"."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"A state breaking change is merged to ",(0,r.kt)("inlineCode",{parentName:"li"},"main")," for the provider module. We release only a ",(0,r.kt)("inlineCode",{parentName:"li"},"v5.1.0-provider")," off main."),(0,r.kt)("li",{parentName:"ul"},"Another state breaking change is merged to ",(0,r.kt)("inlineCode",{parentName:"li"},"main")," for the provider module. We release only a ",(0,r.kt)("inlineCode",{parentName:"li"},"v5.2.0-provider")," off main."),(0,r.kt)("li",{parentName:"ul"},"At this point, the latest consumer version is still ",(0,r.kt)("inlineCode",{parentName:"li"},"v5.0.0-consumer"),". We now merge a state breaking change for the consumer module to ",(0,r.kt)("inlineCode",{parentName:"li"},"main"),", and consequently release ",(0,r.kt)("inlineCode",{parentName:"li"},"v5.1.0-consumer"),". Note that ",(0,r.kt)("inlineCode",{parentName:"li"},"v5.1.0-consumer")," is tagged off a LATER commit from main than ",(0,r.kt)("inlineCode",{parentName:"li"},"v5.2.0-provider"),". This is fine, as the consumer module should not be affected by the provider module's state breaking changes."),(0,r.kt)("li",{parentName:"ul"},"Once either module sees a library API breaking change, we bump the major version for both modules. For example, we merge a library API breaking change to ",(0,r.kt)("inlineCode",{parentName:"li"},"main")," for the provider module. We release ",(0,r.kt)("inlineCode",{parentName:"li"},"v6.0.0-provider")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"v6.0.0-consumer")," off main. Note that most often, a library API breaking change will affect both modules simultaneously (example being bumping sdk version).")),(0,r.kt)("h2",{id:"consequences"},"Consequences"),(0,r.kt)("h3",{id:"positive"},"Positive"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Consumer repos have clear communication of what tagged versions are relevant to them. Consumer devs should know to never reference an ICS version that starts with ",(0,r.kt)("inlineCode",{parentName:"li"},"provider"),", even if it'd technically build."),(0,r.kt)("li",{parentName:"ul"},"Consumer and provider modules do not deviate as long as we continually release off a shared main branch. Backporting remains relatively unchanged besides being explicit about what module(s) your changes should affect."),(0,r.kt)("li",{parentName:"ul"},"No code changes, just changes in process. Very simple.")),(0,r.kt)("h3",{id:"negative"},"Negative"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("del",{parentName:"li"},"Slightly more complexity."),"Considerably more complex to manage the ICS library.\nThis is because ICS needs to support multiple versions of SDK (e.g., 0.45, 0.47, 0.50).\nIn addition, ICS needs to support a special fork of SDK (with LSM included) for the Cosmos Hub.\nThis means that instead of focusing on main the development team needs to manage multiple release\nbranches with different dependency trees. "),(0,r.kt)("li",{parentName:"ul"},"This solution does not allow having provider and consumer on separate versions of e.g. the Cosmos SDK.")),(0,r.kt)("h3",{id:"neutral"},"Neutral"),(0,r.kt)("h2",{id:"references"},"References"),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/801"},"#801")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/801#issuecomment-1683349298"},"#801 comment"))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/758625d4.273190c7.js b/legacy/assets/js/758625d4.273190c7.js new file mode 100644 index 0000000000..0c378e2df4 --- /dev/null +++ b/legacy/assets/js/758625d4.273190c7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[321],{3905:(e,r,t)=>{t.d(r,{Zo:()=>c,kt:()=>w});var a=t(7294);function n(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);r&&(a=a.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?i(Object(t),!0).forEach((function(r){n(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function s(e,r){if(null==e)return{};var t,a,n=function(e,r){if(null==e)return{};var t,a,n={},i=Object.keys(e);for(a=0;a<i.length;a++)t=i[a],r.indexOf(t)>=0||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)t=i[a],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(n[t]=e[t])}return n}var l=a.createContext({}),d=function(e){var r=a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):o(o({},r),e)),t},c=function(e){var r=d(e.components);return a.createElement(l.Provider,{value:r},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var r=e.children;return a.createElement(a.Fragment,{},r)}},u=a.forwardRef((function(e,r){var t=e.components,n=e.mdxType,i=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=d(t),u=n,w=p["".concat(l,".").concat(u)]||p[u]||m[u]||i;return t?a.createElement(w,o(o({ref:r},c),{},{components:t})):a.createElement(w,o({ref:r},c))}));function w(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var i=t.length,o=new Array(i);o[0]=u;var s={};for(var l in r)hasOwnProperty.call(r,l)&&(s[l]=r[l]);s.originalType=e,s[p]="string"==typeof e?e:n,o[1]=s;for(var d=2;d<i;d++)o[d]=t[d];return a.createElement.apply(null,o)}return a.createElement.apply(null,t)}u.displayName="MDXCreateElement"},4142:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>l,contentTitle:()=>o,default:()=>m,frontMatter:()=>i,metadata:()=>s,toc:()=>d});var a=t(7462),n=(t(7294),t(3905));const i={sidebar_position:3},o="Withdrawing consumer chain validator rewards",s={unversionedId:"validators/withdraw_rewards",id:"validators/withdraw_rewards",title:"Withdrawing consumer chain validator rewards",description:"Here are example steps for withdrawing rewards from consumer chains in the provider chain",source:"@site/docs/validators/withdraw_rewards.md",sourceDirName:"validators",slug:"/validators/withdraw_rewards",permalink:"/interchain-security/legacy/validators/withdraw_rewards",draft:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Joining Replicated Security testnet",permalink:"/interchain-security/legacy/validators/joining-testnet"},next:{title:"Validator instructions for Changeover Procedure",permalink:"/interchain-security/legacy/validators/changeover-procedure"}},l={},d=[{value:"Querying validator rewards",id:"querying-validator-rewards",level:2},{value:"Withdrawing rewards and commission",id:"withdrawing-rewards-and-commission",level:2},{value:"1. Withdraw rewards",id:"1-withdraw-rewards",level:3},{value:"2. Confirm withdrawal",id:"2-confirm-withdrawal",level:3}],c={toc:d},p="wrapper";function m(e){let{components:r,...t}=e;return(0,n.kt)(p,(0,a.Z)({},c,t,{components:r,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"withdrawing-consumer-chain-validator-rewards"},"Withdrawing consumer chain validator rewards"),(0,n.kt)("p",null,"Here are example steps for withdrawing rewards from consumer chains in the provider chain"),(0,n.kt)("admonition",{type:"info"},(0,n.kt)("p",{parentName:"admonition"},"The examples used are from ",(0,n.kt)("inlineCode",{parentName:"p"},"rs-testnet"),", the replicated security persistent testnet."),(0,n.kt)("p",{parentName:"admonition"},"Validator operator address: ",(0,n.kt)("inlineCode",{parentName:"p"},"cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6"),"\nSelf-delegation address: ",(0,n.kt)("inlineCode",{parentName:"p"},"cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf"))),(0,n.kt)("p",null,"Prior to withdrawing rewards, query balances for self-delegation address:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "1000000000000"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n')),(0,n.kt)("h2",{id:"querying-validator-rewards"},"Querying validator rewards"),(0,n.kt)("p",null,"Query rewards for the validator address:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6\n\nrewards:\n- amount: "158.069895000000000000"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "841842390516.072526500000000000"\n denom: uatom\n')),(0,n.kt)("p",null,"The ",(0,n.kt)("inlineCode",{parentName:"p"},"ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD")," denom represents rewards from a consumer chain."),(0,n.kt)("h2",{id:"withdrawing-rewards-and-commission"},"Withdrawing rewards and commission"),(0,n.kt)("h3",{id:"1-withdraw-rewards"},"1. Withdraw rewards"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y\n\ntxhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A\n")),(0,n.kt)("h3",{id:"2-confirm-withdrawal"},"2. Confirm withdrawal"),(0,n.kt)("p",null,"After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "216"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "2233766225342"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/7616f23a.fe758987.js b/legacy/assets/js/7616f23a.fe758987.js new file mode 100644 index 0000000000..24a6de820e --- /dev/null +++ b/legacy/assets/js/7616f23a.fe758987.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2247],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function c(e,t){if(null==e)return{};var n,o,r=function(e,t){if(null==e)return{};var n,o,r={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=o.createContext({}),l=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},d=function(e){var t=l(e.components);return o.createElement(s.Provider,{value:t},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=c(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,m=u["".concat(s,".").concat(h)]||u[h]||p[h]||i;return n?o.createElement(m,a(a({ref:t},d),{},{components:n})):o.createElement(m,a({ref:t},d))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=h;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[u]="string"==typeof e?e:r,a[1]=c;for(var l=2;l<i;l++)a[l]=n[l];return o.createElement.apply(null,a)}return o.createElement.apply(null,n)}h.displayName="MDXCreateElement"},770:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>p,frontMatter:()=>i,metadata:()=>c,toc:()=>l});var o=n(7462),r=(n(7294),n(3905));const i={sidebar_position:1},a="Overview",c={unversionedId:"introduction/overview",id:"introduction/overview",title:"Overview",description:"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.",source:"@site/docs/introduction/overview.md",sourceDirName:"introduction",slug:"/introduction/overview",permalink:"/interchain-security/legacy/introduction/overview",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Docs",permalink:"/interchain-security/legacy/"},next:{title:"Terminology",permalink:"/interchain-security/legacy/introduction/terminology"}},s={},l=[{value:"Why Replicated Security?",id:"why-replicated-security",level:2},{value:"Core protocol",id:"core-protocol",level:2},{value:"Downtime Slashing",id:"downtime-slashing",level:3},{value:"Equivocation (Double Sign) Slashing",id:"equivocation-double-sign-slashing",level:3},{value:"Tokenomics and Rewards",id:"tokenomics-and-rewards",level:3}],d={toc:l},u="wrapper";function p(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"overview"},"Overview"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another."),(0,r.kt)("br",null),'Replicated security allows anyone to launch a "consumer" blockchain using the same validator set as the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit the full security and decentralization of the provider.'),(0,r.kt)("h2",{id:"why-replicated-security"},"Why Replicated Security?"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Full provider security. At launch, consumer chains are secured by the full validator set and market cap of the provider chain."),(0,r.kt)("li",{parentName:"ul"},"Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum."),(0,r.kt)("li",{parentName:"ul"},"Projects keep majority of gas fees. Depending on configuration, these fees either go to the project\u2019s community DAO, or can be used in the protocol in other ways."),(0,r.kt)("li",{parentName:"ul"},"No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. A governance vote will take place for a chain to get adopted by the provider validators which will encourage participation and signal strong buy-in into the project's long-term success."),(0,r.kt)("li",{parentName:"ul"},"Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set.")),(0,r.kt)("h2",{id:"core-protocol"},"Core protocol"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Protocol specification is available as ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md"},"ICS-028")," in the IBC repository.")),(0,r.kt)("p",null,"Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer."),(0,r.kt)("p",null,"To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider."),(0,r.kt)("h3",{id:"downtime-slashing"},"Downtime Slashing"),(0,r.kt)("p",null,"If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period."),(0,r.kt)("h3",{id:"equivocation-double-sign-slashing"},"Equivocation (Double Sign) Slashing"),(0,r.kt)("p",null,"Evidence of equivocation must be submitted to provider governance and be voted on. This behavior is an extra safeguard before a validator is slashed, and may be replaced by a more automated system in the future."),(0,r.kt)("h3",{id:"tokenomics-and-rewards"},"Tokenomics and Rewards"),(0,r.kt)("p",null,"Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/7670b92c.94ffb81a.js b/legacy/assets/js/7670b92c.94ffb81a.js new file mode 100644 index 0000000000..fbe90be97f --- /dev/null +++ b/legacy/assets/js/7670b92c.94ffb81a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9552],{3905:(e,n,t)=>{t.d(n,{Zo:()=>d,kt:()=>h});var o=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?r(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):r(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,o,a=function(e,n){if(null==e)return{};var t,o,a={},r=Object.keys(e);for(o=0;o<r.length;o++)t=r[o],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o<r.length;o++)t=r[o],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=o.createContext({}),p=function(e){var n=o.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},d=function(e){var n=p(e.components);return o.createElement(l.Provider,{value:n},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},m=o.forwardRef((function(e,n){var t=e.components,a=e.mdxType,r=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),c=p(t),m=a,h=c["".concat(l,".").concat(m)]||c[m]||u[m]||r;return t?o.createElement(h,i(i({ref:n},d),{},{components:t})):o.createElement(h,i({ref:n},d))}));function h(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var r=t.length,i=new Array(r);i[0]=m;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[c]="string"==typeof e?e:a,i[1]=s;for(var p=2;p<r;p++)i[p]=t[p];return o.createElement.apply(null,i)}return o.createElement.apply(null,t)}m.displayName="MDXCreateElement"},3413:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>r,metadata:()=>s,toc:()=>p});var o=t(7462),a=(t(7294),t(3905));const r={sidebar_position:3},i="ICS Provider Proposals",s={unversionedId:"features/proposals",id:"version-v3.2.0/features/proposals",title:"ICS Provider Proposals",description:"Interchain security module introduces 3 new proposal types to the provider.",source:"@site/versioned_docs/version-v3.2.0/features/proposals.md",sourceDirName:"features",slug:"/features/proposals",permalink:"/interchain-security/legacy/v3.2.0/features/proposals",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Reward distribution",permalink:"/interchain-security/legacy/v3.2.0/features/reward-distribution"},next:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/legacy/v3.2.0/features/slashing"}},l={},p=[{value:"<code>ConsumerAdditionProposal</code>",id:"consumeradditionproposal",level:2},{value:"<code>ConsumerRemovalProposal</code>",id:"consumerremovalproposal",level:2},{value:"<code>EquivocationProposal</code>",id:"equivocationproposal",level:2},{value:"ChangeRewardDenomProposal",id:"changerewarddenomproposal",level:2},{value:"Notes",id:"notes",level:3},{value:"Gaia example:",id:"gaia-example",level:3}],d={toc:p},c="wrapper";function u(e){let{components:n,...t}=e;return(0,a.kt)(c,(0,o.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"ics-provider-proposals"},"ICS Provider Proposals"),(0,a.kt)("p",null,"Interchain security module introduces 3 new proposal types to the provider."),(0,a.kt)("p",null,"The proposals are used to propose upcoming interchain security events through governance."),(0,a.kt)("h2",{id:"consumeradditionproposal"},(0,a.kt)("inlineCode",{parentName:"h2"},"ConsumerAdditionProposal")),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"If you are preparing a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," you can find more information in the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.2.0/consumer-development/onboarding"},"consumer onboarding checklist"),".")),(0,a.kt)("p",null,"Proposal type used to suggest adding a new consumer chain."),(0,a.kt)("p",null,"When proposals of this type are passed and the ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain."),(0,a.kt)("p",null,"Minimal example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'{\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n "title": "Add consumer chain",\n "description": ".md description of your chain and all other relevant information",\n "chain_id": "newchain-1",\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Unbonding period for the consumer chain.\n // It should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n "transfer_timeout_period": 1800000000000,\n "consumer_redistribution_fraction": "0.75",\n "blocks_per_distribution_transmission": 1000,\n "historical_entries": 10000,\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1"\n // relevant for chains performing a sovereign to consumer changeover\n // in order to maintain the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123"\n}\n')),(0,a.kt)("p",null,"More examples can be found in the replicated security testnet repository ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/stopped/baryon-1/proposal-baryon-1.json"},"here")," and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/stopped/noble-1/start-proposal-noble-1.json"},"here"),"."),(0,a.kt)("h2",{id:"consumerremovalproposal"},(0,a.kt)("inlineCode",{parentName:"h2"},"ConsumerRemovalProposal")),(0,a.kt)("p",null,"Proposal type used to suggest removing an existing consumer chain."),(0,a.kt)("p",null,"When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain.\nAfter the consumer chain removal, the chain in question will no longer be secured by the provider's validator set."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain.\nAdditional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set.\nMore information will be made available in the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.2.0/consumer-development/offboarding"},"Consumer Offboarding Checklist"),".")),(0,a.kt)("p",null,"Minimal example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'{\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details"\n}\n')),(0,a.kt)("h2",{id:"equivocationproposal"},(0,a.kt)("inlineCode",{parentName:"h2"},"EquivocationProposal")),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},(0,a.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," will only be accepted on the provider chain if at least one of the consumer chains submits equivocation evidence to the provider.\nSending equivocation evidence to the provider is handled automatically by the interchain security protocol when an equivocation infraction is detected on the consumer chain.")),(0,a.kt)("p",null,"Proposal type used to suggest slashing a validator for double signing on consumer chain.\nWhen proposals of this type are passed, the validator in question will be slashed for equivocation on the provider chain."),(0,a.kt)("admonition",{type:"warning"},(0,a.kt)("p",{parentName:"admonition"},"Take note that an equivocation slash causes a validator to be tombstoned (can never re-enter the active set).\nTombstoning a validator on the provider chain will remove the validator from the validator set of all consumer chains.")),(0,a.kt)("p",null,"Minimal example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'{\n "title": "Validator-1 double signed on consumerchain-1",\n "description": "Here is more information about the infraction so you can verify it yourself",\n // the list of equivocations that will be processed\n "equivocations": [\n {\n "height": 14444680,\n "time": "2023-02-28T20:40:00.000000Z",\n "power": 5500000,\n "consensus_address": "<consensus address ON THE PROVIDER>"\n }\n ]\n}\n')),(0,a.kt)("h2",{id:"changerewarddenomproposal"},"ChangeRewardDenomProposal"),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},(0,a.kt)("inlineCode",{parentName:"p"},"ChangeRewardDenomProposal")," will only be accepted on the provider chain if at least one of the denomsToAdd or denomsToRemove fields is populated with at least one denom. Also, a denom cannot be repeated in both sets.")),(0,a.kt)("p",null,"Proposal type used to mutate the set of denoms accepted by the provider as rewards."),(0,a.kt)("p",null,"Minimal example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'{\n "title": "Add untrn as a reward denom",\n "description": "Here is more information about the proposal",\n "denomsToAdd": ["untrn"],\n "denomsToRemove": []\n}\n')),(0,a.kt)("h3",{id:"notes"},"Notes"),(0,a.kt)("p",null,"When submitting equivocation evidence through an ",(0,a.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," please take note that you need to use the consensus address (",(0,a.kt)("inlineCode",{parentName:"p"},"valcons"),") of the offending validator on the ",(0,a.kt)("strong",{parentName:"p"},"provider chain"),".\nBesides that, the ",(0,a.kt)("inlineCode",{parentName:"p"},"height")," and the ",(0,a.kt)("inlineCode",{parentName:"p"},"time")," fields should be mapped to the ",(0,a.kt)("strong",{parentName:"p"},"provider chain")," to avoid your evidence being rejected."),(0,a.kt)("p",null,"Before submitting the proposal please check that the evidence is not outdated by comparing the infraction height with the ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_duration")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks")," consensus parameters of the ",(0,a.kt)("strong",{parentName:"p"},"provider chain"),"."),(0,a.kt)("h3",{id:"gaia-example"},"Gaia example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'\u279c ~ cat genesis.json | jq ".consensus_params"\n{\n "block": {\n ...\n },\n "evidence": {\n "max_age_duration": "172800000000000",\n "max_age_num_blocks": "1000000",\n "max_bytes": "50000"\n },\n "validator": {\n ...\n },\n "version": {}\n}\n')),(0,a.kt)("p",null,"Any ",(0,a.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," transactions that submit evidence with ",(0,a.kt)("inlineCode",{parentName:"p"},"height")," older than ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"time")," older than ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_duration")," will be considered invalid."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/774a0fba.a14158d6.js b/legacy/assets/js/774a0fba.a14158d6.js new file mode 100644 index 0000000000..0d33f96c95 --- /dev/null +++ b/legacy/assets/js/774a0fba.a14158d6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7335],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>f});var i=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,i,r=function(e,t){if(null==e)return{};var n,i,r={},a=Object.keys(e);for(i=0;i<a.length;i++)n=a[i],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i<a.length;i++)n=a[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=i.createContext({}),l=function(e){var t=i.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=l(e.components);return i.createElement(c.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},h=i.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=l(n),h=r,f=d["".concat(c,".").concat(h)]||d[h]||p[h]||a;return n?i.createElement(f,o(o({ref:t},u),{},{components:n})):i.createElement(f,o({ref:t},u))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,o=new Array(a);o[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var l=2;l<a;l++)o[l]=n[l];return i.createElement.apply(null,o)}return i.createElement.apply(null,n)}h.displayName="MDXCreateElement"},6004:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>p,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var i=n(7462),r=(n(7294),n(3905));const a={sidebar_position:4},o="Consumer Initiated Slashing",s={unversionedId:"features/slashing",id:"version-v3.3.0/features/slashing",title:"Consumer Initiated Slashing",description:"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.",source:"@site/versioned_docs/version-v3.3.0/features/slashing.md",sourceDirName:"features",slug:"/features/slashing",permalink:"/interchain-security/legacy/v3.3.0/features/slashing",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"ICS Provider Proposals",permalink:"/interchain-security/legacy/v3.3.0/features/proposals"},next:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/legacy/v3.3.0/consumer-development/app-integration"}},c={},l=[{value:"Downtime infractions",id:"downtime-infractions",level:2}],u={toc:l},d="wrapper";function p(e){let{components:t,...n}=e;return(0,r.kt)(d,(0,i.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"consumer-initiated-slashing"},"Consumer Initiated Slashing"),(0,r.kt)("p",null,"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.\nIn essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake)."),(0,r.kt)("p",null,"To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized.\nAny infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains."),(0,r.kt)("p",null,"In the current implementation there are 2 important changes brought by the interchain security module:"),(0,r.kt)("h2",{id:"downtime-infractions"},"Downtime infractions"),(0,r.kt)("p",null,"reported by consumer chains are acted upon on the provider as soon as the provider receives the infraction evidence."),(0,r.kt)("p",null,"Instead of slashing, the provider will only jail offending validator for the duration of time established in the chain parameters."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Slash throttling (sometimes called jail throttling) mechanism ensures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider.")),(0,r.kt)("h1",{id:"cryptographic-verification-of-equivocation-and-slashing"},"Cryptographic verification of equivocation and slashing"),(0,r.kt)("p",null,"The Cryptographic verification of equivocation allows external agents to submit evidences of light client and double signing attacks observed on a consumer chain. When valid evidence is received, the malicious validators will be slashed, jailed, and tombstoned on the provider."),(0,r.kt)("p",null,"The feature is outlined in ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/adrs/adr-005-cryptographic-equivocation-verification"},"ADR-005")," and ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/adrs/adr-013-equivocation-slashing"},"ADR-013"),"."),(0,r.kt)("p",null,"By sending a ",(0,r.kt)("inlineCode",{parentName:"p"},"MsgSubmitConsumerMisbehaviour")," or a ",(0,r.kt)("inlineCode",{parentName:"p"},"MsgSubmitConsumerDoubleVoting")," transaction, the provider will\nverify the reported equivocation and, if successful, slash, jail, and tombstone the malicious validator."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/775e2592.f3f5f0d3.js b/legacy/assets/js/775e2592.f3f5f0d3.js new file mode 100644 index 0000000000..5d82f3a81a --- /dev/null +++ b/legacy/assets/js/775e2592.f3f5f0d3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7375],{3905:(e,t,a)=>{a.d(t,{Zo:()=>h,kt:()=>m});var n=a(7294);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?r(Object(a),!0).forEach((function(t){i(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):r(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function s(e,t){if(null==e)return{};var a,n,i=function(e,t){if(null==e)return{};var a,n,i={},r=Object.keys(e);for(n=0;n<r.length;n++)a=r[n],t.indexOf(a)>=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n<r.length;n++)a=r[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var l=n.createContext({}),c=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},h=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,r=e.originalType,l=e.parentName,h=s(e,["components","mdxType","originalType","parentName"]),d=c(a),p=i,m=d["".concat(l,".").concat(p)]||d[p]||u[p]||r;return a?n.createElement(m,o(o({ref:t},h),{},{components:a})):n.createElement(m,o({ref:t},h))}));function m(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=a.length,o=new Array(r);o[0]=p;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:i,o[1]=s;for(var c=2;c<r;c++)o[c]=a[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,a)}p.displayName="MDXCreateElement"},6428:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>s,toc:()=>c});var n=a(7462),i=(a(7294),a(3905));const r={sidebar_position:7,title:"Throttle with retries"},o=void 0,s={unversionedId:"adrs/adr-008-throttle-retries",id:"adrs/adr-008-throttle-retries",title:"Throttle with retries",description:"ADR 008: Throttle with retries",source:"@site/docs/adrs/adr-008-throttle-retries.md",sourceDirName:"adrs",slug:"/adrs/adr-008-throttle-retries",permalink:"/interchain-security/legacy/adrs/adr-008-throttle-retries",draft:!1,tags:[],version:"current",sidebarPosition:7,frontMatter:{sidebar_position:7,title:"Throttle with retries"},sidebar:"tutorialSidebar",previous:{title:"Cryptographic verification of equivocation evidence",permalink:"/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification"},next:{title:"Soft Opt-Out",permalink:"/interchain-security/legacy/adrs/adr-009-soft-opt-out"}},l={},c=[{value:"ADR 008: Throttle with retries",id:"adr-008-throttle-with-retries",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consumer changes",id:"consumer-changes",level:3},{value:"Consumer pending packets storage optimization",id:"consumer-pending-packets-storage-optimization",level:3},{value:"Provider changes",id:"provider-changes",level:3},{value:"Why the provider can handle VSCMatured packets immediately",id:"why-the-provider-can-handle-vscmatured-packets-immediately",level:3},{value:"Splitting of PRs and Upgrade Order",id:"splitting-of-prs-and-upgrade-order",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],h={toc:c},d="wrapper";function u(e){let{components:t,...r}=e;return(0,i.kt)(d,(0,n.Z)({},h,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h2",{id:"adr-008-throttle-with-retries"},"ADR 008: Throttle with retries"),(0,i.kt)("h2",{id:"changelog"},"Changelog"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"6/9/23: Initial draft"),(0,i.kt)("li",{parentName:"ul"},"6/22/23: added note on consumer pending packets storage optimization"),(0,i.kt)("li",{parentName:"ul"},"7/14/23: Added note on upgrade order")),(0,i.kt)("h2",{id:"status"},"Status"),(0,i.kt)("p",null,"Accepted"),(0,i.kt)("h2",{id:"context"},"Context"),(0,i.kt)("p",null,"For context on why the throttling mechanism exists, see ",(0,i.kt)("a",{parentName:"p",href:"/interchain-security/legacy/adrs/adr-002-throttle"},"ADR 002"),"."),(0,i.kt)("p",null,"Note the terms slash throttling and jail throttling are synonymous, since in replicated security a ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPacket")," simply jails a validator for downtime infractions. "),(0,i.kt)("p",null,"Currently the throttling mechanism is designed so that provider logic (slash meter, etc.) dictates how many slash packets can be handled over time. Throttled slash packets are persisted on the provider, leading to multiple possible issues. Namely:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"If slash or vsc matured packets are actually throttled/queued on the provider, state can grow and potentially lead to a DoS attack. We have short term solutions around this, but overall they come with their own weaknesses. See ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/594"},"#594"),"."),(0,i.kt)("li",{parentName:"ul"},"If a jailing attack described in ",(0,i.kt)("a",{parentName:"li",href:"/interchain-security/legacy/adrs/adr-002-throttle"},"ADR 002")," were actually to be carried out with the current throttling design, we'd likely have to halt the provider, and perform an emergency upgrade and/or migration to clear the queues of slash packets that were deemed to be malicious. Alternatively, validators would just have to ",(0,i.kt)("em",{parentName:"li"},"tough it out")," and wait for the queues to clear, during which all/most validators would be jailed. Right after being jailed, vals would have to unjail themselves promptly to ensure safety. The synchronous coordination required to maintain safety in such a scenario is not ideal.")),(0,i.kt)("p",null,"So what's the solution? We can improve the throttling mechanism to instead queue/persist relevant data on each consumer, and have consumers retry slash requests as needed."),(0,i.kt)("h2",{id:"decision"},"Decision"),(0,i.kt)("h3",{id:"consumer-changes"},"Consumer changes"),(0,i.kt)("p",null,"Note the consumer already queues up both slash and vsc matured packets via ",(0,i.kt)("inlineCode",{parentName:"p"},"AppendPendingPacket"),". Those packets are dequeued every endblock in ",(0,i.kt)("inlineCode",{parentName:"p"},"SendPackets")," and sent to the provider."),(0,i.kt)("p",null,"Instead, we will now introduce the following logic on endblock:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Slash packets will always be sent to the provider once they're at the head of the queue. However, once sent, the consumer will not send any trailing vsc matured packets from the queue until the provider responds with an ack that the slash packet has been handled (ie. val was jailed). That is, slash packets block the sending of trailing vsc matured packets in the consumer queue."),(0,i.kt)("li",{parentName:"ul"},"If two slash packets are at the head of the queue, the consumer will send the first slash packet, and then wait for a success ack from the provider before sending the second slash packet. This seems like it'd simplify implementation."),(0,i.kt)("li",{parentName:"ul"},"VSC matured packets at the head of the queue (ie. NOT trailing a slash packet) can be sent immediately, and do not block any other packets in the queue, since the provider always handles them immediately.")),(0,i.kt)("p",null,"To prevent the provider from having to keep track of what slash packets have been rejected, the consumer will have to retry the sending of slash packets over some period of time. This can be achieved with an on-chain consumer param. The suggested param value would probably be 1/2 of the provider's ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishmentPeriod"),", although it doesn't matter too much as long as the param value is sane."),(0,i.kt)("p",null,"Note to prevent weird edge case behavior, a retry would not be attempted until either a success ack or failure ack has been recv from the provider."),(0,i.kt)("p",null,"With the behavior described, we maintain very similar behavior to the current throttling mechanism regarding the timing that slash and vsc matured packets are handled on the provider. Obviously the queueing and blocking logic is moved, and the two chains would have to send more messages between one another (only in the case the throttling mechanism is triggered)."),(0,i.kt)("p",null,"In the normal case, when no or a few slash packets are being sent, the VSCMaturedPackets will not be delayed, and hence unbonding will not be delayed."),(0,i.kt)("p",null,"For implementation of this design, see ",(0,i.kt)("a",{target:"_blank",href:a(1036).Z},"throttle_retry.go"),"."),(0,i.kt)("h3",{id:"consumer-pending-packets-storage-optimization"},"Consumer pending packets storage optimization"),(0,i.kt)("p",null,"In addition to the mentioned consumer changes above. An optimization will need to be made to the consumer's pending packets storage to properly implement the feature from this ADR."),(0,i.kt)("p",null,'The consumer ccv module previously queued "pending packets" to be sent on each endblocker in ',(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/3bc4e7135066d848aac60b0787364c07157fd36d/x/ccv/consumer/keeper/relay.go#L178"},"SendPackets"),". These packets are queued in state with a protobuf list of ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerPacketData"),". For a single append operation, the entire list is deserialized, then a packet is appended to that list, and the list is serialized again. See older version of ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/05c2dae7c6372b1252b9e97215d07c6aa7618f33/x/ccv/consumer/keeper/keeper.go#L606"},"AppendPendingPacket"),". That is, a single append operation has O(N) complexity, where N is the size of the list."),(0,i.kt)("p",null,"This poor append performance isn't a problem when the pending packets list is small. But with this ADR being implemented, the pending packets list could potentially grow to the order of thousands of entries, in the scenario that a slash packet is bouncing."),(0,i.kt)("p",null,"We can improve the append time for this queue by converting it from a protobuf-esq list, to a queue implemented with sdk-esq code. The idea is to persist an uint64 index that will be incremented each time you queue up a packet. You can think of this as storing the tail of the queue. Then, packet data will be keyed by that index, making the data naturally ordered byte-wise for sdk's iterator. The index will also be stored in the packet data value bytes, so that the index can later be used to delete certain packets from the queue."),(0,i.kt)("p",null,"Two things are achieved with this approach:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"More efficient packet append/enqueue times"),(0,i.kt)("li",{parentName:"ul"},"The ability to delete select packets from the queue (previously all packets were deleted at once)")),(0,i.kt)("h3",{id:"provider-changes"},"Provider changes"),(0,i.kt)("p",null,"The main change needed for the provider is the removal of queuing logic for slash and vsc matured packets upon being received."),(0,i.kt)("p",null,"Instead, the provider will consult the slash meter to determine if a slash packet can be handled immediately. If not, the provider will return an ack message to the consumer communicating that the slash packet could not be handled, and needs to be sent again in the future (retried)."),(0,i.kt)("p",null,"VSCMatured packets will always be handled immediately upon being received by the provider."),(0,i.kt)("p",null,"Note ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"spec"),". Specifically the section on ",(0,i.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order"),". Previously the onus was on the provider to maintain this property via queuing packets and handling them FIFO."),(0,i.kt)("p",null,"Now this property will be maintained by the consumer sending packets in the correct order, and blocking the sending of VSCMatured packets as needed. Then, the ordered IBC channel will ensure that Slash/VSCMatured packets are received in the correct order on the provider."),(0,i.kt)("p",null,"The provider's main responsibility regarding throttling will now be to determine if a recv slash packet can be handled via slash meter etc., and appropriately ack to the sending consumer."),(0,i.kt)("h3",{id:"why-the-provider-can-handle-vscmatured-packets-immediately"},"Why the provider can handle VSCMatured packets immediately"),(0,i.kt)("p",null,"First we answer, what does a VSCMatured packet communicate to the provider? A VSCMatured packet communicates that a VSC has been applied to a consumer long enough that infractions committed on the consumer could have been submitted."),(0,i.kt)("p",null,"If the consumer is following the queuing/blocking protocol described. No bad behavior occurs, ",(0,i.kt)("inlineCode",{parentName:"p"},"VSC Maturity and Slashing Order")," property is maintained."),(0,i.kt)("p",null,"If a consumer sends VSCMatured packets too leniently: The consumer is malicious and sending duplicate vsc matured packets, or sending the packets sooner than the ccv protocol specifies. In this scenario, the provider needs to handle vsc matured packets immediately to prevent DOS, state bloat, or other issues. The only possible negative outcome is that the malicious consumer may not be able to jail a validator who should have been jailed. The malicious behavior only creates a negative outcome for the chain that is being malicious."),(0,i.kt)("p",null,"If a consumer blocks the sending of VSCMatured packets: The consumer is malicious and blocking vsc matured packets that should have been sent. This will block unbonding only up until the VSC timeout period has elapsed. At that time, the consumer is removed. Again the malicious behavior only creates a negative outcome for the chain that is being malicious."),(0,i.kt)("h3",{id:"splitting-of-prs-and-upgrade-order"},"Splitting of PRs and Upgrade Order"),(0,i.kt)("p",null,"This feature will implement consumer changes in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1024"},"#1024"),'. Note these changes should be deployed to prod for all consumers before the provider changes are deployed to prod. That is the consumer changes in #1024 are compatible with the current ("v1") provider implementation of throttling that\'s running on the Cosmos Hub as of July 2023.'),(0,i.kt)("p",null,"Once all consumers have deployed the changes in #1024, the provider changes from (TBD) can be deployed to prod, fully enabling v2 throttling."),(0,i.kt)("h2",{id:"consequences"},"Consequences"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Consumers will now have to manage their own queues, and retry logic."),(0,i.kt)("li",{parentName:"ul"},"Consumers still aren't trustless, but the provider is now less susceptible to mismanaged or malicious consumers."),(0,i.kt)("li",{parentName:"ul"},'Recovering from the "jailing attack" is more elegant.'),(0,i.kt)("li",{parentName:"ul"},"Some issues like ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/1001"},"#1001")," will now be handled implicitly by the improved throttling mechanism."),(0,i.kt)("li",{parentName:"ul"},"Slash and vsc matured packets can be handled immediately once recv by the provider if the slash meter allows."),(0,i.kt)("li",{parentName:"ul"},"In general, we reduce the amount of computation that happens in the provider end-blocker.")),(0,i.kt)("h3",{id:"positive"},"Positive"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},'We no longer have to reason about a "global queue" and a "chain specific queue", and keeping those all in-sync. Now slash and vsc matured packet queuing is handled on each consumer individually.'),(0,i.kt)("li",{parentName:"ul"},"Due to the above, the throttling protocol becomes less complex overall."),(0,i.kt)("li",{parentName:"ul"},"We no longer have to worry about throttle related DoS attack on the provider, since no queuing exists on the provider.")),(0,i.kt)("h3",{id:"negative"},"Negative"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Increased number of IBC packets being relayed anytime throttling logic is triggered."),(0,i.kt)("li",{parentName:"ul"},"Consumer complexity increases, since consumers now have manage queuing themselves, and implement packet retry logic.")),(0,i.kt)("h3",{id:"neutral"},"Neutral"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Core throttling logic on the provider remains unchanged, ie. slash meter, replenishment cycles, etc.")),(0,i.kt)("h2",{id:"references"},"References"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/713"},"EPIC")," tracking the changes proposed by this ADR"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/interchain-security/legacy/adrs/adr-002-throttle"},"ADR 002: Jail Throttling")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/594"},"#594"))))}u.isMDXComponent=!0},1036:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/files/throttle_retry-5ae73abd8a25d0235e6447e71abd730b.go"}}]); \ No newline at end of file diff --git a/legacy/assets/js/7a380eb1.83f2cce9.js b/legacy/assets/js/7a380eb1.83f2cce9.js new file mode 100644 index 0000000000..5cecd4b712 --- /dev/null +++ b/legacy/assets/js/7a380eb1.83f2cce9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[524],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>h});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=s(r),m=a,h=u["".concat(c,".").concat(m)]||u[m]||d[m]||i;return r?n.createElement(h,o(o({ref:t},p),{},{components:r})):n.createElement(h,o({ref:t},p))}));function h(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=m;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var s=2;s<i;s++)o[s]=r[s];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},8983:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var n=r(7462),a=(r(7294),r(3905));const i={sidebar_position:1,title:"ADRs"},o="Architecture Decision Records (ADR)",l={unversionedId:"adrs/intro",id:"version-v2.4.0-lsm/adrs/intro",title:"ADRs",description:"This is a location to record all high-level architecture decisions in the Interchain Security project.",source:"@site/versioned_docs/version-v2.4.0-lsm/adrs/intro.md",sourceDirName:"adrs",slug:"/adrs/intro",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/intro",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:1,frontMatter:{sidebar_position:1,title:"ADRs"},sidebar:"tutorialSidebar",previous:{title:"Frequently Asked Questions",permalink:"/interchain-security/legacy/v2.4.0-lsm/faq"},next:{title:"ADR Template",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-template"}},c={},s=[{value:"Table of Contents",id:"table-of-contents",level:2}],p={toc:s},u="wrapper";function d(e){let{components:t,...r}=e;return(0,a.kt)(u,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"architecture-decision-records-adr"},"Architecture Decision Records (ADR)"),(0,a.kt)("p",null,"This is a location to record all high-level architecture decisions in the Interchain Security project."),(0,a.kt)("p",null,"You can read more about the ADR concept in this ",(0,a.kt)("a",{parentName:"p",href:"https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0#.78xhdix6t"},"blog post"),"."),(0,a.kt)("p",null,"An ADR should provide:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Context on the relevant goals and the current state"),(0,a.kt)("li",{parentName:"ul"},"Proposed changes to achieve the goals"),(0,a.kt)("li",{parentName:"ul"},"Summary of pros and cons"),(0,a.kt)("li",{parentName:"ul"},"References"),(0,a.kt)("li",{parentName:"ul"},"Changelog")),(0,a.kt)("p",null,"Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and\njustification for a change in architecture, or for the architecture of something\nnew. The spec is much more compressed and streamlined summary of everything as\nit is or should be."),(0,a.kt)("p",null,"If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match."),(0,a.kt)("p",null,"Note the context/background should be written in the present tense."),(0,a.kt)("p",null,"To suggest an ADR, please make use of the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-template"},"ADR template")," provided."),(0,a.kt)("h2",{id:"table-of-contents"},"Table of Contents"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"ADR ","#"),(0,a.kt)("th",{parentName:"tr",align:null},"Description"),(0,a.kt)("th",{parentName:"tr",align:null},"Status"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-001-key-assignment"},"001")),(0,a.kt)("td",{parentName:"tr",align:null},"Consumer chain key assignment"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-002-throttle"},"002")),(0,a.kt)("td",{parentName:"tr",align:null},"Jail Throttling"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposal"},"003")),(0,a.kt)("td",{parentName:"tr",align:null},"Equivocation governance proposal"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/7b7e6708.18df0ce5.js b/legacy/assets/js/7b7e6708.18df0ce5.js new file mode 100644 index 0000000000..b232bca9f8 --- /dev/null +++ b/legacy/assets/js/7b7e6708.18df0ce5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[414],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,m=u["".concat(c,".").concat(h)]||u[h]||d[h]||i;return n?a.createElement(m,o(o({ref:t},p),{},{components:n})):a.createElement(m,o({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:r,o[1]=s;for(var l=2;l<i;l++)o[l]=n[l];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},1186:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var a=n(7462),r=(n(7294),n(3905));const i={sidebar_position:2,title:"Joining Replicated Security testnet"},o=void 0,s={unversionedId:"validators/joining-testnet",id:"version-v3.3.1-lsm/validators/joining-testnet",title:"Joining Replicated Security testnet",description:"Introduction",source:"@site/versioned_docs/version-v3.3.1-lsm/validators/joining-testnet.md",sourceDirName:"validators",slug:"/validators/joining-testnet",permalink:"/interchain-security/legacy/validators/joining-testnet",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"Joining Replicated Security testnet"},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/legacy/validators/overview"},next:{title:"Withdrawing consumer chain validator rewards",permalink:"/interchain-security/legacy/validators/withdraw_rewards"}},c={},l=[{value:"Introduction",id:"introduction",level:2},{value:"Joining the provider chain",id:"joining-the-provider-chain",level:2},{value:"Initialization",id:"initialization",level:2},{value:"Joining consumer chains",id:"joining-consumer-chains",level:2},{value:"Re-using consensus key",id:"re-using-consensus-key",level:2},{value:"Assigning consensus keys",id:"assigning-consensus-keys",level:2}],p={toc:l},u="wrapper";function d(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"This short guide will teach you how to join the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security"},"Replicated Security testnet"),"."),(0,r.kt)("p",null,"The experience gained in the testnet will prepare you for validating interchain secured chains."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set."),(0,r.kt)("p",{parentName:"admonition"},"For general information about running cosmos-sdk based chains check out the ",(0,r.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html"},"validator basics")," and ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/main/run-node/run-node"},"Running a Node section")," of Cosmos SDK docs")),(0,r.kt)("h2",{id:"joining-the-provider-chain"},"Joining the provider chain"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain.")),(0,r.kt)("p",null,"A comprehensive guide is available ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security/provider"},"here"),"."),(0,r.kt)("h2",{id:"initialization"},"Initialization"),(0,r.kt)("p",null,"First, initialize your ",(0,r.kt)("inlineCode",{parentName:"p"},"$NODE_HOME")," using the ",(0,r.kt)("inlineCode",{parentName:"p"},"provider")," chain binary."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"NODE_MONIKER=<your_node>\nCHAIN_ID=provider\nNODE_HOME=<path_to_your_home>\n\ngaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME\n")),(0,r.kt)("p",null,"Add your key to the keyring - more details available ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/main/run-node/keyring"},"here"),"."),(0,r.kt)("p",null,"In this example we will use the ",(0,r.kt)("inlineCode",{parentName:"p"},"test")," keyring-backend. This option is not safe to use in production."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad keys add <key_moniker> --keyring-backend test\n\n# save the address as variable for later use\nMY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)\n")),(0,r.kt)("p",null,"Before issuing any transactions, use the ",(0,r.kt)("inlineCode",{parentName:"p"},"provider")," testnet faucet to add funds to your address."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider\n\n# example output:\n{\n "address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",\n "amount": "10000000uatom",\n "chain": "provider",\n "hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",\n "status": "success"\n}\n')),(0,r.kt)("p",null,"Then, use the account associated with the keyring to issue a ",(0,r.kt)("inlineCode",{parentName:"p"},"create-validator")," transaction which will register your validator on chain."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad tx staking create-validator \\\n --amount=1000000uatom \\\n --pubkey=$(gaiad tendermint show-validator) \\\n --moniker="choose a moniker" \\\n --chain-id=$CHAIN_ID" \\\n --commission-rate="0.10" \\\n --commission-max-rate="0.20" \\\n --commission-max-change-rate="0.01" \\\n --min-self-delegation="1000000" \\\n --gas="auto" \\\n --gas-prices="0.0025uatom" \\\n --from=<key_moniker>\n')),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Check this ",(0,r.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html#edit-validator-description"},"guide")," to edit your validator.")),(0,r.kt)("p",null,"After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use ",(0,r.kt)("inlineCode",{parentName:"p"},"statesync")," to catch up to the rest of the network."),(0,r.kt)("p",null,"You can use this script to modify your ",(0,r.kt)("inlineCode",{parentName:"p"},"config.toml")," with the required statesync parameters."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"# create the statesync script\n$: cd $NODE_HOME\n$: touch statesync.sh\n$ chmod 700 statesync.sh # make executable\n")),(0,r.kt)("p",null,"Paste the following instructions into the ",(0,r.kt)("inlineCode",{parentName:"p"},"statesync.sh"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'#!/bin/bash\n\nSNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"\n\nLATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \\\nBLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \\\nTRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)\n\nsed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\\1true| ; \\\ns|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\\1\\"$SNAP_RPC,$SNAP_RPC\\"| ; \\\ns|^(trust_height[[:space:]]+=[[:space:]]+).*$|\\1$BLOCK_HEIGHT| ; \\\ns|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\\1\\"$TRUST_HASH\\"|" $NODE_HOME/config/config.toml\n')),(0,r.kt)("p",null,"Then, you can execute the script:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"$: ./statesync.sh # setup config.toml for statesync\n")),(0,r.kt)("p",null,"Finally, copy the provider genesis and start your node:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/replicated-security/provider/provider-genesis.json\n$: wget $GENESIS_URL -O genesis.json\n$: genesis.json $NODE_HOME/config/genesis.json\n# start the service\n$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"\n')),(0,r.kt)("p",null,"Additional scripts to setup your nodes are available ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/provider/join-rs-provider.sh"},"here")," and ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/provider/join-rs-provider-cv.sh"},"here"),". The scripts will configure your node and create the required services - the scripts only work in linux environments."),(0,r.kt)("h2",{id:"joining-consumer-chains"},"Joining consumer chains"),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Once you reach the active set on the provider chain, you will be required to validate all available consumer chains."),(0,r.kt)("p",{parentName:"admonition"},"You can use the same consensus key on all consumer chains, or opt to use a different key on each consumer chain.\nCheck out this ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/features/key-assignment"},"guide")," to learn more about key assignment in replicated security.")),(0,r.kt)("p",null,"To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"When running the provider chain and consumers on the same machine please update the ",(0,r.kt)("inlineCode",{parentName:"p"},"PORT")," numbers for each of them and make sure they do not overlap (otherwise the binaries will not start)."),(0,r.kt)("p",{parentName:"admonition"},"Important ports to re-configure:"),(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--rpc.laddr")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--p2p.laddr")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--api.address")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--grpc.address")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--grpc-web.address")))),(0,r.kt)("h2",{id:"re-using-consensus-key"},"Re-using consensus key"),(0,r.kt)("p",null,"To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the ",(0,r.kt)("inlineCode",{parentName:"p"},"priv_validator_key.json")," into the home directory of your consumer chain (",(0,r.kt)("inlineCode",{parentName:"p"},"<consumer_home>/config/priv_validator_key.json"),")."),(0,r.kt)("p",null,"When you start the chain, the consensus key will be the same on the provider and the consumer chain."),(0,r.kt)("h2",{id:"assigning-consensus-keys"},"Assigning consensus keys"),(0,r.kt)("p",null,"Whenever you initialize a new node, it will be configured with a consensus key you can use."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'# machine running consumer chain\nconsumerd init <node_moniker> --home <home_path> --chain-id consumer-1\n\n# use the output of this command to get the consumer chain consensus key\nconsumerd tendermint show-validator\n# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}\n')),(0,r.kt)("p",null,"Then, let the provider know which key you will be using for the consumer chain:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"# machine running the provider chain\ngaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b sync -y -o json\n")),(0,r.kt)("p",null,"After this step, you are ready to copy the consumer genesis into your nodes's ",(0,r.kt)("inlineCode",{parentName:"p"},"/config")," folder, start your consumer chain node and catch up to the network."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/7c1fc285.13bcbb37.js b/legacy/assets/js/7c1fc285.13bcbb37.js new file mode 100644 index 0000000000..cb4ca9e712 --- /dev/null +++ b/legacy/assets/js/7c1fc285.13bcbb37.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4645],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>d});var o=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function c(e,n){if(null==e)return{};var t,o,r=function(e,n){if(null==e)return{};var t,o,r={},a=Object.keys(e);for(o=0;o<a.length;o++)t=a[o],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o<a.length;o++)t=a[o],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=o.createContext({}),l=function(e){var n=o.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},u=function(e){var n=l(e.components);return o.createElement(s.Provider,{value:n},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},h=o.forwardRef((function(e,n){var t=e.components,r=e.mdxType,a=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=l(t),h=r,d=p["".concat(s,".").concat(h)]||p[h]||m[h]||a;return t?o.createElement(d,i(i({ref:n},u),{},{components:t})):o.createElement(d,i({ref:n},u))}));function d(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var a=t.length,i=new Array(a);i[0]=h;var c={};for(var s in n)hasOwnProperty.call(n,s)&&(c[s]=n[s]);c.originalType=e,c[p]="string"==typeof e?e:r,i[1]=c;for(var l=2;l<a;l++)i[l]=t[l];return o.createElement.apply(null,i)}return o.createElement.apply(null,t)}h.displayName="MDXCreateElement"},8131:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var o=t(7462),r=(t(7294),t(3905));const a={sidebar_position:1},i="Developing an ICS consumer chain",c={unversionedId:"consumer-development/app-integration",id:"version-v2.0.0/consumer-development/app-integration",title:"Developing an ICS consumer chain",description:"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.",source:"@site/versioned_docs/version-v2.0.0/consumer-development/app-integration.md",sourceDirName:"consumer-development",slug:"/consumer-development/app-integration",permalink:"/interchain-security/legacy/v2.0.0/consumer-development/app-integration",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/legacy/v2.0.0/features/slashing"},next:{title:"Consumer Chain Governance",permalink:"/interchain-security/legacy/v2.0.0/consumer-development/consumer-chain-governance"}},s={},l=[{value:"Basic consumer chain",id:"basic-consumer-chain",level:2},{value:"Democracy consumer chain",id:"democracy-consumer-chain",level:2},{value:"Standalone chain to consumer chain changeover",id:"standalone-chain-to-consumer-chain-changeover",level:2}],u={toc:l},p="wrapper";function m(e){let{components:n,...t}=e;return(0,r.kt)(p,(0,o.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"developing-an-ics-consumer-chain"},"Developing an ICS consumer chain"),(0,r.kt)("p",null,"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.\nTo help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications."),(0,r.kt)("h2",{id:"basic-consumer-chain"},"Basic consumer chain"),(0,r.kt)("p",null,"The source code for the example app can be found ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer"},"here"),"."),(0,r.kt)("p",null,"Please note that consumer chains do not implement the staking module - the validator set is replicated from the provider, meaning that the provider and the consumer use the same validator set and their stake on the provider directly determines their stake on the consumer.\nAt present there is no opt-in mechanism available, so all validators of the provider must also validate on the provider chain."),(0,r.kt)("p",null,"Your chain should import the consumer module from ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," and register it in the correct places in your ",(0,r.kt)("inlineCode",{parentName:"p"},"app.go"),".\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in.\nYou should not need to manage or override any code from the ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module."),(0,r.kt)("h2",{id:"democracy-consumer-chain"},"Democracy consumer chain"),(0,r.kt)("p",null,"The source code for the example app can be found ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy"},"here"),"."),(0,r.kt)("p",null,"This type of consumer chain wraps the basic CosmosSDK ",(0,r.kt)("inlineCode",{parentName:"p"},"x/distribution"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"x/staking")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"x/governance")," modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system."),(0,r.kt)("p",null,"This allows the consumer chain to leverage those modules while also using the ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module."),(0,r.kt)("p",null,'With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.'),(0,r.kt)("h2",{id:"standalone-chain-to-consumer-chain-changeover"},"Standalone chain to consumer chain changeover"),(0,r.kt)("p",null,"This feature is being actively worked on. Information will be provided at a later time."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/7cd5f60b.0f1e5e23.js b/legacy/assets/js/7cd5f60b.0f1e5e23.js new file mode 100644 index 0000000000..948f8e9f5e --- /dev/null +++ b/legacy/assets/js/7cd5f60b.0f1e5e23.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5357],{3905:(e,r,t)=>{t.d(r,{Zo:()=>l,kt:()=>h});var n=t(7294);function i(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function o(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function a(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?o(Object(t),!0).forEach((function(r){i(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function s(e,r){if(null==e)return{};var t,n,i=function(e,r){if(null==e)return{};var t,n,i={},o=Object.keys(e);for(n=0;n<o.length;n++)t=o[n],r.indexOf(t)>=0||(i[t]=e[t]);return i}(e,r);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)t=o[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var d=n.createContext({}),c=function(e){var r=n.useContext(d),t=r;return e&&(t="function"==typeof e?e(r):a(a({},r),e)),t},l=function(e){var r=c(e.components);return n.createElement(d.Provider,{value:r},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},m=n.forwardRef((function(e,r){var t=e.components,i=e.mdxType,o=e.originalType,d=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=c(t),m=i,h=u["".concat(d,".").concat(m)]||u[m]||p[m]||o;return t?n.createElement(h,a(a({ref:r},l),{},{components:t})):n.createElement(h,a({ref:r},l))}));function h(e,r){var t=arguments,i=r&&r.mdxType;if("string"==typeof e||i){var o=t.length,a=new Array(o);a[0]=m;var s={};for(var d in r)hasOwnProperty.call(r,d)&&(s[d]=r[d]);s.originalType=e,s[u]="string"==typeof e?e:i,a[1]=s;for(var c=2;c<o;c++)a[c]=t[c];return n.createElement.apply(null,a)}return n.createElement.apply(null,t)}m.displayName="MDXCreateElement"},2632:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>d,contentTitle:()=>a,default:()=>p,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var n=t(7462),i=(t(7294),t(3905));const o={sidebar_position:2},a="Reward distribution",s={unversionedId:"features/reward-distribution",id:"version-v3.3.0/features/reward-distribution",title:"Reward distribution",description:"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.",source:"@site/versioned_docs/version-v3.3.0/features/reward-distribution.md",sourceDirName:"features",slug:"/features/reward-distribution",permalink:"/interchain-security/legacy/v3.3.0/features/reward-distribution",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/legacy/v3.3.0/features/key-assignment"},next:{title:"ICS Provider Proposals",permalink:"/interchain-security/legacy/v3.3.0/features/proposals"}},d={},c=[{value:"Note",id:"note",level:2},{value:"Instructions for adding a denom",id:"instructions-for-adding-a-denom",level:3},{value:"Parameters",id:"parameters",level:2},{value:"<code>consumer_redistribution_fraction</code>",id:"consumer_redistribution_fraction",level:3},{value:"<code>blocks_per_distribution_transmission</code>",id:"blocks_per_distribution_transmission",level:3},{value:"<code>transfer_timeout_period</code>",id:"transfer_timeout_period",level:3},{value:"<code>distribution_transmission_channel</code>",id:"distribution_transmission_channel",level:3},{value:"<code>provider_fee_pool_addr_str</code>",id:"provider_fee_pool_addr_str",level:3}],l={toc:c},u="wrapper";function p(e){let{components:r,...t}=e;return(0,i.kt)(u,(0,n.Z)({},l,t,{components:r,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"reward-distribution"},"Reward distribution"),(0,i.kt)("p",null,"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.\nIn replicated security block rewards and fees are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel that gets created during consumer chain initialization."),(0,i.kt)("p",null,"Reward distribution on the provider is handled by the distribution module - validators and delegators receive a fraction of the consumer chain tokens as staking rewards.\nThe distributed reward tokens are IBC tokens and therefore cannot be staked on the provider chain."),(0,i.kt)("p",null,"Sending and distributing rewards from consumer chains to provider chain is handled by the ",(0,i.kt)("inlineCode",{parentName:"p"},"Reward Distribution")," sub-protocol."),(0,i.kt)("h2",{id:"note"},"Note"),(0,i.kt)("p",null,"The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerRewardsPool"),".\nThere is a new transaction type called ",(0,i.kt)("inlineCode",{parentName:"p"},"RegisterConsumerRewardDenom"),". This transaction allows consumer chains to register denoms to be used as consumer chain rewards on the provider.\nThe cost to register a denom is configurable (",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerRewardDenomRegistrationFee")," chain param) and the full amount of this fee is transferred to the community pool of the provider chain. Only denoms registered through this transaction are then transferred from the ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerRewardsPool")," to the ",(0,i.kt)("inlineCode",{parentName:"p"},"FeePoolAddress"),", to be distributed out to delegators and validators."),(0,i.kt)("h3",{id:"instructions-for-adding-a-denom"},"Instructions for adding a denom"),(0,i.kt)("p",null,"The transaction must be carried out on the provider chain. Please use the ",(0,i.kt)("inlineCode",{parentName:"p"},"ibc/*")," denom trace format."),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre"},"# reward denoms must be registered on the provider chain (gaia in this example)\ngaiad tx provider register-consumer-reward-denom ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9 --from mykey\n"))),(0,i.kt)("h2",{id:"parameters"},"Parameters"),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"The following chain parameters dictate consumer chain distribution amount and frequency.\nThey are set at consumer genesis and ",(0,i.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction"),"\n",(0,i.kt)("inlineCode",{parentName:"p"},"transfer_timeout_period")," must be provided in every ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerChainAddition")," proposal.")),(0,i.kt)("h3",{id:"consumer_redistribution_fraction"},(0,i.kt)("inlineCode",{parentName:"h3"},"consumer_redistribution_fraction")),(0,i.kt)("p",null,'The fraction of tokens allocated to the consumer redistribution address during distribution events. The fraction is a string representing a decimal number. For example "0.75" would represent 75%.'),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"Example:"),(0,i.kt)("p",{parentName:"admonition"},"With ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction")," set to ",(0,i.kt)("inlineCode",{parentName:"p"},"0.75")," the consumer chain would send 75% of its block rewards and accumulated fees to the consumer redistribution address, and the remaining 25% to the provider chain every ",(0,i.kt)("inlineCode",{parentName:"p"},"n")," blocks where ",(0,i.kt)("inlineCode",{parentName:"p"},"n == blocks_per_distribution_transmission"),".")),(0,i.kt)("h3",{id:"blocks_per_distribution_transmission"},(0,i.kt)("inlineCode",{parentName:"h3"},"blocks_per_distribution_transmission")),(0,i.kt)("p",null,"The number of blocks between IBC token transfers from the consumer chain to the provider chain."),(0,i.kt)("h3",{id:"transfer_timeout_period"},(0,i.kt)("inlineCode",{parentName:"h3"},"transfer_timeout_period")),(0,i.kt)("p",null,"Timeout period for consumer chain reward distribution IBC packets."),(0,i.kt)("h3",{id:"distribution_transmission_channel"},(0,i.kt)("inlineCode",{parentName:"h3"},"distribution_transmission_channel")),(0,i.kt)("p",null,"Provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."),(0,i.kt)("h3",{id:"provider_fee_pool_addr_str"},(0,i.kt)("inlineCode",{parentName:"h3"},"provider_fee_pool_addr_str")),(0,i.kt)("p",null,"Provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/811ce3c2.901b6dd1.js b/legacy/assets/js/811ce3c2.901b6dd1.js new file mode 100644 index 0000000000..47ff3eafbe --- /dev/null +++ b/legacy/assets/js/811ce3c2.901b6dd1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9701],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>m});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?i(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,a,r=function(e,n){if(null==e)return{};var t,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=a.createContext({}),c=function(e){var n=a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=c(e.components);return a.createElement(l.Provider,{value:n},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},y=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=c(t),y=r,m=d["".concat(l,".").concat(y)]||d[y]||p[y]||i;return t?a.createElement(m,o(o({ref:n},u),{},{components:t})):a.createElement(m,o({ref:n},u))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,o=new Array(i);o[0]=y;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var c=2;c<i;c++)o[c]=t[c];return a.createElement.apply(null,o)}return a.createElement.apply(null,t)}y.displayName="MDXCreateElement"},4740:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var a=t(7462),r=(t(7294),t(3905));const i={sidebar_position:1},o="Key Assignment",s={unversionedId:"features/key-assignment",id:"version-v2.0.0/features/key-assignment",title:"Key Assignment",description:"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.",source:"@site/versioned_docs/version-v2.0.0/features/key-assignment.md",sourceDirName:"features",slug:"/features/key-assignment",permalink:"/interchain-security/legacy/v2.0.0/features/key-assignment",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Technical Specification",permalink:"/interchain-security/legacy/v2.0.0/introduction/technical-specification"},next:{title:"Reward distribution",permalink:"/interchain-security/legacy/v2.0.0/features/reward-distribution"}},l={},c=[{value:"Rules",id:"rules",level:2},{value:"Adding a key",id:"adding-a-key",level:2},{value:"Changing a key",id:"changing-a-key",level:2},{value:"Removing a key",id:"removing-a-key",level:2}],u={toc:c},d="wrapper";function p(e){let{components:n,...t}=e;return(0,r.kt)(d,(0,a.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"key-assignment"},"Key Assignment"),(0,r.kt)("p",null,"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.\nThere are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains."),(0,r.kt)("p",null,"The feature is outlined in this ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.0.0/adrs/adr-001-key-assignment"},"ADR-001")),(0,r.kt)("p",null,"By sending an ",(0,r.kt)("inlineCode",{parentName:"p"},"AssignConsumerKey")," transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity.")),(0,r.kt)("h2",{id:"rules"},"Rules"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"a key can be assigned before the consumer addition proposal passes on the provider"),(0,r.kt)("li",{parentName:"ul"},"validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider"),(0,r.kt)("li",{parentName:"ul"},"validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X"),(0,r.kt)("li",{parentName:"ul"},"a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Validators can use a different key for each consumer chain. ")),(0,r.kt)("h2",{id:"adding-a-key"},"Adding a key"),(0,r.kt)("p",null,"First, create a new node on the consumer chain using the equivalent:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"consumerd init <moniker>\n")),(0,r.kt)("p",null,"Then query your node for the consensus key."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}\n')),(0,r.kt)("p",null,"Then, make an ",(0,r.kt)("inlineCode",{parentName:"p"},"assign-consensus-key")," transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"gaiad tx provider assign-consensus-key <consumer-chain-id> '<pubkey>' --from <tx-signer> --home <home_dir> --gas 900000 -b block -y -o json\n")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"consumer-chain-id")," is the string identifier of the consumer chain, as assigned on the provider chain"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"consumer-pub-key")," has the following format ",(0,r.kt)("inlineCode",{parentName:"li"},'{"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}'))),(0,r.kt)("p",null,"Check that the key was assigned correcly by querying the provider:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad query provider validator-consumer-key <consumer-chain-id> cosmosvalcons1e....3xsj3ayzf4uv6\n")),(0,r.kt)("p",null,"You must use a ",(0,r.kt)("inlineCode",{parentName:"p"},"valcons")," address. You can obtain it by querying your node on the provider ",(0,r.kt)("inlineCode",{parentName:"p"},"gaiad tendermint show-address")),(0,r.kt)("p",null,"OR"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad query provider validator-provider-key <consumer-chain-id> consumervalcons1e....123asdnoaisdao\n")),(0,r.kt)("p",null,"You must use a ",(0,r.kt)("inlineCode",{parentName:"p"},"valcons")," address. You can obtain it by querying your node on the consumer ",(0,r.kt)("inlineCode",{parentName:"p"},"consumerd tendermint show-address")),(0,r.kt)("h2",{id:"changing-a-key"},"Changing a key"),(0,r.kt)("p",null,"To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied"),(0,r.kt)("h2",{id:"removing-a-key"},"Removing a key"),(0,r.kt)("p",null,"To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the ",(0,r.kt)("inlineCode",{parentName:"p"},"Adding a key")," section and using your provider consensus key."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/81762141.ff37e79d.js b/legacy/assets/js/81762141.ff37e79d.js new file mode 100644 index 0000000000..daaa52bbf5 --- /dev/null +++ b/legacy/assets/js/81762141.ff37e79d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1409],{3905:(e,n,t)=>{t.d(n,{Zo:()=>c,kt:()=>m});var o=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function r(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?i(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,o,a=function(e,n){if(null==e)return{};var t,o,a={},i=Object.keys(e);for(o=0;o<i.length;o++)t=i[o],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)t=i[o],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=o.createContext({}),p=function(e){var n=o.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):r(r({},n),e)),t},c=function(e){var n=p(e.components);return o.createElement(l.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},h=o.forwardRef((function(e,n){var t=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=p(t),h=a,m=d["".concat(l,".").concat(h)]||d[h]||u[h]||i;return t?o.createElement(m,r(r({ref:n},c),{},{components:t})):o.createElement(m,r({ref:n},c))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var i=t.length,r=new Array(i);r[0]=h;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:a,r[1]=s;for(var p=2;p<i;p++)r[p]=t[p];return o.createElement.apply(null,r)}return o.createElement.apply(null,t)}h.displayName="MDXCreateElement"},7125:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>r,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>p});var o=t(7462),a=(t(7294),t(3905));const i={sidebar_position:3},r="ICS Provider Proposals",s={unversionedId:"features/proposals",id:"version-v2.0.0/features/proposals",title:"ICS Provider Proposals",description:"Interchain security module introduces 3 new proposal types to the provider.",source:"@site/versioned_docs/version-v2.0.0/features/proposals.md",sourceDirName:"features",slug:"/features/proposals",permalink:"/interchain-security/legacy/v2.0.0/features/proposals",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Reward distribution",permalink:"/interchain-security/legacy/v2.0.0/features/reward-distribution"},next:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/legacy/v2.0.0/features/slashing"}},l={},p=[{value:"<code>ConsumerAdditionProposal</code>",id:"consumeradditionproposal",level:2},{value:"<code>ConsumerRemovalProposal</code>",id:"consumerremovalproposal",level:2},{value:"<code>EquivocationProposal</code>",id:"equivocationproposal",level:2},{value:"Notes",id:"notes",level:3},{value:"Gaia example:",id:"gaia-example",level:3}],c={toc:p},d="wrapper";function u(e){let{components:n,...t}=e;return(0,a.kt)(d,(0,o.Z)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"ics-provider-proposals"},"ICS Provider Proposals"),(0,a.kt)("p",null,"Interchain security module introduces 3 new proposal types to the provider."),(0,a.kt)("p",null,"The proposals are used to propose upcoming interchain security events through governance."),(0,a.kt)("h2",{id:"consumeradditionproposal"},(0,a.kt)("inlineCode",{parentName:"h2"},"ConsumerAdditionProposal")),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"If you are preparing a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," you can find more information in the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.0.0/consumer-development/onboarding"},"consumer onboarding checklist"),".")),(0,a.kt)("p",null,"Proposal type used to suggest adding a new consumer chain."),(0,a.kt)("p",null,"When proposals of this type are passed and the ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain."),(0,a.kt)("p",null,"Minimal example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'{\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n "title": "Add consumer chain",\n "description": ".md description of your chain and all other relevant information",\n "chain_id": "newchain-1",\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Unbonding period for the consumer chain.\n // It should should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n "transfer_timeout_period": 1800000000000,\n "consumer_redistribution_fraction": "0.75",\n "blocks_per_distribution_transmission": 1000,\n "historical_entries": 10000,\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1"\n // relevant for chains performing a sovereign to consumer changeover\n // in order to maintan the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123"\n}\n')),(0,a.kt)("p",null,"More examples can be found in the replicated security testnet repository ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/baryon-1/proposal-baryon-1.json"},"here")," and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/noble-1/start-proposal-noble-1.json"},"here"),"."),(0,a.kt)("h2",{id:"consumerremovalproposal"},(0,a.kt)("inlineCode",{parentName:"h2"},"ConsumerRemovalProposal")),(0,a.kt)("p",null,"Proposal type used to suggest removing an existing consumer chain."),(0,a.kt)("p",null,"When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain.\nAfter the consumer chain removal, the chain in question will no longer be secured by the provider's validator set."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain.\nAdditional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set.\nMore information will be made available in the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.0.0/consumer-development/offboarding"},"Consumer Offboarding Checklist"),".")),(0,a.kt)("p",null,"Minimal example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'{\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details"\n}\n')),(0,a.kt)("h2",{id:"equivocationproposal"},(0,a.kt)("inlineCode",{parentName:"h2"},"EquivocationProposal")),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},(0,a.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," will only be accepted on the provider chain if at least one of the consumer chains submits equivocation evidence to the provider.\nSending equivocation evidence to the provider is handled automatically by the interchain security protocol when an equivocation infraction is detected on the consumer chain.")),(0,a.kt)("p",null,"Proposal type used to suggest slashing a validator for double signing on consumer chain.\nWhen proposals of this type are passed, the validator in question will be slashed for equivocation on the provider chain."),(0,a.kt)("admonition",{type:"warning"},(0,a.kt)("p",{parentName:"admonition"},"Take note that an equivocation slash causes a validator to be tombstoned (can never re-enter the active set).\nTombstoning a validator on the provider chain will remove the validator from the validator set of all consumer chains.")),(0,a.kt)("p",null,"Minimal example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'{\n "title": "Validator-1 double signed on consumerchain-1",\n "description": "Here is more information about the infraction so you can verify it yourself",\n // the list of equivocations that will be processed\n "equivocations": [\n {\n "height": 14444680,\n "time": "2023-02-28T20:40:00.000000Z",\n "power": 5500000,\n "consensus_address": "<consensus address ON THE PROVIDER>"\n }\n ]\n}\n')),(0,a.kt)("h3",{id:"notes"},"Notes"),(0,a.kt)("p",null,"When submitting equivocation evidence through an ",(0,a.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," please take note that you need to use the consensus address (",(0,a.kt)("inlineCode",{parentName:"p"},"valcons"),") of the offending validator on the ",(0,a.kt)("strong",{parentName:"p"},"provider chain"),".\nBesides that, the ",(0,a.kt)("inlineCode",{parentName:"p"},"height")," and the ",(0,a.kt)("inlineCode",{parentName:"p"},"time")," fields should be mapped to the ",(0,a.kt)("strong",{parentName:"p"},"provider chain")," to avoid your evidence being rejected."),(0,a.kt)("p",null,"Before submitting the proposal please check that the evidence is not outdated by comparing the infraction height with the ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_duration")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks")," consensus parameters of the ",(0,a.kt)("strong",{parentName:"p"},"provider chain"),"."),(0,a.kt)("h3",{id:"gaia-example"},"Gaia example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'\u279c ~ cat genesis.json | jq ".consensus_params"\n{\n "block": {\n ...\n },\n "evidence": {\n "max_age_duration": "172800000000000",\n "max_age_num_blocks": "1000000",\n "max_bytes": "50000"\n },\n "validator": {\n ...\n },\n "version": {}\n}\n')),(0,a.kt)("p",null,"Any ",(0,a.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," transactions that submit evidence with ",(0,a.kt)("inlineCode",{parentName:"p"},"height")," older than ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"time")," older than ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_duration")," will be considered invalid."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/834888be.5b1bcc44.js b/legacy/assets/js/834888be.5b1bcc44.js new file mode 100644 index 0000000000..740265fc8d --- /dev/null +++ b/legacy/assets/js/834888be.5b1bcc44.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5831],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=c(n),m=a,h=d["".concat(s,".").concat(m)]||d[m]||p[m]||o;return n?r.createElement(h,i(i({ref:t},u),{},{components:n})):r.createElement(h,i({ref:t},u))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,i[1]=l;for(var c=2;c<o;c++)i[c]=n[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},270:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const o={sidebar_position:2,title:"ADR Template"},i="ADR {ADR-NUMBER}:",l={unversionedId:"adrs/adr-template",id:"version-v3.3.1-lsm/adrs/adr-template",title:"ADR Template",description:"Changelog",source:"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-template.md",sourceDirName:"adrs",slug:"/adrs/adr-template",permalink:"/interchain-security/legacy/adrs/adr-template",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"ADR Template"},sidebar:"tutorialSidebar",previous:{title:"ADR Template",permalink:"/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop"},next:{title:"Key Assignment",permalink:"/interchain-security/legacy/adrs/adr-001-key-assignment"}},s={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],u={toc:c},d="wrapper";function p(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-adr-number-title"},"ADR {ADR-NUMBER}: {TITLE}"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"{date}: {changelog}")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},'A decision may be "proposed" if it hasn\'t been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement.')),(0,a.kt)("p",null,"{Deprecated|Proposed|Accepted}"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution. ")),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"This section explains all of the details of the proposed solution, including implementation details.\nIt should also describe affects / corollary items that may need to be changed as a part of this.\nIf the proposed change will be large, please also indicate a way to do the change to maximize ease of review.\n(e.g. the optimal split of things to do between separate PR's)")),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},'This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones.')),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"{reference link}")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/84bd924c.97d868f9.js b/legacy/assets/js/84bd924c.97d868f9.js new file mode 100644 index 0000000000..b740ba81eb --- /dev/null +++ b/legacy/assets/js/84bd924c.97d868f9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2777],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>p});var i=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,i)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){n(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,i,n=function(e,t){if(null==e)return{};var r,i,n={},o=Object.keys(e);for(i=0;i<o.length;i++)r=o[i],t.indexOf(r)>=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i<o.length;i++)r=o[i],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=i.createContext({}),l=function(e){var t=i.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},u=function(e){var t=l(e.components);return i.createElement(s.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},y=i.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),d=l(r),y=n,p=d["".concat(s,".").concat(y)]||d[y]||h[y]||o;return r?i.createElement(p,a(a({ref:t},u),{},{components:r})):i.createElement(p,a({ref:t},u))}));function p(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,a=new Array(o);a[0]=y;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[d]="string"==typeof e?e:n,a[1]=c;for(var l=2;l<o;l++)a[l]=r[l];return i.createElement.apply(null,a)}return i.createElement.apply(null,r)}y.displayName="MDXCreateElement"},329:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>c,toc:()=>l});var i=r(7462),n=(r(7294),r(3905));const o={sidebar_position:2},a="Terminology",c={unversionedId:"introduction/terminology",id:"version-v3.1.0/introduction/terminology",title:"Terminology",description:"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.",source:"@site/versioned_docs/version-v3.1.0/introduction/terminology.md",sourceDirName:"introduction",slug:"/introduction/terminology",permalink:"/interchain-security/legacy/v3.1.0/introduction/terminology",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/legacy/v3.1.0/introduction/overview"},next:{title:"Interchain Security Parameters",permalink:"/interchain-security/legacy/v3.1.0/introduction/params"}},s={},l=[{value:"Shared Security",id:"shared-security",level:2},{value:"Interchain Security",id:"interchain-security",level:2},{value:"Replicated Security",id:"replicated-security",level:2},{value:"Mesh security",id:"mesh-security",level:2}],u={toc:l},d="wrapper";function h(e){let{components:t,...r}=e;return(0,n.kt)(d,(0,i.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"terminology"},"Terminology"),(0,n.kt)("p",null,"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions."),(0,n.kt)("h2",{id:"shared-security"},"Shared Security"),(0,n.kt)("p",null,"Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share it's proof-of-stake security with another blockchain or off-chain process."),(0,n.kt)("h2",{id:"interchain-security"},"Interchain Security"),(0,n.kt)("p",null,"Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC."),(0,n.kt)("h2",{id:"replicated-security"},"Replicated Security"),(0,n.kt)("p",null,'A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC. Note this documentation is focused on explaining the concepts from replicated security.'),(0,n.kt)("h2",{id:"mesh-security"},"Mesh security"),(0,n.kt)("p",null,"A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see ",(0,n.kt)("a",{parentName:"p",href:"https://informal.systems/blog/replicated-vs-mesh-security"},"Replicated vs. Mesh Security on the Informal Blog"),"."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/8565b213.798e93c8.js b/legacy/assets/js/8565b213.798e93c8.js new file mode 100644 index 0000000000..27ccfbece3 --- /dev/null +++ b/legacy/assets/js/8565b213.798e93c8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1962],{3905:(e,t,n)=>{n.d(t,{Zo:()=>h,kt:()=>m});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},h=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,h=s(e,["components","mdxType","originalType","parentName"]),d=l(n),p=a,m=d["".concat(c,".").concat(p)]||d[p]||u[p]||o;return n?r.createElement(m,i(i({ref:t},h),{},{components:n})):r.createElement(m,i({ref:t},h))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=p;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:a,i[1]=s;for(var l=2;l<o;l++)i[l]=n[l];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}p.displayName="MDXCreateElement"},7068:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>l});var r=n(7462),a=(n(7294),n(3905));const o={sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},i=void 0,s={unversionedId:"frequently-asked-questions",id:"version-v2.4.0-lsm/frequently-asked-questions",title:"Frequently Asked Questions",description:"What is the meaning of Validator Set Replication?",source:"@site/versioned_docs/version-v2.4.0-lsm/frequently-asked-questions.md",sourceDirName:".",slug:"/faq",permalink:"/interchain-security/legacy/v2.4.0-lsm/faq",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:5,frontMatter:{sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},sidebar:"tutorialSidebar",previous:{title:"Withdrawing consumer chain validator rewards",permalink:"/interchain-security/legacy/v2.4.0-lsm/validators/withdraw_rewards"},next:{title:"ADRs",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/intro"}},c={},l=[{value:"What is the meaning of Validator Set Replication?",id:"what-is-the-meaning-of-validator-set-replication",level:2},{value:"What even is a consumer chain?",id:"what-even-is-a-consumer-chain",level:2},{value:"What happens to consumer if provider is down?",id:"what-happens-to-consumer-if-provider-is-down",level:2},{value:"What happens to provider if consumer is down?",id:"what-happens-to-provider-if-consumer-is-down",level:2},{value:"Can I run the provider and consumer chains on the same machine?",id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine",level:2},{value:"Can the consumer chain have its own token?",id:"can-the-consumer-chain-have-its-own-token",level:2},{value:"How are Tx fees paid on consumer?",id:"how-are-tx-fees-paid-on-consumer",level:2},{value:"Are there any restrictions the consumer chains need to abide by?",id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by",level:2},{value:"What's in it for the validators and stakers?",id:"whats-in-it-for-the-validators-and-stakers",level:2},{value:"Can the consumer chain have its own governance?",id:"can-the-consumer-chain-have-its-own-governance",level:2},{value:"Can validators opt-out of replicated security?",id:"can-validators-opt-out-of-replicated-security",level:2},{value:"How does Equivocation Governance Slashing work?",id:"how-does-equivocation-governance-slashing-work",level:2},{value:"Can Consumer Chains perform Software Upgrades?",id:"can-consumer-chains-perform-software-upgrades",level:2},{value:"How can I connect to the testnets?",id:"how-can-i-connect-to-the-testnets",level:2},{value:"How do I start using ICS?",id:"how-do-i-start-using-ics",level:2},{value:"Which relayers are supported?",id:"which-relayers-are-supported",level:2},{value:"How does key delegation work in ICS?",id:"how-does-key-delegation-work-in-ics",level:2}],h={toc:l},d="wrapper";function u(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,r.Z)({},h,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"what-is-the-meaning-of-validator-set-replication"},"What is the meaning of Validator Set Replication?"),(0,a.kt)("p",null,"VSR simply means that the same validator set is used to secure both the provider and consumer chains. VSR is ensured through ICS protocol which keeps consumers up to date with the validator set of the provider."),(0,a.kt)("h2",{id:"what-even-is-a-consumer-chain"},"What even is a consumer chain?"),(0,a.kt)("p",null,"Consumer chain is blockchain operated by the same validator operators as the provider chain. The ICS protocol ensures the validator set replication properties (informs consumer chain about the current state of the validator set on the provider)"),(0,a.kt)("p",null,"Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements."),(0,a.kt)("h2",{id:"what-happens-to-consumer-if-provider-is-down"},"What happens to consumer if provider is down?"),(0,a.kt)("p",null,"In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set."),(0,a.kt)("p",null,"The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness."),(0,a.kt)("p",null,"However, if the ",(0,a.kt)("inlineCode",{parentName:"p"},"trusting_period")," (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain.\nThis means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about."),(0,a.kt)("p",null,'Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point.\nAt the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.'),(0,a.kt)("h2",{id:"what-happens-to-provider-if-consumer-is-down"},"What happens to provider if consumer is down?"),(0,a.kt)("p",null,"Consumer chains do not impact the provider chain.\nThe ICS protocol is concerned only with validator set replication and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events)."),(0,a.kt)("h2",{id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine"},"Can I run the provider and consumer chains on the same machine?"),(0,a.kt)("p",null,"Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation."),(0,a.kt)("h2",{id:"can-the-consumer-chain-have-its-own-token"},"Can the consumer chain have its own token?"),(0,a.kt)("p",null,"As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees."),(0,a.kt)("h2",{id:"how-are-tx-fees-paid-on-consumer"},"How are Tx fees paid on consumer?"),(0,a.kt)("p",null,"The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations."),(0,a.kt)("h2",{id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by"},"Are there any restrictions the consumer chains need to abide by?"),(0,a.kt)("p",null,"No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way.\nThe only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain."),(0,a.kt)("h2",{id:"whats-in-it-for-the-validators-and-stakers"},"What's in it for the validators and stakers?"),(0,a.kt)("p",null,"The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by ",(0,a.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction"),". The rewards are distributed (sent to the provider) every ",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission"),"."),(0,a.kt)("admonition",{type:"note"},(0,a.kt)("p",{parentName:"admonition"}," ",(0,a.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission")," are parameters defined in the ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," used to create the consumer chain. These parameters can be changed via consumer chain governance.")),(0,a.kt)("h2",{id:"can-the-consumer-chain-have-its-own-governance"},"Can the consumer chain have its own governance?"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Yes.")),(0,a.kt)("p",null,'In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.'),(0,a.kt)("p",null,"Validators can also be representatives but representatives are not required to run validator nodes."),(0,a.kt)("p",null,"This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance."),(0,a.kt)("h2",{id:"can-validators-opt-out-of-replicated-security"},"Can validators opt-out of replicated security?"),(0,a.kt)("p",null,"At present, the validators cannot opt-out of validating consumer chains."),(0,a.kt)("p",null,"There are multiple opt-out mechanisms under active research."),(0,a.kt)("h2",{id:"how-does-equivocation-governance-slashing-work"},"How does Equivocation Governance Slashing work?"),(0,a.kt)("p",null,"To avoid potential attacks directed at provider chain validators, a new mechanism was introduced:"),(0,a.kt)("p",null,"When a validator double-signs on the consumer chain, a special type of slash packet is relayed to the provider chain. The provider will store information about the double signing validator and allow a governance proposal to be submitted.\nIf the double-signing proposal passes, the offending validator will be slashed on the provider chain and tombstoned. Tombstoning will permanently exclude the validator from the active set of the provider."),(0,a.kt)("admonition",{type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"An equivocation proposal cannot be submitted for a validator that did not double sign on any of the consumer chains.")),(0,a.kt)("h2",{id:"can-consumer-chains-perform-software-upgrades"},"Can Consumer Chains perform Software Upgrades?"),(0,a.kt)("p",null,"Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM)."),(0,a.kt)("p",null,"Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module."),(0,a.kt)("h2",{id:"how-can-i-connect-to-the-testnets"},"How can I connect to the testnets?"),(0,a.kt)("p",null,"Check out the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.4.0-lsm/validators/joining-testnet"},"Joining Replicated Security testnet")," section."),(0,a.kt)("h2",{id:"how-do-i-start-using-ics"},"How do I start using ICS?"),(0,a.kt)("p",null,"To become a consumer chain use this ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/onboarding"},"checklist")," and check the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/app-integration"},"App integration section")),(0,a.kt)("h2",{id:"which-relayers-are-supported"},"Which relayers are supported?"),(0,a.kt)("p",null,"Currently supported versions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Hermes 1.4.1")),(0,a.kt)("h2",{id:"how-does-key-delegation-work-in-ics"},"How does key delegation work in ICS?"),(0,a.kt)("p",null,"You can check the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.4.0-lsm/features/key-assignment"},"Key Assignment Guide")," for specific instructions."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/863c9ec3.48c51999.js b/legacy/assets/js/863c9ec3.48c51999.js new file mode 100644 index 0000000000..0fd87e8e48 --- /dev/null +++ b/legacy/assets/js/863c9ec3.48c51999.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2068],{3905:(e,n,t)=>{t.d(n,{Zo:()=>d,kt:()=>m});var i=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function a(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?r(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):r(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,i,o=function(e,n){if(null==e)return{};var t,i,o={},r=Object.keys(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var c=i.createContext({}),l=function(e){var n=i.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):a(a({},n),e)),t},d=function(e){var n=l(e.components);return i.createElement(c.Provider,{value:n},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},h=i.forwardRef((function(e,n){var t=e.components,o=e.mdxType,r=e.originalType,c=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),u=l(t),h=o,m=u["".concat(c,".").concat(h)]||u[h]||p[h]||r;return t?i.createElement(m,a(a({ref:n},d),{},{components:t})):i.createElement(m,a({ref:n},d))}));function m(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var r=t.length,a=new Array(r);a[0]=h;var s={};for(var c in n)hasOwnProperty.call(n,c)&&(s[c]=n[c]);s.originalType=e,s[u]="string"==typeof e?e:o,a[1]=s;for(var l=2;l<r;l++)a[l]=t[l];return i.createElement.apply(null,a)}return i.createElement.apply(null,t)}h.displayName="MDXCreateElement"},2248:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>p,frontMatter:()=>r,metadata:()=>s,toc:()=>l});var i=t(7462),o=(t(7294),t(3905));const r={sidebar_position:4},a="Consumer Initiated Slashing",s={unversionedId:"features/slashing",id:"version-v3.2.0/features/slashing",title:"Consumer Initiated Slashing",description:"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.",source:"@site/versioned_docs/version-v3.2.0/features/slashing.md",sourceDirName:"features",slug:"/features/slashing",permalink:"/interchain-security/legacy/v3.2.0/features/slashing",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"ICS Provider Proposals",permalink:"/interchain-security/legacy/v3.2.0/features/proposals"},next:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/legacy/v3.2.0/consumer-development/app-integration"}},c={},l=[{value:"Downtime infractions",id:"downtime-infractions",level:2},{value:"Double-signing (equivocation)",id:"double-signing-equivocation",level:2}],d={toc:l},u="wrapper";function p(e){let{components:n,...t}=e;return(0,o.kt)(u,(0,i.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-initiated-slashing"},"Consumer Initiated Slashing"),(0,o.kt)("p",null,"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.\nIn essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake)."),(0,o.kt)("p",null,"To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized.\nAny infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains."),(0,o.kt)("p",null,"In the current implementation there are 2 important changes brought by the interchain security module:"),(0,o.kt)("h2",{id:"downtime-infractions"},"Downtime infractions"),(0,o.kt)("p",null,"reported by consumer chains are acted upon on the provider as soon as the provider receives the infraction evidence."),(0,o.kt)("p",null,"Instead of slashing, the provider will only jail offending validator for the duration of time established in the chain parameters."),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Slash throttling (sometimes called jail throttling) mechanism ensures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider.")),(0,o.kt)("h2",{id:"double-signing-equivocation"},"Double-signing (equivocation)"),(0,o.kt)("p",null,"infractions are not acted upon immediately."),(0,o.kt)("p",null,"Upon receiving double signing evidence, the provider chain will take note of the evidence and allow for ",(0,o.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," to be submitted to slash the offending validator.\nAny ",(0,o.kt)("inlineCode",{parentName:"p"},"EquivocationProposal"),"s to slash a validator that has not double signed on any of the consumer chains will be automatically rejected by the provider chain."),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"The offending validator will only be slashed (and tombstoned) if an ",(0,o.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," is accepted and passed through governance."),(0,o.kt)("p",{parentName:"admonition"},"The offending validator will effectively get slashed and tombstoned on all consumer chains.")),(0,o.kt)("p",null,"You can find instructions on creating ",(0,o.kt)("inlineCode",{parentName:"p"},"EquivocationProposal"),"s ",(0,o.kt)("a",{parentName:"p",href:"./proposals#equivocationproposal"},"here"),"."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/875b184f.2edbe09d.js b/legacy/assets/js/875b184f.2edbe09d.js new file mode 100644 index 0000000000..2c26bb4639 --- /dev/null +++ b/legacy/assets/js/875b184f.2edbe09d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8281],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>m});var i=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?r(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):r(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,i,a=function(e,n){if(null==e)return{};var t,i,a={},r=Object.keys(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=i.createContext({}),c=function(e){var n=i.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},p=function(e){var n=c(e.components);return i.createElement(l.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},h=i.forwardRef((function(e,n){var t=e.components,a=e.mdxType,r=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(t),h=a,m=d["".concat(l,".").concat(h)]||d[h]||u[h]||r;return t?i.createElement(m,o(o({ref:n},p),{},{components:t})):i.createElement(m,o({ref:n},p))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var r=t.length,o=new Array(r);o[0]=h;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:a,o[1]=s;for(var c=2;c<r;c++)o[c]=t[c];return i.createElement.apply(null,o)}return i.createElement.apply(null,t)}h.displayName="MDXCreateElement"},7648:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>s,toc:()=>c});var i=t(7462),a=(t(7294),t(3905));const r={sidebar_position:1},o="Overview",s={unversionedId:"validators/overview",id:"version-v3.1.0/validators/overview",title:"Overview",description:"We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.",source:"@site/versioned_docs/version-v3.1.0/validators/overview.md",sourceDirName:"validators",slug:"/validators/overview",permalink:"/interchain-security/legacy/v3.1.0/validators/overview",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Offboarding Checklist",permalink:"/interchain-security/legacy/v3.1.0/consumer-development/offboarding"},next:{title:"Joining Replicated Security testnet",permalink:"/interchain-security/legacy/v3.1.0/validators/joining-testnet"}},l={},c=[{value:"Startup sequence overview",id:"startup-sequence-overview",level:2},{value:"1. Consumer Chain init + 2. Genesis generation",id:"1-consumer-chain-init--2-genesis-generation",level:3},{value:"3. Submit Proposal",id:"3-submit-proposal",level:3},{value:"4. CCV Genesis state generation",id:"4-ccv-genesis-state-generation",level:3},{value:"5. Updating the genesis file",id:"5-updating-the-genesis-file",level:3},{value:"6. Chain start",id:"6-chain-start",level:3},{value:"7. Creating IBC connections",id:"7-creating-ibc-connections",level:3},{value:"Downtime Infractions",id:"downtime-infractions",level:2},{value:"Double-signing Infractions",id:"double-signing-infractions",level:2},{value:"Key assignment",id:"key-assignment",level:2},{value:"References:",id:"references",level:2}],p={toc:c},d="wrapper";function u(e){let{components:n,...r}=e;return(0,a.kt)(d,(0,i.Z)({},p,r,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"overview"},"Overview"),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"We advise that you join the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security"},"Replicated Security testnet")," to gain hands-on experience with running consumer chains.")),(0,a.kt)("p",null,"At present, replicated security requires all validators of the provider chain (ie. Cosmos Hub) to run validator nodes for all governance-approved consumer chains."),(0,a.kt)("p",null,"Once a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," passes, validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains."),(0,a.kt)("p",null,"Provider chain and consumer chains represent standalone chains that only share the validator set ie. the same validator operators are tasked with running all chains."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 180 validators for Cosmos Hub).")),(0,a.kt)("h2",{id:"startup-sequence-overview"},"Startup sequence overview"),(0,a.kt)("p",null,"Consumer chains cannot start and be secured by the validator set of the provider unless a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," is passed.\nEach proposal contains defines a ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider."),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"Validators are required to run consumer chain binaries only after ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," has passed.")),(0,a.kt)("p",null,"Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains."),(0,a.kt)("p",null,"The image below illustrates the startup sequence\n",(0,a.kt)("img",{alt:"startup",src:t(7728).Z,width:"942",height:"632"})),(0,a.kt)("h3",{id:"1-consumer-chain-init--2-genesis-generation"},"1. Consumer Chain init + 2. Genesis generation"),(0,a.kt)("p",null,"Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")),(0,a.kt)("h3",{id:"3-submit-proposal"},"3. Submit Proposal"),(0,a.kt)("p",null,"Consumer chain team (or their advocates) submits a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal"),".\nThe most important parameters for validators are:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"spawn_time")," - the time after which the consumer chain must be started"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"genesis_hash")," - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and ",(0,a.kt)("inlineCode",{parentName:"li"},"spawn_time")," is reached"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"binary_hash")," - hash of the consumer chain binary used to validate the software builds")),(0,a.kt)("h3",{id:"4-ccv-genesis-state-generation"},"4. CCV Genesis state generation"),(0,a.kt)("p",null,"After reaching ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json"),". The CCV validator set consists of the validator set on the provider at ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time"),"."),(0,a.kt)("p",null,"The state can be queried on the provider chain (in this case the Cosmos Hub):"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json\n")),(0,a.kt)("p",null,"This is used by the launch coordinator to create the final ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," that will be distributed to validators in step 5."),(0,a.kt)("h3",{id:"5-updating-the-genesis-file"},"5. Updating the genesis file"),(0,a.kt)("p",null,"Upon reaching the ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," the initial validator set state will become available on the provider chain. The initial validator set is included in the ",(0,a.kt)("strong",{parentName:"p"},"final genesis.json")," of the consumer chain."),(0,a.kt)("h3",{id:"6-chain-start"},"6. Chain start"),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences.")),(0,a.kt)("p",null,"The new ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," to start their consumer chain node."),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"Please pay attention to any onboarding repositories provided by the consumer chain teams.\nRecommendations are available in ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.1.0/consumer-development/onboarding"},"Consumer Onboarding Checklist"),".\nAnother comprehensive guide is available in the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md"},"Replicated Security testnet repo"),".")),(0,a.kt)("h3",{id:"7-creating-ibc-connections"},"7. Creating IBC connections"),(0,a.kt)("p",null,"Finally, to fully establish replicated security an IBC relayer is used to establish connections and create the required channels."),(0,a.kt)("admonition",{type:"warning"},(0,a.kt)("p",{parentName:"admonition"},"The relayer can establish the connection only after the consumer chain starts producing blocks.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> \nhermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1\nhermes start\n")),(0,a.kt)("h2",{id:"downtime-infractions"},"Downtime Infractions"),(0,a.kt)("p",null,"At present, the consumer chain can report evidence about downtime infractions to the provider chain. The ",(0,a.kt)("inlineCode",{parentName:"p"},"min_signed_per_window")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"signed_blocks_window")," can be different on each consumer chain and are subject to changes via consumer chain governance."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains."),(0,a.kt)("p",{parentName:"admonition"},"To unjail, the validator must wait for the jailing period to elapse on the provider chain and ",(0,a.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html#unjail-validator"},"submit an unjail transaction")," on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains."),(0,a.kt)("p",{parentName:"admonition"},"More information is available in ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.1.0/features/slashing#downtime-infractions"},"Downtime Slashing documentation"))),(0,a.kt)("h2",{id:"double-signing-infractions"},"Double-signing Infractions"),(0,a.kt)("p",null,"To learn more about equivocation handling in replicated security check out the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.1.0/features/slashing#double-signing-equivocation"},"Slashing")," and ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.1.0/features/proposals#equivocationproposal"},"EquivocationProposal")," documentation sections"),(0,a.kt)("h2",{id:"key-assignment"},"Key assignment"),(0,a.kt)("p",null,"Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use."),(0,a.kt)("p",null,"For more information check our the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.1.0/features/key-assignment"},"Key assignment overview and guide")),(0,a.kt)("h2",{id:"references"},"References:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-faq.html"},"Cosmos Hub Validators FAQ")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-setup.html"},"Cosmos Hub Running a validator")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md#chain-launch"},"Startup Sequence")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-setup.html#unjail-validator"},"Submit Unjailing Transaction"))))}u.isMDXComponent=!0},7728:(e,n,t)=>{t.d(n,{Z:()=>i});const i=t.p+"assets/images/hypha-consumer-start-process-2141109f76c584706dd994d7965fd692.svg"}}]); \ No newline at end of file diff --git a/legacy/assets/js/8782d4a8.ed4f52f3.js b/legacy/assets/js/8782d4a8.ed4f52f3.js new file mode 100644 index 0000000000..5c502047ef --- /dev/null +++ b/legacy/assets/js/8782d4a8.ed4f52f3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5101],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>u});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(n),m=i,u=d["".concat(l,".").concat(m)]||d[m]||h[m]||o;return n?a.createElement(u,r(r({ref:t},p),{},{components:n})):a.createElement(u,r({ref:t},p))}));function u(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:i,r[1]=s;for(var c=2;c<o;c++)r[c]=n[c];return a.createElement.apply(null,r)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},2189:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var a=n(7462),i=(n(7294),n(3905));const o={sidebar_position:5},r="Changeover Procedure",s={unversionedId:"consumer-development/changeover-procedure",id:"version-v3.3.1-lsm/consumer-development/changeover-procedure",title:"Changeover Procedure",description:"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.",source:"@site/versioned_docs/version-v3.3.1-lsm/consumer-development/changeover-procedure.md",sourceDirName:"consumer-development",slug:"/consumer-development/changeover-procedure",permalink:"/interchain-security/legacy/consumer-development/changeover-procedure",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Offboarding Checklist",permalink:"/interchain-security/legacy/consumer-development/offboarding"},next:{title:"Consumer Genesis Transformation",permalink:"/interchain-security/legacy/consumer-development/consumer-genesis-transformation"}},l={},c=[{value:"Overview",id:"overview",level:2},{value:"1. ConsumerAddition proposal submitted to the <code>provider</code> chain",id:"1-consumeraddition-proposal-submitted-to-the-provider-chain",level:3},{value:"2. upgrade proposal on standalone chain",id:"2-upgrade-proposal-on-standalone-chain",level:3},{value:"3. spawn time is reached",id:"3-spawn-time-is-reached",level:3},{value:"4. standalone chain upgrade",id:"4-standalone-chain-upgrade",level:3},{value:"Notes",id:"notes",level:4},{value:"Onboarding Checklist",id:"onboarding-checklist",level:2},{value:"1. Complete testing & integration",id:"1-complete-testing--integration",level:2},{value:"2. Create an Onboarding Repository",id:"2-create-an-onboarding-repository",level:2},{value:"3. Submit a ConsumerChainAddition Governance Proposal to the provider",id:"3-submit-a-consumerchainaddition-governance-proposal-to-the-provider",level:2},{value:"3. Submit an Upgrade Proposal & Prepare for Changeover",id:"3-submit-an-upgrade-proposal--prepare-for-changeover",level:2},{value:"4. Upgrade time \ud83d\ude80",id:"4-upgrade-time-",level:2}],p={toc:c},d="wrapper";function h(e){let{components:t,...n}=e;return(0,i.kt)(d,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"changeover-procedure"},"Changeover Procedure"),(0,i.kt)("p",null,"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the ",(0,i.kt)("strong",{parentName:"p"},"changeover procedure")," and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain."),(0,i.kt)("p",null,"The relevant protocol specifications are available below:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md#channel-initialization-existing-chains"},"ICS-28 with existing chains"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/interchain-security/legacy/adrs/adr-010-standalone-changeover"},"ADR in ICS repo"))),(0,i.kt)("h2",{id:"overview"},"Overview"),(0,i.kt)("p",null,"Standalone to consumer changeover procedure can rougly be separated into 4 parts:"),(0,i.kt)("h3",{id:"1-consumeraddition-proposal-submitted-to-the-provider-chain"},"1. ConsumerAddition proposal submitted to the ",(0,i.kt)("inlineCode",{parentName:"h3"},"provider")," chain"),(0,i.kt)("p",null,'The proposal is equivalent to the "normal" ConsumerAddition proposal submitted by new consumer chains.'),(0,i.kt)("p",null,"However, here are the most important notes and differences between a new consumer chain and a standalone chain performing a changeover:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"chain_id")," must be equal to the standalone chain id"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"initial_height")," field has additional rules to abide by:")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre"},'{\n...\n "initial_height" : {\n // must correspond to current revision number of standalone chain\n // e.g. stride-1 => "revision_number": 1\n "revision_number": 1,\n\n // must correspond to a height that is at least 1 block after the upgrade\n // that will add the `consumer` module to the standalone chain\n // e.g. "upgrade_height": 100 => "revision_height": 101\n "revision_height": 1,\n },\n...\n}\n')),(0,i.kt)("p",{parentName:"admonition"},"RevisionNumber: 0, RevisionHeight: 111")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"genesis_hash")," can be safely ignored because the chain is already running. A hash of the standalone chain's initial genesis may be used")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"binary_hash")," may not be available ahead of time. All chains performing the changeover go through rigorous testing - if bugs are caught and fixed the hash listed in the proposal may not be the most recent one.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," listed in the proposal MUST be before the ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height")," listed in the the upgrade proposal on the standalone chain."),(0,i.kt)("admonition",{parentName:"li",type:"caution"},(0,i.kt)("p",{parentName:"admonition"},(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," must occur before the ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height")," on the standalone chain is reached because the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider")," chain must generate the ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerGenesis")," that contains the ",(0,i.kt)("strong",{parentName:"p"},"validator set")," that will be used after the changeover."))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"unbonding_period")," must correspond to the value used on the standalone chain. Otherwise, the clients used for the ccv protocol may be incorrectly initialized.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"distribution_transmission_channel")," ",(0,i.kt)("strong",{parentName:"p"},"should be set"),"."))),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"Populating ",(0,i.kt)("inlineCode",{parentName:"p"},"distribution_transmission_channel")," will enable the standalone chain to re-use one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ",(0,i.kt)("inlineCode",{parentName:"p"},"ibc denom")," that may already be in use."),(0,i.kt)("p",{parentName:"admonition"},"If the parameter is not set, a new channel will be created.")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"ccv_timeout_period")," has no important notes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"transfer_timeout_period")," has no important notes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction")," has no important notes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission")," has no important notes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"historical_entries")," has no important notes"))),(0,i.kt)("h3",{id:"2-upgrade-proposal-on-standalone-chain"},"2. upgrade proposal on standalone chain"),(0,i.kt)("p",null,"The standalone chain creates an upgrade proposal to include the ",(0,i.kt)("inlineCode",{parentName:"p"},"interchain-security/x/ccv/consumer")," module."),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"The upgrade height in the proposal should correspond to a height that is after the ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," in the consumer addition proposal submitted to the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider")," chain.")),(0,i.kt)("p",null,"Otherwise, the upgrade is indistinguishable from a regular on-chain upgrade proposal."),(0,i.kt)("h3",{id:"3-spawn-time-is-reached"},"3. spawn time is reached"),(0,i.kt)("p",null,"When the ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," is reached on the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider")," it will generate a ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerGenesis")," that contains the validator set that will supercede the ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," validator set."),(0,i.kt)("p",null,"This ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerGenesis")," must be available on the standalone chain during the on-chain upgrade."),(0,i.kt)("h3",{id:"4-standalone-chain-upgrade"},"4. standalone chain upgrade"),(0,i.kt)("p",null,"Performing the on-chain upgrade on the standalone chain will add the ",(0,i.kt)("inlineCode",{parentName:"p"},"ccv/consumer")," module and allow the chain to become a ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer")," of replicated security."),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerGenesis")," must be exported to a file and placed in the correct folder on the standalone chain before the upgade."),(0,i.kt)("p",{parentName:"admonition"},"The file must be placed at the exact specified location, otherwise the upgrade will not be executed correctly."),(0,i.kt)("p",{parentName:"admonition"},"Usually the file is placed in ",(0,i.kt)("inlineCode",{parentName:"p"},"$NODE_HOME/config"),", but the file name and the exact directory is dictated by the upgrade code on the ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," chain."),(0,i.kt)("ul",{parentName:"admonition"},(0,i.kt)("li",{parentName:"ul"},"please check exact instructions provided by the ",(0,i.kt)("inlineCode",{parentName:"li"},"standalone")," chain team"))),(0,i.kt)("p",null,"After the ",(0,i.kt)("inlineCode",{parentName:"p"},"genesis.json")," file has been made available, the process is equivalent to a normal on-chain upgrade. The standalone validator set will sign the next couple of blocks before transferring control to ",(0,i.kt)("inlineCode",{parentName:"p"},"provider")," validator set."),(0,i.kt)("p",null,"The standalone validator set can still be slashed for any infractions if evidence is submitted within the ",(0,i.kt)("inlineCode",{parentName:"p"},"unboding_period"),"."),(0,i.kt)("h4",{id:"notes"},"Notes"),(0,i.kt)("p",null,"The changeover procedure may be updated in the future to create a seamless way of providing the validator set information to the standalone chain."),(0,i.kt)("h2",{id:"onboarding-checklist"},"Onboarding Checklist"),(0,i.kt)("p",null,"This onboarding checklist is slightly different from the one under ",(0,i.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/onboarding"},"Onboarding")),(0,i.kt)("p",null,"Additionally, you can check the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md"},"testnet repo")," for a comprehensive guide on preparing and launching consumer chains."),(0,i.kt)("h2",{id:"1-complete-testing--integration"},"1. Complete testing & integration"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test integration with gaia"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test your protocol with supported relayer versions (minimum hermes 1.4.1)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test the changeover procedure"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","reach out to the ICS team if you are facing issues")),(0,i.kt)("h2",{id:"2-create-an-onboarding-repository"},"2. Create an Onboarding Repository"),(0,i.kt)("p",null,"To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain."),(0,i.kt)("p",null,"This should include (at minimum):"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see ",(0,i.kt)("a",{parentName:"li",href:"/interchain-security/legacy/consumer-development/consumer-genesis-transformation"},"Transform Consumer Genesis"),")"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","information about relevant seed/peer nodes you are running"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","relayer information (compatible versions)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","copy of your governance proposal (as JSON)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","a script showing how to start your chain and connect to peers (optional)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable")),(0,i.kt)("p",null,"Example of such a repository can be found ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyphacoop/ics-testnets/tree/main/game-of-chains-2022/sputnik"},"here"),"."),(0,i.kt)("h2",{id:"3-submit-a-consumerchainaddition-governance-proposal-to-the-provider"},"3. Submit a ConsumerChainAddition Governance Proposal to the provider"),(0,i.kt)("p",null,"Before you submit a ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerChainAddition")," proposal, please provide a ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," that is ",(0,i.kt)("strong",{parentName:"p"},"before")," the the ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height")," of the upgrade that will introduce the ",(0,i.kt)("inlineCode",{parentName:"p"},"ccv module")," to your chain."),(0,i.kt)("admonition",{type:"danger"},(0,i.kt)("p",{parentName:"admonition"},"If the ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," happens after your ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height")," the provider will not be able to communicate the new validator set to be used after the changeover.")),(0,i.kt)("p",null,"Additionally, reach out to the community via the ",(0,i.kt)("a",{parentName:"p",href:"https://forum.cosmos.network/"},"forum")," to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine your chain's spawn time"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine consumer chain parameters to be put in the proposal"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take note to include a link to your onboarding repository")),(0,i.kt)("p",null,"Example of a consumer chain addition proposal."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},'// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain or add a standalone chain.\n// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.\n// It is recommended that spawn time occurs after the proposal end time and that it is scheduled to happen before the standalone chain upgrade\n// that sill introduce the ccv module.\n{\n // Title of the proposal\n "title": "Changeover Standalone chain",\n // Description of the proposal\n // format the text as a .md file and include the file in your onboarding repository\n "description": ".md description of your chain and all other relevant information",\n // Proposed chain-id of the new consumer chain.\n // Must be unique from all other consumer chain ids of the executing provider chain.\n "chain_id": "standalone-1",\n // Initial height of new consumer chain.\n // For a completely new chain, this will be {0,1}.\n "initial_height" : {\n // must correspond to current revision number of standalone chain\n // e.g. standalone-1 => "revision_number": 1\n "revision_number": 1,\n\n // must correspond to a height that is at least 1 block after the upgrade\n // that will add the `consumer` module to the standalone chain\n // e.g. "upgrade_height": 100 => "revision_height": 101\n "revision_number": 1,\n },\n // Hash of the consumer chain genesis state without the consumer CCV module genesis params.\n // => not relevant for changeover procedure\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n // Hash of the consumer chain binary that should be run by validators on standalone chain upgrade\n // => not relevant for changeover procedure as it may become stale\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n // Unbonding period for the consumer chain.\n // It should should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n // IBC transfer packets will timeout after this interval elapses.\n "transfer_timeout_period": 1800000000000,\n // The fraction of tokens allocated to the consumer redistribution address during distribution events.\n // The fraction is a string representing a decimal number. For example "0.75" would represent 75%.\n // The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.\n "consumer_redistribution_fraction": "0.75",\n // BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.\n // eg. send rewards to the provider every 1000 blocks\n "blocks_per_distribution_transmission": 1000,\n // The number of historical info entries to persist in store.\n // This param is a part of the cosmos sdk staking module. In the case of\n // a ccv enabled consumer chain, the ccv module acts as the staking module.\n "historical_entries": 10000,\n // The ID of a token transfer channel used for the Reward Distribution\n // sub-protocol. If DistributionTransmissionChannel == "", a new transfer\n // channel is created on top of the same connection as the CCV channel.\n // Note that transfer_channel_id is the ID of the channel end on the consumer chain.\n // it is most relevant for chains performing a standalone to consumer changeover\n // in order to maintan the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123" // NOTE: use existing transfer channel if available\n}\n')),(0,i.kt)("h2",{id:"3-submit-an-upgrade-proposal--prepare-for-changeover"},"3. Submit an Upgrade Proposal & Prepare for Changeover"),(0,i.kt)("p",null,"This proposal should add the ccv ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer")," module to your chain."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","proposal ",(0,i.kt)("inlineCode",{parentName:"li"},"upgrade_height")," must happen after ",(0,i.kt)("inlineCode",{parentName:"li"},"spawn_time")," in the ",(0,i.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal")),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","advise validators about the exact procedure for your chain and point them to your onboarding repository")),(0,i.kt)("h2",{id:"4-upgrade-time-"},"4. Upgrade time \ud83d\ude80"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","after ",(0,i.kt)("inlineCode",{parentName:"li"},"spawn_time"),", request ",(0,i.kt)("inlineCode",{parentName:"li"},"ConsumerGenesis")," from the ",(0,i.kt)("inlineCode",{parentName:"li"},"provider")," and place it in ",(0,i.kt)("inlineCode",{parentName:"li"},"<CURRENT_USER_HOME_DIR>/.sovereign/config/genesis.json")),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","upgrade the binary to the one listed in your ",(0,i.kt)("inlineCode",{parentName:"li"},"UpgradeProposal"))),(0,i.kt)("p",null,'The chain starts after at least 66.67% of standalone voting power comes online. The consumer chain is considered interchain secured once the "old" validator set signs a couple of blocks and transfers control to the ',(0,i.kt)("inlineCode",{parentName:"p"},"provider")," validator set."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","provide a repo with onboarding instructions for validators (it should already be listed in the proposal)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json after ",(0,i.kt)("inlineCode",{parentName:"li"},"spawn_time")," obtained from ",(0,i.kt)("inlineCode",{parentName:"li"},"provider")," (MUST contain the initial validator set)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/89638eb3.c12ace70.js b/legacy/assets/js/89638eb3.c12ace70.js new file mode 100644 index 0000000000..81038f19fd --- /dev/null +++ b/legacy/assets/js/89638eb3.c12ace70.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[818],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},o=Object.keys(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(r),m=i,f=d["".concat(l,".").concat(m)]||d[m]||u[m]||o;return r?n.createElement(f,a(a({ref:t},p),{},{components:r})):n.createElement(f,a({ref:t},p))}));function f(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=r.length,a=new Array(o);a[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:i,a[1]=s;for(var c=2;c<o;c++)a[c]=r[c];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},5882:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var n=r(7462),i=(r(7294),r(3905));const o={sidebar_position:6},a="Joining Stride",s={unversionedId:"validators/joining-stride",id:"version-v3.3.1-lsm/validators/joining-stride",title:"Joining Stride",description:"Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.",source:"@site/versioned_docs/version-v3.3.1-lsm/validators/joining-stride.md",sourceDirName:"validators",slug:"/validators/joining-stride",permalink:"/interchain-security/legacy/validators/joining-stride",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"tutorialSidebar",previous:{title:"Joining Neutron",permalink:"/interchain-security/legacy/validators/joining-neutron"},next:{title:"Frequently Asked Questions",permalink:"/interchain-security/legacy/faq"}},l={},c=[{value:"Note",id:"note",level:2},{value:"Resources",id:"resources",level:2}],p={toc:c},d="wrapper";function u(e){let{components:t,...r}=e;return(0,i.kt)(d,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"joining-stride"},"Joining Stride"),(0,i.kt)("p",null,"Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using ",(0,i.kt)("inlineCode",{parentName:"p"},"cosmoshub-4")," validator set."),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"stride-1")," network (mainnet) will perform a software upgrade and at height ",(0,i.kt)("inlineCode",{parentName:"p"},"4616678")," that will transition the network to using the Cosmos Hub's (",(0,i.kt)("inlineCode",{parentName:"p"},"cosmoshub-4"),") validator set."),(0,i.kt)("p",null," You can find instructions about the Stride consumer chain launch and joining the mainnet ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/Stride-Labs/mainnet/tree/main/ics-instructions"},"here"),"."),(0,i.kt)("p",null," This ",(0,i.kt)("a",{parentName:"p",href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt"},"Excalidraw graphic")," explains the timeline of Stride's changeover procedure."),(0,i.kt)("h2",{id:"note"},"Note"),(0,i.kt)("p",null,"Stride re-uses an existing ",(0,i.kt)("inlineCode",{parentName:"p"},"transfer")," channel to send consumer rewards to the provider chain, in order to preserve existing transfer IBC denom between ",(0,i.kt)("inlineCode",{parentName:"p"},"stride-1")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"cosmoshub-4"),"."),(0,i.kt)("h2",{id:"resources"},"Resources"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://docs.stride.zone/docs"},"Stride docs")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt"},"Changeover procedure timeline")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/Stride-Labs/mainnet/tree/main/ics-instructions"},"Changeover upgrade docs"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/8e91dc0c.36e2e9b4.js b/legacy/assets/js/8e91dc0c.36e2e9b4.js new file mode 100644 index 0000000000..baa8556644 --- /dev/null +++ b/legacy/assets/js/8e91dc0c.36e2e9b4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2098],{3905:(e,n,t)=>{t.d(n,{Zo:()=>c,kt:()=>h});var r=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,r,o=function(e,n){if(null==e)return{};var t,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=r.createContext({}),p=function(e){var n=r.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},c=function(e){var n=p(e.components);return r.createElement(l.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=p(t),m=o,h=d["".concat(l,".").concat(m)]||d[m]||u[m]||a;return t?r.createElement(h,i(i({ref:n},c),{},{components:t})):r.createElement(h,i({ref:n},c))}));function h(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=m;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:o,i[1]=s;for(var p=2;p<a;p++)i[p]=t[p];return r.createElement.apply(null,i)}return r.createElement.apply(null,t)}m.displayName="MDXCreateElement"},8081:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>s,toc:()=>p});var r=t(7462),o=(t(7294),t(3905));const a={sidebar_position:3},i="ICS Provider Proposals",s={unversionedId:"features/proposals",id:"version-v3.3.0/features/proposals",title:"ICS Provider Proposals",description:"Interchain security module introduces 3 new proposal types to the provider.",source:"@site/versioned_docs/version-v3.3.0/features/proposals.md",sourceDirName:"features",slug:"/features/proposals",permalink:"/interchain-security/legacy/v3.3.0/features/proposals",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Reward distribution",permalink:"/interchain-security/legacy/v3.3.0/features/reward-distribution"},next:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/legacy/v3.3.0/features/slashing"}},l={},p=[{value:"<code>ConsumerAdditionProposal</code>",id:"consumeradditionproposal",level:2},{value:"<code>ConsumerRemovalProposal</code>",id:"consumerremovalproposal",level:2},{value:"ChangeRewardDenomProposal",id:"changerewarddenomproposal",level:2}],c={toc:p},d="wrapper";function u(e){let{components:n,...t}=e;return(0,o.kt)(d,(0,r.Z)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"ics-provider-proposals"},"ICS Provider Proposals"),(0,o.kt)("p",null,"Interchain security module introduces 3 new proposal types to the provider."),(0,o.kt)("p",null,"The proposals are used to propose upcoming interchain security events through governance."),(0,o.kt)("h2",{id:"consumeradditionproposal"},(0,o.kt)("inlineCode",{parentName:"h2"},"ConsumerAdditionProposal")),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"If you are preparing a ",(0,o.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," you can find more information in the ",(0,o.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/consumer-development/onboarding"},"consumer onboarding checklist"),".")),(0,o.kt)("p",null,"Proposal type used to suggest adding a new consumer chain."),(0,o.kt)("p",null,"When proposals of this type are passed and the ",(0,o.kt)("inlineCode",{parentName:"p"},"spawn_time")," specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain."),(0,o.kt)("p",null,"Minimal example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'{\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n "title": "Add consumer chain",\n "description": ".md description of your chain and all other relevant information",\n "chain_id": "newchain-1",\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Unbonding period for the consumer chain.\n // It should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n "transfer_timeout_period": 1800000000000,\n "consumer_redistribution_fraction": "0.75",\n "blocks_per_distribution_transmission": 1000,\n "historical_entries": 10000,\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1"\n // relevant for chains performing a sovereign to consumer changeover\n // in order to maintain the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123"\n}\n')),(0,o.kt)("p",null,"More examples can be found in the replicated security testnet repository ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/stopped/baryon-1/proposal-baryon-1.json"},"here")," and ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/stopped/noble-1/start-proposal-noble-1.json"},"here"),"."),(0,o.kt)("h2",{id:"consumerremovalproposal"},(0,o.kt)("inlineCode",{parentName:"h2"},"ConsumerRemovalProposal")),(0,o.kt)("p",null,"Proposal type used to suggest removing an existing consumer chain."),(0,o.kt)("p",null,"When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain.\nAfter the consumer chain removal, the chain in question will no longer be secured by the provider's validator set."),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain.\nAdditional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set.\nMore information will be made available in the ",(0,o.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/consumer-development/offboarding"},"Consumer Offboarding Checklist"),".")),(0,o.kt)("p",null,"Minimal example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'{\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details"\n}\n')),(0,o.kt)("h2",{id:"changerewarddenomproposal"},"ChangeRewardDenomProposal"),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"ChangeRewardDenomProposal")," will only be accepted on the provider chain if at least one of the denomsToAdd or denomsToRemove fields is populated with at least one denom. Also, a denom cannot be repeated in both sets.")),(0,o.kt)("p",null,"Proposal type used to mutate the set of denoms accepted by the provider as rewards."),(0,o.kt)("p",null,"Minimal example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'{\n "title": "Add untrn as a reward denom",\n "description": "Here is more information about the proposal",\n "denomsToAdd": ["untrn"],\n "denomsToRemove": []\n}\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/8fb9dc62.61dd95c4.js b/legacy/assets/js/8fb9dc62.61dd95c4.js new file mode 100644 index 0000000000..6f4f5dee76 --- /dev/null +++ b/legacy/assets/js/8fb9dc62.61dd95c4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6960],{3905:(e,r,t)=>{t.d(r,{Zo:()=>c,kt:()=>w});var n=t(7294);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function o(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?i(Object(t),!0).forEach((function(r){a(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function s(e,r){if(null==e)return{};var t,n,a=function(e,r){if(null==e)return{};var t,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=n.createContext({}),d=function(e){var r=n.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):o(o({},r),e)),t},c=function(e){var r=d(e.components);return n.createElement(l.Provider,{value:r},e.children)},m="mdxType",p={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},u=n.forwardRef((function(e,r){var t=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),m=d(t),u=a,w=m["".concat(l,".").concat(u)]||m[u]||p[u]||i;return t?n.createElement(w,o(o({ref:r},c),{},{components:t})):n.createElement(w,o({ref:r},c))}));function w(e,r){var t=arguments,a=r&&r.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=u;var s={};for(var l in r)hasOwnProperty.call(r,l)&&(s[l]=r[l]);s.originalType=e,s[m]="string"==typeof e?e:a,o[1]=s;for(var d=2;d<i;d++)o[d]=t[d];return n.createElement.apply(null,o)}return n.createElement.apply(null,t)}u.displayName="MDXCreateElement"},4184:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>d});var n=t(7462),a=(t(7294),t(3905));const i={},o="Withdrawing consumer chain validator rewards",s={unversionedId:"validators/withdraw_rewards",id:"version-v2.0.0/validators/withdraw_rewards",title:"Withdrawing consumer chain validator rewards",description:"Here are example steps for withdrawing rewards from consumer chains in the provider chain",source:"@site/versioned_docs/version-v2.0.0/validators/withdraw_rewards.md",sourceDirName:"validators",slug:"/validators/withdraw_rewards",permalink:"/interchain-security/legacy/v2.0.0/validators/withdraw_rewards",draft:!1,tags:[],version:"v2.0.0",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Joining Replicated Security testnet",permalink:"/interchain-security/legacy/v2.0.0/validators/joining-testnet"},next:{title:"Frequently Asked Questions",permalink:"/interchain-security/legacy/v2.0.0/faq"}},l={},d=[{value:"Querying validator rewards",id:"querying-validator-rewards",level:2},{value:"Withdrawing rewards and commission",id:"withdrawing-rewards-and-commission",level:2},{value:"1. Withdraw rewards",id:"1-withdraw-rewards",level:3},{value:"2. Confirm withdrawal",id:"2-confirm-withdrawal",level:3}],c={toc:d},m="wrapper";function p(e){let{components:r,...t}=e;return(0,a.kt)(m,(0,n.Z)({},c,t,{components:r,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"withdrawing-consumer-chain-validator-rewards"},"Withdrawing consumer chain validator rewards"),(0,a.kt)("p",null,"Here are example steps for withdrawing rewards from consumer chains in the provider chain"),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The examples used are from ",(0,a.kt)("inlineCode",{parentName:"p"},"rs-testnet"),", the replicated security persistent testnet."),(0,a.kt)("p",{parentName:"admonition"},"Validator operator address: ",(0,a.kt)("inlineCode",{parentName:"p"},"cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6"),"\nSelf-delegation address: ",(0,a.kt)("inlineCode",{parentName:"p"},"cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf"))),(0,a.kt)("p",null,"Prior to withdrawing rewards, query balances for self-delegation address:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "1000000000000"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n')),(0,a.kt)("h2",{id:"querying-validator-rewards"},"Querying validator rewards"),(0,a.kt)("p",null,"Query rewards for the validator address:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6\n\nrewards:\n- amount: "158.069895000000000000"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "841842390516.072526500000000000"\n denom: uatom\n')),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD")," denom represents rewards from a consumer chain."),(0,a.kt)("h2",{id:"withdrawing-rewards-and-commission"},"Withdrawing rewards and commission"),(0,a.kt)("h3",{id:"1-withdraw-rewards"},"1. Withdraw rewards"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y\n\ntxhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A\n")),(0,a.kt)("h3",{id:"2-confirm-withdrawal"},"2. Confirm withdrawal"),(0,a.kt)("p",null,"After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "216"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "2233766225342"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n')))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/903c2771.ebeb1a28.js b/legacy/assets/js/903c2771.ebeb1a28.js new file mode 100644 index 0000000000..2f366e293e --- /dev/null +++ b/legacy/assets/js/903c2771.ebeb1a28.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6054],{3905:(e,t,o)=>{o.d(t,{Zo:()=>c,kt:()=>m});var n=o(7294);function a(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function r(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,n)}return o}function i(e){for(var t=1;t<arguments.length;t++){var o=null!=arguments[t]?arguments[t]:{};t%2?r(Object(o),!0).forEach((function(t){a(e,t,o[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(o)):r(Object(o)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(o,t))}))}return e}function l(e,t){if(null==e)return{};var o,n,a=function(e,t){if(null==e)return{};var o,n,a={},r=Object.keys(e);for(n=0;n<r.length;n++)o=r[n],t.indexOf(o)>=0||(a[o]=e[o]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n<r.length;n++)o=r[n],t.indexOf(o)>=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(a[o]=e[o])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),o=t;return e&&(o="function"==typeof e?e(t):i(i({},t),e)),o},c=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var o=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),p=u(o),h=a,m=p["".concat(s,".").concat(h)]||p[h]||d[h]||r;return o?n.createElement(m,i(i({ref:t},c),{},{components:o})):n.createElement(m,i({ref:t},c))}));function m(e,t){var o=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=o.length,i=new Array(r);i[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:a,i[1]=l;for(var u=2;u<r;u++)i[u]=o[u];return n.createElement.apply(null,i)}return n.createElement.apply(null,o)}h.displayName="MDXCreateElement"},8896:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>r,metadata:()=>l,toc:()=>u});var n=o(7462),a=(o(7294),o(3905));const r={sidebar_position:10,title:"Soft Opt-Out"},i=void 0,l={unversionedId:"adrs/adr-009-soft-opt-out",id:"adrs/adr-009-soft-opt-out",title:"Soft Opt-Out",description:"ADR 009: Soft Opt-Out",source:"@site/docs/adrs/adr-009-soft-opt-out.md",sourceDirName:"adrs",slug:"/adrs/adr-009-soft-opt-out",permalink:"/interchain-security/legacy/adrs/adr-009-soft-opt-out",draft:!1,tags:[],version:"current",sidebarPosition:10,frontMatter:{sidebar_position:10,title:"Soft Opt-Out"},sidebar:"tutorialSidebar",previous:{title:"Throttle with retries",permalink:"/interchain-security/legacy/adrs/adr-008-throttle-retries"},next:{title:"Standalone to Consumer Changeover",permalink:"/interchain-security/legacy/adrs/adr-010-standalone-changeover"}},s={},u=[{value:"ADR 009: Soft Opt-Out",id:"adr-009-soft-opt-out",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],c={toc:u},p="wrapper";function d(e){let{components:t,...o}=e;return(0,a.kt)(p,(0,n.Z)({},c,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"adr-009-soft-opt-out"},"ADR 009: Soft Opt-Out"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"6/13/23: Initial draft of ADR. Feature already implemented and in production.")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"Some small validators may not have the resources needed to validate all consumer chains. Therefore a need exists to allow the bottom ",(0,a.kt)("inlineCode",{parentName:"p"},"x%")," of validators to opt-out of validating a consumer chain. Meaning downtime infractions for these validators are dropped without ever reaching the provider."),(0,a.kt)("p",null,"This document specifies a modification to the ccv protocol which allows the bottom x% of the validator set by power to opt out of validating consumer chains without being jailed or otherwise punished for it. The feature is implemented with entirely consumer-side code."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"A consumer param exists, known as ",(0,a.kt)("inlineCode",{parentName:"p"},"SoftOptOutThreshold"),", which is a string decimal in the range of ","[0, 0.2]",", that determines the portion of validators which are allowed to opt out of validating that specific consumer."),(0,a.kt)("p",null,"In every consumer beginblocker, a function is ran which determines the so called ",(0,a.kt)("em",{parentName:"p"},"smallest non opt-out voting power"),". Validators with voting power greater than or equal to this value must validate the consumer chain, while validators below this value may opt out of validating the consumer chain."),(0,a.kt)("p",null,"The smallest non opt-out voting power is recomputed every beginblocker in ",(0,a.kt)("inlineCode",{parentName:"p"},"UpdateSmallestNonOptOutPower()"),". In a nutshell, the method obtains the total voting power of the consumer, iterates through the full valset (ordered power ascending) keeping track of a power sum, and when ",(0,a.kt)("inlineCode",{parentName:"p"},"powerSum / totalPower > SoftOptOutThreshold"),", the ",(0,a.kt)("inlineCode",{parentName:"p"},"SmallestNonOptOutPower")," is found and persisted."),(0,a.kt)("p",null,"Then, whenever the ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash()")," interface is executed on the consumer, if the voting power of the relevant validator being slashed is less than ",(0,a.kt)("inlineCode",{parentName:"p"},"SmallestNonOptOutPower")," for that block, the slash request is dropped and never sent to the provider."),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Small validators can opt out of validating specific consumers without being punished for it.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"The bottom ",(0,a.kt)("inlineCode",{parentName:"li"},"x%")," is still part of the total voting power of the consumer chain. This means that if the soft opt-out threshold is set to ",(0,a.kt)("inlineCode",{parentName:"li"},"10%")," for example, and every validator in the bottom ",(0,a.kt)("inlineCode",{parentName:"li"},"10%")," opts out from validating the consumer, then a ",(0,a.kt)("inlineCode",{parentName:"li"},"24%")," downtime of the remaining voting power would halt the chain. This may be especially problematic during consumer upgrades."),(0,a.kt)("li",{parentName:"ul"},"In nominal scenarios, consumers with soft opt out enabled will be constructing slash packets for small vals, which may be dropped. This is wasted computation, but necessary to keep implementation simple. Note that the sdk's ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/cosmos-sdk/blob/d3f09c222243bb3da3464969f0366330dcb977a8/x/slashing/keeper/infractions.go#L75"},"full downtime logic")," is always executed on the consumer, which can be computationally expensive and slow down certain blocks.")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Validators in the bottom of the valset who don't have to validate, may receive large delegation(s) which suddenly boost the validator to the subset that has to validate. This may catch the validator off guard.")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Original issue with some napkin math ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/784"},"#784"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/90a8ce65.0ab58bcb.js b/legacy/assets/js/90a8ce65.0ab58bcb.js new file mode 100644 index 0000000000..1d58a5a694 --- /dev/null +++ b/legacy/assets/js/90a8ce65.0ab58bcb.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2749],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),c=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),m=a,h=u["".concat(l,".").concat(m)]||u[m]||d[m]||i;return n?o.createElement(h,r(r({ref:t},p),{},{components:n})):o.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,r=new Array(i);r[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,r[1]=s;for(var c=2;c<i;c++)r[c]=n[c];return o.createElement.apply(null,r)}return o.createElement.apply(null,n)}m.displayName="MDXCreateElement"},3794:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var o=n(7462),a=(n(7294),n(3905));const i={sidebar_position:4,title:"Equivocation governance proposal"},r="ADR 003: Equivocation governance proposal",s={unversionedId:"adrs/adr-003-equivocation-gov-proposal",id:"version-v3.3.0/adrs/adr-003-equivocation-gov-proposal",title:"Equivocation governance proposal",description:"Changelog",source:"@site/versioned_docs/version-v3.3.0/adrs/adr-003-equivocation-gov-proposal.md",sourceDirName:"adrs",slug:"/adrs/adr-003-equivocation-gov-proposal",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-003-equivocation-gov-proposal",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Equivocation governance proposal"},sidebar:"tutorialSidebar",previous:{title:"Jail Throttling",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-002-throttle"},next:{title:"Cryptographic verification of equivocation evidence",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-005-cryptographic-equivocation-verification"}},l={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],p={toc:c},u="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-003-equivocation-governance-proposal"},"ADR 003: Equivocation governance proposal"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"2023-02-06: Initial draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain."),(0,a.kt)("p",null,"For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain."),(0,a.kt)("p",null,"A new kind of governance proposal is added to the ",(0,a.kt)("inlineCode",{parentName:"p"},"provider")," module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain."),(0,a.kt)("p",null,"If such proposal passes, the proposal handler delegates to the ",(0,a.kt)("inlineCode",{parentName:"p"},"evidence")," module to process the equivocation. This module ensures the evidence isn\u2019t too old, or else ignores it (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/21021b837882d1d40f1d79bcbc4fad2e79a3fefe/x/evidence/keeper/infraction.go#L54-L62"},"code"),"). ",(0,a.kt)("em",{parentName:"p"},"Too old")," is determined by 2 consensus params : "),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"evidence.max_age_duration")," number of nanoseconds before an evidence is considered too old"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"evidence.max_age_numblocks")," number of blocks before an evidence is considered too old.")),(0,a.kt)("p",null,"On the hub, those parameters are equals to "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682\n(...)\n"evidence": {\n "max_age_num_blocks": "1000000",\n "max_age_duration": "172800000000000",\n (...)\n},\n(...)\n')),(0,a.kt)("p",null,"A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the ",(0,a.kt)("inlineCode",{parentName:"p"},"evidence")," module when the proposal passes and is handled by the hub."),(0,a.kt)("p",null,"For ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks=1M"),", the parameter is big enough if we consider the hub produces 12k blocks per day (",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_year/365 = 436,0000/365"),"). The evidence can be up to 83 days old (",(0,a.kt)("inlineCode",{parentName:"p"},"1,000,000/12,000"),") and not be ignored."),(0,a.kt)("p",null,"For ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_duration=172,800,000,000,000"),", the parameter is too low, because the value is in nanoseconds so it\u2019s 2 days. Fortunately the condition that checks those 2 parameters uses a ",(0,a.kt)("strong",{parentName:"p"},"AND"),", so if ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks")," condition passes, the evidence won\u2019t be ignored."),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Remove the possibility from a malicious consumer chain to \u201cattack\u201d the provider chain by slashing/jailing validators."),(0,a.kt)("li",{parentName:"ul"},"Provide a more acceptable implementation for the validator community.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Punishment action of double-signing isn\u2019t \u201cautomated\u201d, a governance proposal is required which takes more time."),(0,a.kt)("li",{parentName:"ul"},"You need to pay 250ATOM to submit an equivocation evidence.")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"PR that ignores non downtime slash packet : ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/692"},"https://github.com/cosmos/interchain-security/pull/692")),(0,a.kt)("li",{parentName:"ul"},"PR that adds the governance slash proposal: ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/703"},"https://github.com/cosmos/interchain-security/pull/703"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/91cc339f.5ff44e54.js b/legacy/assets/js/91cc339f.5ff44e54.js new file mode 100644 index 0000000000..8716bdce9b --- /dev/null +++ b/legacy/assets/js/91cc339f.5ff44e54.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1298],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>m});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=c(n),h=a,m=d["".concat(s,".").concat(h)]||d[h]||p[h]||o;return n?r.createElement(m,i(i({ref:t},u),{},{components:n})):r.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,i[1]=l;for(var c=2;c<o;c++)i[c]=n[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}h.displayName="MDXCreateElement"},2732:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const o={sidebar_position:2,title:"ADR Template"},i="ADR {ADR-NUMBER}:",l={unversionedId:"adrs/adr-template",id:"version-v3.2.0/adrs/adr-template",title:"ADR Template",description:"Changelog",source:"@site/versioned_docs/version-v3.2.0/adrs/adr-template.md",sourceDirName:"adrs",slug:"/adrs/adr-template",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-template",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"ADR Template"},sidebar:"tutorialSidebar",previous:{title:"ADR Template",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop"},next:{title:"Key Assignment",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-001-key-assignment"}},s={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],u={toc:c},d="wrapper";function p(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-adr-number-title"},"ADR {ADR-NUMBER}: {TITLE}"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"{date}: {changelog}")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},'A decision may be "proposed" if it hasn\'t been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement.')),(0,a.kt)("p",null,"{Deprecated|Proposed|Accepted}"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution. ")),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"This section explains all of the details of the proposed solution, including implementation details.\nIt should also describe affects / corollary items that may need to be changed as a part of this.\nIf the proposed change will be large, please also indicate a way to do the change to maximize ease of review.\n(e.g. the optimal split of things to do between separate PR's)")),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},'This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones.')),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"{reference link}")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/935f2afb.64bd8468.js b/legacy/assets/js/935f2afb.64bd8468.js new file mode 100644 index 0000000000..5367b3aeed --- /dev/null +++ b/legacy/assets/js/935f2afb.64bd8468.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[53],{1109:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"current","label":"Next","banner":"unreleased","badge":true,"noIndex":false,"className":"docs-version-current","isLast":false,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Interchain Security Docs","href":"/interchain-security/legacy/","docId":"index"},{"type":"category","label":"Introduction","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/legacy/introduction/overview","docId":"introduction/overview"},{"type":"link","label":"Terminology","href":"/interchain-security/legacy/introduction/terminology","docId":"introduction/terminology"},{"type":"link","label":"Interchain Security Parameters","href":"/interchain-security/legacy/introduction/params","docId":"introduction/params"},{"type":"link","label":"Technical Specification","href":"/interchain-security/legacy/introduction/technical-specification","docId":"introduction/technical-specification"}]},{"type":"category","label":"Features","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Key Assignment","href":"/interchain-security/legacy/features/key-assignment","docId":"features/key-assignment"},{"type":"link","label":"Reward distribution","href":"/interchain-security/legacy/features/reward-distribution","docId":"features/reward-distribution"},{"type":"link","label":"ICS Provider Proposals","href":"/interchain-security/legacy/features/proposals","docId":"features/proposals"},{"type":"link","label":"Consumer Initiated Slashing","href":"/interchain-security/legacy/features/slashing","docId":"features/slashing"}]},{"type":"category","label":"Consumer Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Developing an ICS consumer chain","href":"/interchain-security/legacy/consumer-development/app-integration","docId":"consumer-development/app-integration"},{"type":"link","label":"Consumer Chain Governance","href":"/interchain-security/legacy/consumer-development/consumer-chain-governance","docId":"consumer-development/consumer-chain-governance"},{"type":"link","label":"Onboarding Checklist","href":"/interchain-security/legacy/consumer-development/onboarding","docId":"consumer-development/onboarding"},{"type":"link","label":"Offboarding Checklist","href":"/interchain-security/legacy/consumer-development/offboarding","docId":"consumer-development/offboarding"},{"type":"link","label":"Changeover Procedure","href":"/interchain-security/legacy/consumer-development/changeover-procedure","docId":"consumer-development/changeover-procedure"},{"type":"link","label":"Consumer Genesis Transformation","href":"/interchain-security/legacy/consumer-development/consumer-genesis-transformation","docId":"consumer-development/consumer-genesis-transformation"}]},{"type":"category","label":"Validators Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/legacy/validators/overview","docId":"validators/overview"},{"type":"link","label":"Joining Replicated Security testnet","href":"/interchain-security/legacy/validators/joining-testnet","docId":"validators/joining-testnet"},{"type":"link","label":"Withdrawing consumer chain validator rewards","href":"/interchain-security/legacy/validators/withdraw_rewards","docId":"validators/withdraw_rewards"},{"type":"link","label":"Validator instructions for Changeover Procedure","href":"/interchain-security/legacy/validators/changeover-procedure","docId":"validators/changeover-procedure"},{"type":"link","label":"Joining Neutron","href":"/interchain-security/legacy/validators/joining-neutron","docId":"validators/joining-neutron"},{"type":"link","label":"Joining Stride","href":"/interchain-security/legacy/validators/joining-stride","docId":"validators/joining-stride"}]},{"type":"link","label":"Frequently Asked Questions","href":"/interchain-security/legacy/faq","docId":"frequently-asked-questions"},{"type":"category","label":"ADRs","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"ADRs","href":"/interchain-security/legacy/adrs/intro","docId":"adrs/intro"},{"type":"link","label":"ADR Template","href":"/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop","docId":"adrs/adr-007-pause-unbonding-on-eqv-prop"},{"type":"link","label":"ADR Template","href":"/interchain-security/legacy/adrs/adr-template","docId":"adrs/adr-template"},{"type":"link","label":"Key Assignment","href":"/interchain-security/legacy/adrs/adr-001-key-assignment","docId":"adrs/adr-001-key-assignment"},{"type":"link","label":"Jail Throttling","href":"/interchain-security/legacy/adrs/adr-002-throttle","docId":"adrs/adr-002-throttle"},{"type":"link","label":"Equivocation governance proposal","href":"/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposal","docId":"adrs/adr-003-equivocation-gov-proposal"},{"type":"link","label":"Cryptographic verification of equivocation evidence","href":"/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification","docId":"adrs/adr-005-cryptographic-equivocation-verification"},{"type":"link","label":"Throttle with retries","href":"/interchain-security/legacy/adrs/adr-008-throttle-retries","docId":"adrs/adr-008-throttle-retries"},{"type":"link","label":"Soft Opt-Out","href":"/interchain-security/legacy/adrs/adr-009-soft-opt-out","docId":"adrs/adr-009-soft-opt-out"},{"type":"link","label":"Standalone to Consumer Changeover","href":"/interchain-security/legacy/adrs/adr-010-standalone-changeover","docId":"adrs/adr-010-standalone-changeover"},{"type":"link","label":"Improving testing and increasing confidence","href":"/interchain-security/legacy/adrs/adr-011-improving-test-confidence","docId":"adrs/adr-011-improving-test-confidence"},{"type":"link","label":"Separate Releasing","href":"/interchain-security/legacy/adrs/adr-012-separate-releasing","docId":"adrs/adr-012-separate-releasing"},{"type":"link","label":"Slashing on the provider for consumer equivocation","href":"/interchain-security/legacy/adrs/adr-013-equivocation-slashing","docId":"adrs/adr-013-equivocation-slashing"}]}]},"docs":{"adrs/adr-001-key-assignment":{"id":"adrs/adr-001-key-assignment","title":"Key Assignment","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-002-throttle":{"id":"adrs/adr-002-throttle","title":"Jail Throttling","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-003-equivocation-gov-proposal":{"id":"adrs/adr-003-equivocation-gov-proposal","title":"Equivocation governance proposal","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-005-cryptographic-equivocation-verification":{"id":"adrs/adr-005-cryptographic-equivocation-verification","title":"Cryptographic verification of equivocation evidence","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-007-pause-unbonding-on-eqv-prop":{"id":"adrs/adr-007-pause-unbonding-on-eqv-prop","title":"ADR Template","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-008-throttle-retries":{"id":"adrs/adr-008-throttle-retries","title":"Throttle with retries","description":"ADR 008: Throttle with retries","sidebar":"tutorialSidebar"},"adrs/adr-009-soft-opt-out":{"id":"adrs/adr-009-soft-opt-out","title":"Soft Opt-Out","description":"ADR 009: Soft Opt-Out","sidebar":"tutorialSidebar"},"adrs/adr-010-standalone-changeover":{"id":"adrs/adr-010-standalone-changeover","title":"Standalone to Consumer Changeover","description":"ADR 010: Standalone to Consumer Changeover","sidebar":"tutorialSidebar"},"adrs/adr-011-improving-test-confidence":{"id":"adrs/adr-011-improving-test-confidence","title":"Improving testing and increasing confidence","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-012-separate-releasing":{"id":"adrs/adr-012-separate-releasing","title":"Separate Releasing","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-013-equivocation-slashing":{"id":"adrs/adr-013-equivocation-slashing","title":"Slashing on the provider for consumer equivocation","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-template":{"id":"adrs/adr-template","title":"ADR Template","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/intro":{"id":"adrs/intro","title":"ADRs","description":"This is a location to record all high-level architecture decisions in the Interchain Security project.","sidebar":"tutorialSidebar"},"consumer-development/app-integration":{"id":"consumer-development/app-integration","title":"Developing an ICS consumer chain","description":"When developing an ICS consumer chain, besides just focusing on your chain\'s logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.","sidebar":"tutorialSidebar"},"consumer-development/changeover-procedure":{"id":"consumer-development/changeover-procedure","title":"Changeover Procedure","description":"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.","sidebar":"tutorialSidebar"},"consumer-development/consumer-chain-governance":{"id":"consumer-development/consumer-chain-governance","title":"Consumer Chain Governance","description":"Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the \\"Whitelist\\" section below.","sidebar":"tutorialSidebar"},"consumer-development/consumer-genesis-transformation":{"id":"consumer-development/consumer-genesis-transformation","title":"Consumer Genesis Transformation","description":"Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentaion on Onboarding and Changeover).","sidebar":"tutorialSidebar"},"consumer-development/offboarding":{"id":"consumer-development/offboarding","title":"Offboarding Checklist","description":"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).","sidebar":"tutorialSidebar"},"consumer-development/onboarding":{"id":"consumer-development/onboarding","title":"Onboarding Checklist","description":"The following checklists will aid in onboarding a new consumer chain to replicated security.","sidebar":"tutorialSidebar"},"features/key-assignment":{"id":"features/key-assignment","title":"Key Assignment","description":"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.","sidebar":"tutorialSidebar"},"features/proposals":{"id":"features/proposals","title":"ICS Provider Proposals","description":"Interchain security module introduces 3 new proposal types to the provider.","sidebar":"tutorialSidebar"},"features/reward-distribution":{"id":"features/reward-distribution","title":"Reward distribution","description":"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.","sidebar":"tutorialSidebar"},"features/slashing":{"id":"features/slashing","title":"Consumer Initiated Slashing","description":"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.","sidebar":"tutorialSidebar"},"frequently-asked-questions":{"id":"frequently-asked-questions","title":"Frequently Asked Questions","description":"What is the meaning of Validator Set Replication?","sidebar":"tutorialSidebar"},"index":{"id":"index","title":"Interchain Security Docs","description":"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.","sidebar":"tutorialSidebar"},"introduction/overview":{"id":"introduction/overview","title":"Overview","description":"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.","sidebar":"tutorialSidebar"},"introduction/params":{"id":"introduction/params","title":"Interchain Security Parameters","description":"The parameters necessary for Interchain Security (ICS) are defined in","sidebar":"tutorialSidebar"},"introduction/technical-specification":{"id":"introduction/technical-specification","title":"Technical Specification","description":"For a technical deep dive into the replicated security protocol, see the specification.","sidebar":"tutorialSidebar"},"introduction/terminology":{"id":"introduction/terminology","title":"Terminology","description":"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.","sidebar":"tutorialSidebar"},"validators/changeover-procedure":{"id":"validators/changeover-procedure","title":"Validator instructions for Changeover Procedure","description":"More details available in Changeover Procedure documentation.","sidebar":"tutorialSidebar"},"validators/joining-neutron":{"id":"validators/joining-neutron","title":"Joining Neutron","description":"Neutron is the first consumer chain to implement ICS.","sidebar":"tutorialSidebar"},"validators/joining-stride":{"id":"validators/joining-stride","title":"Joining Stride","description":"Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.","sidebar":"tutorialSidebar"},"validators/joining-testnet":{"id":"validators/joining-testnet","title":"Joining Replicated Security testnet","description":"Introduction","sidebar":"tutorialSidebar"},"validators/overview":{"id":"validators/overview","title":"Overview","description":"We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.","sidebar":"tutorialSidebar"},"validators/withdraw_rewards":{"id":"validators/withdraw_rewards","title":"Withdrawing consumer chain validator rewards","description":"Here are example steps for withdrawing rewards from consumer chains in the provider chain","sidebar":"tutorialSidebar"}}}')}}]); \ No newline at end of file diff --git a/legacy/assets/js/95875ea0.6ffcab52.js b/legacy/assets/js/95875ea0.6ffcab52.js new file mode 100644 index 0000000000..e934fb60a9 --- /dev/null +++ b/legacy/assets/js/95875ea0.6ffcab52.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3813],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=l(n),u=i,h=d["".concat(c,".").concat(u)]||d[u]||m[u]||o;return n?a.createElement(h,r(r({ref:t},p),{},{components:n})):a.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=u;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:i,r[1]=s;for(var l=2;l<o;l++)r[l]=n[l];return a.createElement.apply(null,r)}return a.createElement.apply(null,n)}u.displayName="MDXCreateElement"},1670:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>m,frontMatter:()=>o,metadata:()=>s,toc:()=>l});var a=n(7462),i=(n(7294),n(3905));const o={sidebar_position:3,title:"Onboarding Checklist"},r="Consumer Onboarding Checklist",s={unversionedId:"consumer-development/onboarding",id:"consumer-development/onboarding",title:"Onboarding Checklist",description:"The following checklists will aid in onboarding a new consumer chain to replicated security.",source:"@site/docs/consumer-development/onboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/onboarding",permalink:"/interchain-security/legacy/consumer-development/onboarding",draft:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Onboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Consumer Chain Governance",permalink:"/interchain-security/legacy/consumer-development/consumer-chain-governance"},next:{title:"Offboarding Checklist",permalink:"/interchain-security/legacy/consumer-development/offboarding"}},c={},l=[{value:"1. Complete testing & integration",id:"1-complete-testing--integration",level:2},{value:"2. Create an Onboarding Repository",id:"2-create-an-onboarding-repository",level:2},{value:"3. Submit a Governance Proposal",id:"3-submit-a-governance-proposal",level:2},{value:"4. Launch",id:"4-launch",level:2}],p={toc:l},d="wrapper";function m(e){let{components:t,...n}=e;return(0,i.kt)(d,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"consumer-onboarding-checklist"},"Consumer Onboarding Checklist"),(0,i.kt)("p",null,"The following checklists will aid in onboarding a new consumer chain to replicated security."),(0,i.kt)("p",null,"Additionally, you can check the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md"},"testnet repo")," for a comprehensive guide on preparing and launching consumer chains."),(0,i.kt)("h2",{id:"1-complete-testing--integration"},"1. Complete testing & integration"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test integration with gaia"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test your protocol with supported relayer versions (minimum hermes 1.4.1)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","reach out to the ICS team if you are facing issues")),(0,i.kt)("h2",{id:"2-create-an-onboarding-repository"},"2. Create an Onboarding Repository"),(0,i.kt)("p",null,"To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain."),(0,i.kt)("p",null,"This should include (at minimum):"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json without CCV data (before the proposal passes)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see ",(0,i.kt)("a",{parentName:"li",href:"/interchain-security/legacy/consumer-development/consumer-genesis-transformation"},"Transform Consumer Genesis"),")"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","information about relevant seed/peer nodes you are running"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","relayer information (compatible versions)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","copy of your governance proposal (as JSON)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","a script showing how to start your chain and connect to peers (optional)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable")),(0,i.kt)("p",null,"Example of such a repository can be found ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyphacoop/ics-testnets/tree/main/game-of-chains-2022/sputnik"},"here"),"."),(0,i.kt)("h2",{id:"3-submit-a-governance-proposal"},"3. Submit a Governance Proposal"),(0,i.kt)("p",null,"Before you submit a ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerChainAddition")," proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch.\nIf possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues."),(0,i.kt)("p",null,"Additionally, reach out to the community via the ",(0,i.kt)("a",{parentName:"p",href:"https://forum.cosmos.network/"},"forum")," to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine your chain's spawn time"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine consumer chain parameters to be put in the proposal"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take note to include a link to your onboarding repository"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","describe the purpose and benefits of running your chain")),(0,i.kt)("p",null,"Example of a consumer chain addition proposal."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},'// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.\n// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.\n// It is recommended that spawn time occurs after the proposal end time.\n{\n // Title of the proposal\n "title": "Add consumer chain",\n // Description of the proposal\n // format the text as a .md file and include the file in your onboarding repository\n "description": ".md description of your chain and all other relevant information",\n // Proposed chain-id of the new consumer chain.\n // Must be unique from all other consumer chain ids of the executing provider chain.\n "chain_id": "newchain-1",\n // Initial height of new consumer chain.\n // For a completely new chain, this will be {0,1}.\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Hash of the consumer chain genesis state without the consumer CCV module genesis params.\n // It is used for off-chain confirmation of genesis.json validity by validators and other parties.\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n // Hash of the consumer chain binary that should be run by validators on chain initialization.\n // It is used for off-chain confirmation of binary validity by validators and other parties.\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n // Unbonding period for the consumer chain.\n // It should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n // IBC transfer packets will timeout after this interval elapses.\n "transfer_timeout_period": 1800000000000,\n // The fraction of tokens allocated to the consumer redistribution address during distribution events.\n // The fraction is a string representing a decimal number. For example "0.75" would represent 75%.\n // The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.\n "consumer_redistribution_fraction": "0.75",\n // BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.\n // eg. send rewards to the provider every 1000 blocks\n "blocks_per_distribution_transmission": 1000,\n // The number of historical info entries to persist in store.\n // This param is a part of the cosmos sdk staking module. In the case of\n // a ccv enabled consumer chain, the ccv module acts as the staking module.\n "historical_entries": 10000,\n // The ID of a token transfer channel used for the Reward Distribution\n // sub-protocol. If DistributionTransmissionChannel == "", a new transfer\n // channel is created on top of the same connection as the CCV channel.\n // Note that transfer_channel_id is the ID of the channel end on the consumer chain.\n // it is most relevant for chains performing a sovereign to consumer changeover\n // in order to maintain the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123"\n}\n')),(0,i.kt)("h2",{id:"4-launch"},"4. Launch"),(0,i.kt)("p",null,"The consumer chain starts after at least 66.67% of all provider's voting power comes online. The consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","provide a repo with onboarding instructions for validators (it should already be listed in the proposal)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json with ccv data populated (MUST contain the initial validator set)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","have a block explorer in place to track chain activity & health")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/972fb3fd.1cc68b7b.js b/legacy/assets/js/972fb3fd.1cc68b7b.js new file mode 100644 index 0000000000..772537ae6f --- /dev/null +++ b/legacy/assets/js/972fb3fd.1cc68b7b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6725],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>m});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?i(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,a,r=function(e,n){if(null==e)return{};var t,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=a.createContext({}),c=function(e){var n=a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=c(e.components);return a.createElement(l.Provider,{value:n},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},y=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=c(t),y=r,m=d["".concat(l,".").concat(y)]||d[y]||p[y]||i;return t?a.createElement(m,o(o({ref:n},u),{},{components:t})):a.createElement(m,o({ref:n},u))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,o=new Array(i);o[0]=y;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var c=2;c<i;c++)o[c]=t[c];return a.createElement.apply(null,o)}return a.createElement.apply(null,t)}y.displayName="MDXCreateElement"},3979:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var a=t(7462),r=(t(7294),t(3905));const i={sidebar_position:1},o="Key Assignment",s={unversionedId:"features/key-assignment",id:"version-v3.2.0/features/key-assignment",title:"Key Assignment",description:"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.",source:"@site/versioned_docs/version-v3.2.0/features/key-assignment.md",sourceDirName:"features",slug:"/features/key-assignment",permalink:"/interchain-security/legacy/v3.2.0/features/key-assignment",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Technical Specification",permalink:"/interchain-security/legacy/v3.2.0/introduction/technical-specification"},next:{title:"Reward distribution",permalink:"/interchain-security/legacy/v3.2.0/features/reward-distribution"}},l={},c=[{value:"Rules",id:"rules",level:2},{value:"Adding a key",id:"adding-a-key",level:2},{value:"Changing a key",id:"changing-a-key",level:2},{value:"Removing a key",id:"removing-a-key",level:2}],u={toc:c},d="wrapper";function p(e){let{components:n,...t}=e;return(0,r.kt)(d,(0,a.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"key-assignment"},"Key Assignment"),(0,r.kt)("p",null,"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.\nThere are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains."),(0,r.kt)("p",null,"The feature is outlined in this ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.2.0/adrs/adr-001-key-assignment"},"ADR-001")),(0,r.kt)("p",null,"By sending an ",(0,r.kt)("inlineCode",{parentName:"p"},"AssignConsumerKey")," transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity.")),(0,r.kt)("h2",{id:"rules"},"Rules"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"a key can be assigned before the consumer addition proposal passes on the provider"),(0,r.kt)("li",{parentName:"ul"},"validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider"),(0,r.kt)("li",{parentName:"ul"},"validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X"),(0,r.kt)("li",{parentName:"ul"},"a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Validators can use a different key for each consumer chain.")),(0,r.kt)("h2",{id:"adding-a-key"},"Adding a key"),(0,r.kt)("p",null,"First, create a new node on the consumer chain using the equivalent:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"consumerd init <moniker>\n")),(0,r.kt)("p",null,"Then query your node for the consensus key."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}\n')),(0,r.kt)("p",null,"Then, make an ",(0,r.kt)("inlineCode",{parentName:"p"},"assign-consensus-key")," transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad tx provider assign-consensus-key <consumer-chain-id> '<pubkey>' --from <tx-signer> --home <home_dir> --gas 900000 -b sync -y -o json\n")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"consumer-chain-id")," is the string identifier of the consumer chain, as assigned on the provider chain"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"consumer-pub-key")," has the following format ",(0,r.kt)("inlineCode",{parentName:"li"},'{"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}'))),(0,r.kt)("p",null,"Check that the key was assigned correctly by querying the provider:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad query provider validator-consumer-key <consumer-chain-id> cosmosvalcons1e....3xsj3ayzf4uv6\n")),(0,r.kt)("p",null,"You must use a ",(0,r.kt)("inlineCode",{parentName:"p"},"valcons")," address. You can obtain it by querying your node on the provider ",(0,r.kt)("inlineCode",{parentName:"p"},"gaiad tendermint show-address")),(0,r.kt)("p",null,"OR"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad query provider validator-provider-key <consumer-chain-id> consumervalcons1e....123asdnoaisdao\n")),(0,r.kt)("p",null,"You must use a ",(0,r.kt)("inlineCode",{parentName:"p"},"valcons")," address. You can obtain it by querying your node on the consumer ",(0,r.kt)("inlineCode",{parentName:"p"},"consumerd tendermint show-address")),(0,r.kt)("h2",{id:"changing-a-key"},"Changing a key"),(0,r.kt)("p",null,"To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied"),(0,r.kt)("h2",{id:"removing-a-key"},"Removing a key"),(0,r.kt)("p",null,"To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the ",(0,r.kt)("inlineCode",{parentName:"p"},"Adding a key")," section and using your provider consensus key."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/97c83118.9dbb4c6e.js b/legacy/assets/js/97c83118.9dbb4c6e.js new file mode 100644 index 0000000000..9778afc683 --- /dev/null +++ b/legacy/assets/js/97c83118.9dbb4c6e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3938],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>m});var n=a(7294);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?r(Object(a),!0).forEach((function(t){i(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):r(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function l(e,t){if(null==e)return{};var a,n,i=function(e,t){if(null==e)return{};var a,n,i={},r=Object.keys(e);for(n=0;n<r.length;n++)a=r[n],t.indexOf(a)>=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n<r.length;n++)a=r[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var s=n.createContext({}),h=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},d=function(e){var t=h(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=h(a),u=i,m=c["".concat(s,".").concat(u)]||c[u]||p[u]||r;return a?n.createElement(m,o(o({ref:t},d),{},{components:a})):n.createElement(m,o({ref:t},d))}));function m(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=a.length,o=new Array(r);o[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:i,o[1]=l;for(var h=2;h<r;h++)o[h]=a[h];return n.createElement.apply(null,o)}return n.createElement.apply(null,a)}u.displayName="MDXCreateElement"},7142:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>p,frontMatter:()=>r,metadata:()=>l,toc:()=>h});var n=a(7462),i=(a(7294),a(3905));const r={sidebar_position:3,title:"Jail Throttling"},o="ADR 002: Jail Throttling",l={unversionedId:"adrs/adr-002-throttle",id:"version-v3.3.1-lsm/adrs/adr-002-throttle",title:"Jail Throttling",description:"Changelog",source:"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-002-throttle.md",sourceDirName:"adrs",slug:"/adrs/adr-002-throttle",permalink:"/interchain-security/legacy/adrs/adr-002-throttle",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Jail Throttling"},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/legacy/adrs/adr-001-key-assignment"},next:{title:"Equivocation governance proposal",permalink:"/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposal"}},s={},h=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Required State",id:"required-state",level:3},{value:"Params",id:"params",level:3},{value:"Protocol Overview",id:"protocol-overview",level:3},{value:"OnRecvSlashPacket",id:"onrecvslashpacket",level:4},{value:"OnRecvVSCMaturedPacket",id:"onrecvvscmaturedpacket",level:4},{value:"Endblocker",id:"endblocker",level:4},{value:"Slash Meter Replenishment",id:"slash-meter-replenishment",level:5},{value:"Handle Leading VSCMaturedPackets",id:"handle-leading-vscmaturedpackets",level:5},{value:"Handle Throttle Queues",id:"handle-throttle-queues",level:5},{value:"System Properties",id:"system-properties",level:3},{value:"Main Throttling Property",id:"main-throttling-property",level:3},{value:"How Unjailing Affects the Main Throttling Property",id:"how-unjailing-affects-the-main-throttling-property",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],d={toc:h},c="wrapper";function p(e){let{components:t,...a}=e;return(0,i.kt)(c,(0,n.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"adr-002-jail-throttling"},"ADR 002: Jail Throttling"),(0,i.kt)("h2",{id:"changelog"},"Changelog"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"2023-01-26: Initial Draft"),(0,i.kt)("li",{parentName:"ul"},"2023-02-07: Property refined, ADR ready to review/merge"),(0,i.kt)("li",{parentName:"ul"},"2023-11-22: Refactor for better understanding")),(0,i.kt)("h2",{id:"status"},"Status"),(0,i.kt)("p",null,"Accepted"),(0,i.kt)("h2",{id:"context"},"Context"),(0,i.kt)("p",null,"The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols.\nIn practice, this assumption may not hold.\nA malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider."),(0,i.kt)("p",null,"Before the throttling feature was implemented, the following attack was possible.\nAttacker(s) would create provider validators just below the provider's active set.\nUsing a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once.\nControl of the provider would then pass over to the attackers' validators.\nThis enables the attacker(s) to halt the provider.\nOr even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC."),(0,i.kt)("h2",{id:"decision"},"Decision"),(0,i.kt)("p",null,"The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack,\ni.e., this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time."),(0,i.kt)("h3",{id:"required-state"},"Required State"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Slash meter:")," There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time.\nThis meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Global entry queue:"),' There exists a single queue which stores "global slash entries".\nThese entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering.\nThis queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.'),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Per-chain data queue:"),' For each established consumer, there exists a queue which stores "throttled packet data",\ni.e.,pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering.\nOrder is enforced by IBC sequence number.\nThese "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.'),(0,i.kt)("p",null,(0,i.kt)("em",{parentName:"p"},"Note:")," The reason for a multiple-queue design is the ",(0,i.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order")," property (see ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"spec"),").\nThere are other ways to ensure such a property (like a queue of linked lists, etc.), but the proposed approach seemed to be the most understandable and easiest to implement with a KV store."),(0,i.kt)("h3",{id:"params"},"Params"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishPeriod")," -- the period after which the slash meter is replenished. "),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction")," -- the portion (in range ","[0, 1]",") of total voting power that is replenished to the slash meter when a replenishment occurs. This param also serves as a maximum fraction of total voting power that the slash meter can hold."),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"MaxThrottledPackets")," -- the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value.\nThis param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness."),(0,i.kt)("h3",{id:"protocol-overview"},"Protocol Overview"),(0,i.kt)("h4",{id:"onrecvslashpacket"},"OnRecvSlashPacket"),(0,i.kt)("p",null,"Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"A global slash entry is queued."),(0,i.kt)("li",{parentName:"ol"},"The data of such a packet is added to the per-chain queue.")),(0,i.kt)("h4",{id:"onrecvvscmaturedpacket"},"OnRecvVSCMaturedPacket"),(0,i.kt)("p",null,"Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue."),(0,i.kt)("h4",{id:"endblocker"},"Endblocker"),(0,i.kt)("p",null,"In the ",(0,i.kt)("inlineCode",{parentName:"p"},"EndBlock")," of the provider CCV module, there are three actions performed:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"replenish the slash meter;"),(0,i.kt)("li",{parentName:"ul"},"handle the leading ",(0,i.kt)("inlineCode",{parentName:"li"},"VSCMaturedPackets"),";"),(0,i.kt)("li",{parentName:"ul"},"and handle the throttle queues.")),(0,i.kt)("h5",{id:"slash-meter-replenishment"},"Slash Meter Replenishment"),(0,i.kt)("p",null,"Once the slash meter becomes not full, it'll be replenished after ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishPeriod")," by incrementing the meter with its allowance for the replenishment block, where ",(0,i.kt)("inlineCode",{parentName:"p"},"allowance")," = ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction")," * ",(0,i.kt)("inlineCode",{parentName:"p"},"currentTotalVotingPower"),".\nThe slash meter will never exceed its current allowance (function of the total voting power for the block) in value. "),(0,i.kt)("p",null,"Note a few things:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power.\nIn such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods."),(0,i.kt)("li",{parentName:"ol"},"Total voting power of a chain changes over time, especially as validators are jailed.\nAs validators are jailed, total voting power decreases, and so does the jailing allowance.\nSee below for more detailed throttling property discussion."),(0,i.kt)("li",{parentName:"ol"},"The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1.\nIf the ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," is set too low, integer rounding will put this minimum value into effect.\nThat is, if ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," * ",(0,i.kt)("inlineCode",{parentName:"li"},"currentTotalVotingPower")," < 1, then the effective allowance would be 1.\nThis min value of allowance ensures that there's some packets handled over time, even if that is a very long time.\nIt's a crude solution to an edge case caused by too small of a replenishment fraction.")),(0,i.kt)("p",null,"The behavior described above is achieved by executing ",(0,i.kt)("inlineCode",{parentName:"p"},"CheckForSlashMeterReplenishment()")," every ",(0,i.kt)("inlineCode",{parentName:"p"},"EndBlock"),", BEFORE ",(0,i.kt)("inlineCode",{parentName:"p"},"HandleThrottleQueues()")," is executed."),(0,i.kt)("h5",{id:"handle-leading-vscmaturedpackets"},"Handle Leading VSCMaturedPackets"),(0,i.kt)("p",null,"In every block, it is possible that ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPacket"),' data was queued before any slash packet data.\nSince this "leading" VSCMatured packet data does not have to be throttled (see ',(0,i.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order"),"), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes."),(0,i.kt)("h5",{id:"handle-throttle-queues"},"Handle Throttle Queues"),(0,i.kt)("p",null,"In every ",(0,i.kt)("inlineCode",{parentName:"p"},"EndBlock"),", the following logic is executed to handle data from the throttle queues."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"meter := getSlashMeter()\n\n// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist \nwhile meter.IsPositiveOrZero() && entriesExist() {\n // Get next entry in queue\n entry := getNextGlobalSlashEntry()\n // Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet\n valPower := entry.getValPower()\n meter = meter - valPower\n // Using the per-chain queue, handle the single slash packet using its queued data,\n // then handle all trailing VSCMatured packets for this consumer\n handleSlashPacketAndTrailingVSCMaturedPackets(entry)\n // Delete entry in global queue, delete handled data\n entry.Delete()\n deleteThrottledSlashPacketData()\n deleteTrailingVSCMaturedPacketData()\n}\n")),(0,i.kt)("h3",{id:"system-properties"},"System Properties"),(0,i.kt)("p",null,"All CCV system properties should be maintained by implementing this feature, see ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"CCV spec - Consumer Initiated Slashing"),"."),(0,i.kt)("p",null,"One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than ",(0,i.kt)("inlineCode",{parentName:"p"},"MaxThrottledPackets"),", then the provider binary will panic, and the provider chain will halt.\nTherefore this param should be set carefully. See ",(0,i.kt)("inlineCode",{parentName:"p"},"SetThrottledPacketDataSize"),".\nThis behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators."),(0,i.kt)("h3",{id:"main-throttling-property"},"Main Throttling Property"),(0,i.kt)("p",null,"Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions."),(0,i.kt)("p",null,"First, we introduce the following definitions:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},'A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.'),(0,i.kt)("li",{parentName:"ul"},'The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.'),(0,i.kt)("li",{parentName:"ul"},"There is a list of honest validators such that if they are jailed, ",(0,i.kt)("inlineCode",{parentName:"li"},"X"),"% of the initial validator set will be jailed.")),(0,i.kt)("p",null,"For the Throttling Property to hold, the following assumptions must be true:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack."),(0,i.kt)("li",{parentName:"ol"},"No validator has more than ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," of total voting power on the provider."),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," is large enough that ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," * ",(0,i.kt)("inlineCode",{parentName:"li"},"currentTotalVotingPower")," > 1,\ni.e., the replenish fraction is set high enough that we can ignore the effects of rounding."),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishPeriod")," is sufficiently longer than the time it takes to produce a block.")),(0,i.kt)("p",null,(0,i.kt)("em",{parentName:"p"},"Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined.")),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Throttling Property"),": The time it takes to jail/tombstone ",(0,i.kt)("inlineCode",{parentName:"p"},"X"),"% of the initial validator set will be greater than or equal to\n$\\mathit{SlashMeterReplenishPeriod} \\cdot \\frac{X}{\\mathit{SlashMeterReplenishFraction}} - 2 \\cdot \\mathit{SlashMeterReplenishPeriod}$."),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("strong",{parentName:"p"},"Intuition")),(0,i.kt)("p",{parentName:"blockquote"},"Let's use the following notation:"),(0,i.kt)("ul",{parentName:"blockquote"},(0,i.kt)("li",{parentName:"ul"},"$C$: Number of replenishment cycles"),(0,i.kt)("li",{parentName:"ul"},"$P$: $\\mathit{SlashMeterReplenishPeriod}$"),(0,i.kt)("li",{parentName:"ul"},"$F$: $\\mathit{SlashMeterReplenishFraction}$"),(0,i.kt)("li",{parentName:"ul"},"$V_{\\mathit{max}}$: Max power of a validator as a fraction of total voting power")),(0,i.kt)("p",{parentName:"blockquote"},"In $C$ number of replenishment cycles, the fraction of total voting power that can be removed, $a$, is $a \\leq F \\cdot C + V",(0,i.kt)("em",{parentName:"p"},"{\\mathit{max}}$ (where $V"),"{\\mathit{max}}$ is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value)."),(0,i.kt)("p",{parentName:"blockquote"},"So, we need at least $C \\geq \\frac{a - V_{\\mathit{max}}}{F}$ cycles to remove $a$ fraction of the total voting power."),(0,i.kt)("p",{parentName:"blockquote"},"Since we defined the start of the attack to be the moment when the first slash request arrives, then $F$ fraction of the initial validator set can be jailed immediately. For the remaining $X - F$ fraction of the initial validator set to be jailed, it takes at least $C \\geq \\frac{(X - F) - V",(0,i.kt)("em",{parentName:"p"},"{\\mathit{max}}}{F}$ cycles. Using the assumption that $V"),"{\\mathit{max}} \\leq F$ (assumption 2), we get $C \\geq \\frac{X - 2F}{F}$ cycles."),(0,i.kt)("p",{parentName:"blockquote"},"In order to execute $C$ cycles, we need $C \\cdot P$ time."),(0,i.kt)("p",{parentName:"blockquote"},"Thus, jailing the remaining $X - F$ fraction of the initial validator set corresponds to $\\frac{P \\cdot (X - 2F)}{F}$ time."),(0,i.kt)("p",{parentName:"blockquote"},"In other words, the attack must take at least $\\frac{P \\cdot X}{F} - 2P$ time (in the units of replenish period $P$).")),(0,i.kt)("p",null,"This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests.\nFor example, if ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction")," is set to ",(0,i.kt)("inlineCode",{parentName:"p"},"0.06"),", then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub.\nNote that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power."),(0,i.kt)("p",null,"Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings."),(0,i.kt)("h3",{id:"how-unjailing-affects-the-main-throttling-property"},"How Unjailing Affects the Main Throttling Property"),(0,i.kt)("p",null,"Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained."),(0,i.kt)("p",null,"If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider."),(0,i.kt)("p",null,"In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack."),(0,i.kt)("h2",{id:"consequences"},"Consequences"),(0,i.kt)("h3",{id:"positive"},"Positive"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"The described attack is slowed down in seemingly all cases."),(0,i.kt)("li",{parentName:"ul"},"If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded.")),(0,i.kt)("h3",{id:"negative"},"Negative"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below.\nHowever, this is sacrificing liveness in a edge case scenario for the sake of security.\nAs an improvement, ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/713"},"using retries")," would fully prevent this attack vector.")),(0,i.kt)("h3",{id:"neutral"},"Neutral"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Additional state is introduced to the provider chain."),(0,i.kt)("li",{parentName:"ul"},"VSCMatured and slash packet data is not always handled in the same block that it is received.")),(0,i.kt)("h2",{id:"references"},"References"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/404"},"Original issue inspiring throttling feature")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/594"},"Issue on DOS vector")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/685"},"Consideration of another attack vector"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/98c1c075.825c69fd.js b/legacy/assets/js/98c1c075.825c69fd.js new file mode 100644 index 0000000000..f58cea2fc5 --- /dev/null +++ b/legacy/assets/js/98c1c075.825c69fd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2082],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>d});var o=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function c(e,n){if(null==e)return{};var t,o,r=function(e,n){if(null==e)return{};var t,o,r={},a=Object.keys(e);for(o=0;o<a.length;o++)t=a[o],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o<a.length;o++)t=a[o],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=o.createContext({}),l=function(e){var n=o.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},u=function(e){var n=l(e.components);return o.createElement(s.Provider,{value:n},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},h=o.forwardRef((function(e,n){var t=e.components,r=e.mdxType,a=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=l(t),h=r,d=p["".concat(s,".").concat(h)]||p[h]||m[h]||a;return t?o.createElement(d,i(i({ref:n},u),{},{components:t})):o.createElement(d,i({ref:n},u))}));function d(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var a=t.length,i=new Array(a);i[0]=h;var c={};for(var s in n)hasOwnProperty.call(n,s)&&(c[s]=n[s]);c.originalType=e,c[p]="string"==typeof e?e:r,i[1]=c;for(var l=2;l<a;l++)i[l]=t[l];return o.createElement.apply(null,i)}return o.createElement.apply(null,t)}h.displayName="MDXCreateElement"},4858:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var o=t(7462),r=(t(7294),t(3905));const a={sidebar_position:1},i="Developing an ICS consumer chain",c={unversionedId:"consumer-development/app-integration",id:"version-v3.3.0/consumer-development/app-integration",title:"Developing an ICS consumer chain",description:"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.",source:"@site/versioned_docs/version-v3.3.0/consumer-development/app-integration.md",sourceDirName:"consumer-development",slug:"/consumer-development/app-integration",permalink:"/interchain-security/legacy/v3.3.0/consumer-development/app-integration",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/legacy/v3.3.0/features/slashing"},next:{title:"Consumer Chain Governance",permalink:"/interchain-security/legacy/v3.3.0/consumer-development/consumer-chain-governance"}},s={},l=[{value:"Basic consumer chain",id:"basic-consumer-chain",level:2},{value:"Democracy consumer chain",id:"democracy-consumer-chain",level:2},{value:"Standalone chain to consumer chain changeover",id:"standalone-chain-to-consumer-chain-changeover",level:2}],u={toc:l},p="wrapper";function m(e){let{components:n,...t}=e;return(0,r.kt)(p,(0,o.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"developing-an-ics-consumer-chain"},"Developing an ICS consumer chain"),(0,r.kt)("p",null,"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.\nTo help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications."),(0,r.kt)("h2",{id:"basic-consumer-chain"},"Basic consumer chain"),(0,r.kt)("p",null,"The source code for the example app can be found ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer"},"here"),"."),(0,r.kt)("p",null,"Please note that consumer chains do not implement the staking module - the validator set is replicated from the provider, meaning that the provider and the consumer use the same validator set and their stake on the provider directly determines their stake on the consumer.\nAt present there is no opt-in mechanism available, so all validators of the provider must also validate on the provider chain."),(0,r.kt)("p",null,"Your chain should import the consumer module from ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," and register it in the correct places in your ",(0,r.kt)("inlineCode",{parentName:"p"},"app.go"),".\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in.\nYou should not need to manage or override any code from the ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module."),(0,r.kt)("h2",{id:"democracy-consumer-chain"},"Democracy consumer chain"),(0,r.kt)("p",null,"The source code for the example app can be found ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy"},"here"),"."),(0,r.kt)("p",null,"This type of consumer chain wraps the basic CosmosSDK ",(0,r.kt)("inlineCode",{parentName:"p"},"x/distribution"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"x/staking")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"x/governance")," modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system."),(0,r.kt)("p",null,"This allows the consumer chain to leverage those modules while also using the ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module."),(0,r.kt)("p",null,'With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.'),(0,r.kt)("h2",{id:"standalone-chain-to-consumer-chain-changeover"},"Standalone chain to consumer chain changeover"),(0,r.kt)("p",null,"This feature is being actively worked on. Information will be provided at a later time."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/9b050cce.4f7d54a6.js b/legacy/assets/js/9b050cce.4f7d54a6.js new file mode 100644 index 0000000000..3905a68df0 --- /dev/null +++ b/legacy/assets/js/9b050cce.4f7d54a6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[692],{6932:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"v3.1.0","label":"v3.1.0","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-v3.1.0","isLast":false,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Interchain Security Docs","href":"/interchain-security/legacy/v3.1.0/","docId":"index"},{"type":"category","label":"Introduction","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/legacy/v3.1.0/introduction/overview","docId":"introduction/overview"},{"type":"link","label":"Terminology","href":"/interchain-security/legacy/v3.1.0/introduction/terminology","docId":"introduction/terminology"},{"type":"link","label":"Interchain Security Parameters","href":"/interchain-security/legacy/v3.1.0/introduction/params","docId":"introduction/params"},{"type":"link","label":"Technical Specification","href":"/interchain-security/legacy/v3.1.0/introduction/technical-specification","docId":"introduction/technical-specification"}]},{"type":"category","label":"Features","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Key Assignment","href":"/interchain-security/legacy/v3.1.0/features/key-assignment","docId":"features/key-assignment"},{"type":"link","label":"Reward distribution","href":"/interchain-security/legacy/v3.1.0/features/reward-distribution","docId":"features/reward-distribution"},{"type":"link","label":"ICS Provider Proposals","href":"/interchain-security/legacy/v3.1.0/features/proposals","docId":"features/proposals"},{"type":"link","label":"Consumer Initiated Slashing","href":"/interchain-security/legacy/v3.1.0/features/slashing","docId":"features/slashing"}]},{"type":"category","label":"Consumer Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Developing an ICS consumer chain","href":"/interchain-security/legacy/v3.1.0/consumer-development/app-integration","docId":"consumer-development/app-integration"},{"type":"link","label":"Consumer Chain Governance","href":"/interchain-security/legacy/v3.1.0/consumer-development/consumer-chain-governance","docId":"consumer-development/consumer-chain-governance"},{"type":"link","label":"Upgrading Consumer Chains","href":"/interchain-security/legacy/v3.1.0/consumer-development/consumer-chain-upgrade-procedure","docId":"consumer-development/consumer-chain-upgrade-procedure"},{"type":"link","label":"Onboarding Checklist","href":"/interchain-security/legacy/v3.1.0/consumer-development/onboarding","docId":"consumer-development/onboarding"},{"type":"link","label":"Offboarding Checklist","href":"/interchain-security/legacy/v3.1.0/consumer-development/offboarding","docId":"consumer-development/offboarding"}]},{"type":"category","label":"Validators Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/legacy/v3.1.0/validators/overview","docId":"validators/overview"},{"type":"link","label":"Joining Replicated Security testnet","href":"/interchain-security/legacy/v3.1.0/validators/joining-testnet","docId":"validators/joining-testnet"},{"type":"link","label":"Withdrawing consumer chain validator rewards","href":"/interchain-security/legacy/v3.1.0/validators/withdraw_rewards","docId":"validators/withdraw_rewards"}]},{"type":"link","label":"Frequently Asked Questions","href":"/interchain-security/legacy/v3.1.0/faq","docId":"frequently-asked-questions"},{"type":"category","label":"ADRs","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"ADRs","href":"/interchain-security/legacy/v3.1.0/adrs/intro","docId":"adrs/intro"},{"type":"link","label":"ADR Template","href":"/interchain-security/legacy/v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-prop","docId":"adrs/adr-007-pause-unbonding-on-eqv-prop"},{"type":"link","label":"ADR Template","href":"/interchain-security/legacy/v3.1.0/adrs/adr-template","docId":"adrs/adr-template"},{"type":"link","label":"Key Assignment","href":"/interchain-security/legacy/v3.1.0/adrs/adr-001-key-assignment","docId":"adrs/adr-001-key-assignment"},{"type":"link","label":"Jail Throttling","href":"/interchain-security/legacy/v3.1.0/adrs/adr-002-throttle","docId":"adrs/adr-002-throttle"},{"type":"link","label":"Equivocation governance proposal","href":"/interchain-security/legacy/v3.1.0/adrs/adr-003-equivocation-gov-proposal","docId":"adrs/adr-003-equivocation-gov-proposal"},{"type":"link","label":"Throttle with retries","href":"/interchain-security/legacy/v3.1.0/adrs/adr-008-throttle-retries","docId":"adrs/adr-008-throttle-retries"},{"type":"link","label":"Soft Opt-Out","href":"/interchain-security/legacy/v3.1.0/adrs/adr-009-soft-opt-out","docId":"adrs/adr-009-soft-opt-out"}]}]},"docs":{"adrs/adr-001-key-assignment":{"id":"adrs/adr-001-key-assignment","title":"Key Assignment","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-002-throttle":{"id":"adrs/adr-002-throttle","title":"Jail Throttling","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-003-equivocation-gov-proposal":{"id":"adrs/adr-003-equivocation-gov-proposal","title":"Equivocation governance proposal","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-007-pause-unbonding-on-eqv-prop":{"id":"adrs/adr-007-pause-unbonding-on-eqv-prop","title":"ADR Template","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-008-throttle-retries":{"id":"adrs/adr-008-throttle-retries","title":"Throttle with retries","description":"ADR 008: Throttle with retries","sidebar":"tutorialSidebar"},"adrs/adr-009-soft-opt-out":{"id":"adrs/adr-009-soft-opt-out","title":"Soft Opt-Out","description":"ADR 009: Soft Opt-Out","sidebar":"tutorialSidebar"},"adrs/adr-template":{"id":"adrs/adr-template","title":"ADR Template","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/intro":{"id":"adrs/intro","title":"ADRs","description":"This is a location to record all high-level architecture decisions in the Interchain Security project.","sidebar":"tutorialSidebar"},"consumer-development/app-integration":{"id":"consumer-development/app-integration","title":"Developing an ICS consumer chain","description":"When developing an ICS consumer chain, besides just focusing on your chain\'s logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.","sidebar":"tutorialSidebar"},"consumer-development/consumer-chain-governance":{"id":"consumer-development/consumer-chain-governance","title":"Consumer Chain Governance","description":"Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the \\"Whitelist\\" section below.","sidebar":"tutorialSidebar"},"consumer-development/consumer-chain-upgrade-procedure":{"id":"consumer-development/consumer-chain-upgrade-procedure","title":"Upgrading Consumer Chains","description":"","sidebar":"tutorialSidebar"},"consumer-development/offboarding":{"id":"consumer-development/offboarding","title":"Offboarding Checklist","description":"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).","sidebar":"tutorialSidebar"},"consumer-development/onboarding":{"id":"consumer-development/onboarding","title":"Onboarding Checklist","description":"The following checklists will aid in onboarding a new consumer chain to replicated security.","sidebar":"tutorialSidebar"},"features/key-assignment":{"id":"features/key-assignment","title":"Key Assignment","description":"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.","sidebar":"tutorialSidebar"},"features/proposals":{"id":"features/proposals","title":"ICS Provider Proposals","description":"Interchain security module introduces 3 new proposal types to the provider.","sidebar":"tutorialSidebar"},"features/reward-distribution":{"id":"features/reward-distribution","title":"Reward distribution","description":"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.","sidebar":"tutorialSidebar"},"features/slashing":{"id":"features/slashing","title":"Consumer Initiated Slashing","description":"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of it\'s own chain.","sidebar":"tutorialSidebar"},"frequently-asked-questions":{"id":"frequently-asked-questions","title":"Frequently Asked Questions","description":"What is the meaning of Validator Set Replication?","sidebar":"tutorialSidebar"},"index":{"id":"index","title":"Interchain Security Docs","description":"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.","sidebar":"tutorialSidebar"},"introduction/overview":{"id":"introduction/overview","title":"Overview","description":"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.","sidebar":"tutorialSidebar"},"introduction/params":{"id":"introduction/params","title":"Interchain Security Parameters","description":"The parameters necessary for Interchain Security (ICS) are defined in","sidebar":"tutorialSidebar"},"introduction/technical-specification":{"id":"introduction/technical-specification","title":"Technical Specification","description":"For a technical deep dive into the replicated security protocol, see the specification.","sidebar":"tutorialSidebar"},"introduction/terminology":{"id":"introduction/terminology","title":"Terminology","description":"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.","sidebar":"tutorialSidebar"},"validators/joining-testnet":{"id":"validators/joining-testnet","title":"Joining Replicated Security testnet","description":"Introduction","sidebar":"tutorialSidebar"},"validators/overview":{"id":"validators/overview","title":"Overview","description":"We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.","sidebar":"tutorialSidebar"},"validators/withdraw_rewards":{"id":"validators/withdraw_rewards","title":"Withdrawing consumer chain validator rewards","description":"Here are example steps for withdrawing rewards from consumer chains in the provider chain","sidebar":"tutorialSidebar"}}}')}}]); \ No newline at end of file diff --git a/legacy/assets/js/9b3ea85c.9d0d730c.js b/legacy/assets/js/9b3ea85c.9d0d730c.js new file mode 100644 index 0000000000..6ef41ac49b --- /dev/null +++ b/legacy/assets/js/9b3ea85c.9d0d730c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4676],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,m=u["".concat(c,".").concat(h)]||u[h]||d[h]||i;return n?a.createElement(m,o(o({ref:t},p),{},{components:n})):a.createElement(m,o({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:r,o[1]=s;for(var l=2;l<i;l++)o[l]=n[l];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},2768:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var a=n(7462),r=(n(7294),n(3905));const i={sidebar_position:2,title:"Joining Replicated Security testnet"},o="Introduction",s={unversionedId:"validators/joining-testnet",id:"version-v2.0.0/validators/joining-testnet",title:"Joining Replicated Security testnet",description:"This short guide will teach you how to join the Replicated Security testnet.",source:"@site/versioned_docs/version-v2.0.0/validators/joining-testnet.md",sourceDirName:"validators",slug:"/validators/joining-testnet",permalink:"/interchain-security/legacy/v2.0.0/validators/joining-testnet",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"Joining Replicated Security testnet"},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/legacy/v2.0.0/validators/overview"},next:{title:"Withdrawing consumer chain validator rewards",permalink:"/interchain-security/legacy/v2.0.0/validators/withdraw_rewards"}},c={},l=[{value:"Initialization",id:"initialization",level:2},{value:"Re-using consensus key",id:"re-using-consensus-key",level:2},{value:"Assigning consensus keys",id:"assigning-consensus-keys",level:2},{value:"Baryon",id:"baryon",level:2},{value:"Noble",id:"noble",level:2}],p={toc:l},u="wrapper";function d(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"This short guide will teach you how to join the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security"},"Replicated Security testnet"),"."),(0,r.kt)("p",null,"The experience gained in the testnet will prepare you for validating interchain secured chains."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set."),(0,r.kt)("p",{parentName:"admonition"},"For general information about running cosmos-sdk based chains check out the ",(0,r.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html"},"validator basics")," and ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/main/run-node/run-node"},"Running a Node section")," of Cosmos SDK docs")),(0,r.kt)("h1",{id:"joining-the-provider-chain"},"Joining the provider chain"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain.")),(0,r.kt)("p",null,"A comprehensive guide is available ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security/provider"},"here"),"."),(0,r.kt)("h2",{id:"initialization"},"Initialization"),(0,r.kt)("p",null,"First, initialize your ",(0,r.kt)("inlineCode",{parentName:"p"},"$NODE_HOME")," using the ",(0,r.kt)("inlineCode",{parentName:"p"},"provider")," chain binary."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"NODE_MONIKER=<your_node>\nCHAIN_ID=provider\nNODE_HOME=<path_to_your_home>\n\ngaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME\n")),(0,r.kt)("p",null,"Add your key to the keyring - more details available ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/main/run-node/keyring"},"here"),"."),(0,r.kt)("p",null,"In this example we will use the ",(0,r.kt)("inlineCode",{parentName:"p"},"test")," keyring-backend. This option is not safe to use in production."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad keys add <key_moniker> --keyring-backend test\n\n# save the address as variable for later use\nMY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)\n")),(0,r.kt)("p",null,"Before issuing any transactions, use the ",(0,r.kt)("inlineCode",{parentName:"p"},"provider")," testnet faucet to add funds to your address."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider\n\n# example output:\n{\n "address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",\n "amount": "10000000uatom",\n "chain": "provider",\n "hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",\n "status": "success"\n}\n')),(0,r.kt)("p",null,"Then, use the account associated with the keyring to issue a ",(0,r.kt)("inlineCode",{parentName:"p"},"create-validator")," transaction which will register your validator on chain."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad tx staking create-validator \\\n --amount=1000000uatom \\\n --pubkey=$(gaiad tendermint show-validator) \\\n --moniker="choose a moniker" \\\n --chain-id=$CHAIN_ID" \\\n --commission-rate="0.10" \\\n --commission-max-rate="0.20" \\\n --commission-max-change-rate="0.01" \\\n --min-self-delegation="1000000" \\\n --gas="auto" \\\n --gas-prices="0.0025uatom" \\\n --from=<key_moniker>\n')),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Check this ",(0,r.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html#edit-validator-description"},"guide")," to edit your validator.")),(0,r.kt)("p",null,"After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use ",(0,r.kt)("inlineCode",{parentName:"p"},"statesync")," to catch up to the rest of the network."),(0,r.kt)("p",null,"You can use this script to modify your ",(0,r.kt)("inlineCode",{parentName:"p"},"config.toml")," with the required statesync parameters."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"# create the statesync script\n$: cd $NODE_HOME\n$: touch statesync.sh\n$ chmod 700 statesync.sh # make executable\n")),(0,r.kt)("p",null,"Paste the following instructions into the ",(0,r.kt)("inlineCode",{parentName:"p"},"statesync.sh"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'#!/bin/bash\n\nSNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"\n\nLATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \\\nBLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \\\nTRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)\n\nsed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\\1true| ; \\\ns|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\\1\\"$SNAP_RPC,$SNAP_RPC\\"| ; \\\ns|^(trust_height[[:space:]]+=[[:space:]]+).*$|\\1$BLOCK_HEIGHT| ; \\\ns|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\\1\\"$TRUST_HASH\\"|" $NODE_HOME/config/config.toml\n')),(0,r.kt)("p",null,"Then, you can execute the script:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"$: ./statesync.sh # setup config.toml for statesync\n")),(0,r.kt)("p",null,"Finally, copy the provider genesis and start your node:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/replicated-security/provider/provider-genesis.json\n$: wget $GENESIS_URL -O genesis.json\n$: genesis.json $NODE_HOME/config/genesis.json\n# start the service\n$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"\n')),(0,r.kt)("p",null,"Additional scripts to setup your nodes are available ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/provider/join-rs-provider.sh"},"here")," and ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/provider/join-rs-provider-cv.sh"},"here"),". The scripts will configure your node and create the required services - the scripts only work in linux environments."),(0,r.kt)("h1",{id:"joining-consumer-chains"},"Joining consumer chains"),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Once you reach the active set on the provider chain, you will be required to validate all available consumer chains."),(0,r.kt)("p",{parentName:"admonition"},"You can use the same consensus key on all consumer chains, or opt to use a different key on each consumer chain.\nCheck out this ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.0.0/features/key-assignment"},"guide")," to learn more about key assignment in replicated security.")),(0,r.kt)("p",null,"To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"When running the provider chain and consumers on the same machine please update the ",(0,r.kt)("inlineCode",{parentName:"p"},"PORT")," numbers for each of them and make sure they do not overlap (otherwise the binaries will not start)."),(0,r.kt)("p",{parentName:"admonition"},"Important ports to re-configure:"),(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--rpc.laddr")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--p2p.laddr")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--api.address")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--grpc.address")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--grpc-web.address")))),(0,r.kt)("h2",{id:"re-using-consensus-key"},"Re-using consensus key"),(0,r.kt)("p",null,"To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the ",(0,r.kt)("inlineCode",{parentName:"p"},"priv_validator_key.json")," into the home directory of your consumer chain (",(0,r.kt)("inlineCode",{parentName:"p"},"<consumer_home>/config/priv_validator_key.json"),")."),(0,r.kt)("p",null,"When you start the chain, the consensus key will be the same on the provider and the consumer chain."),(0,r.kt)("h2",{id:"assigning-consensus-keys"},"Assigning consensus keys"),(0,r.kt)("p",null,"Whenever you initialize a new node, it will be configured with a consensus key you can use."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'# machine running consumer chain\nconsumerd init <node_moniker> --home <home_path> --chain-id consumer-1\n\n# use the output of this command to get the consumer chain consensus key\nconsumerd tendermint show-validator\n# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}\n')),(0,r.kt)("p",null,"Then, let the provider know which key you will be using for the consumer chain:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"# machine running the provider chain\ngaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b block -y -o json\n")),(0,r.kt)("p",null,"After this step, you are ready to copy the consumer genesis into your nodes's ",(0,r.kt)("inlineCode",{parentName:"p"},"/config")," folder, start your consumer chain node and catch up to the network."),(0,r.kt)("h2",{id:"baryon"},"Baryon"),(0,r.kt)("p",null,"You can find the onboarding repo instructions for the Baryon chain ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/baryon-1/README.md"},"here")),(0,r.kt)("h2",{id:"noble"},"Noble"),(0,r.kt)("p",null,"You can find the onboarding repo instructions for the Noble chain ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/noble-1/README.md"},"here")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/9c1db290.2111d933.js b/legacy/assets/js/9c1db290.2111d933.js new file mode 100644 index 0000000000..69cdeb0156 --- /dev/null +++ b/legacy/assets/js/9c1db290.2111d933.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7372],{3905:(e,n,t)=>{t.d(n,{Zo:()=>m,kt:()=>d});var r=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function c(e,n){if(null==e)return{};var t,r,o=function(e,n){if(null==e)return{};var t,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var s=r.createContext({}),l=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},m=function(e){var n=l(e.components);return r.createElement(s.Provider,{value:n},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},p=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,m=c(e,["components","mdxType","originalType","parentName"]),u=l(t),p=o,d=u["".concat(s,".").concat(p)]||u[p]||h[p]||a;return t?r.createElement(d,i(i({ref:n},m),{},{components:t})):r.createElement(d,i({ref:n},m))}));function d(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=p;var c={};for(var s in n)hasOwnProperty.call(n,s)&&(c[s]=n[s]);c.originalType=e,c[u]="string"==typeof e?e:o,i[1]=c;for(var l=2;l<a;l++)i[l]=t[l];return r.createElement.apply(null,i)}return r.createElement.apply(null,t)}p.displayName="MDXCreateElement"},3886:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>h,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var r=t(7462),o=(t(7294),t(3905));const a={sidebar_position:2},i="Consumer Chain Governance",c={unversionedId:"consumer-development/consumer-chain-governance",id:"version-v3.3.0/consumer-development/consumer-chain-governance",title:"Consumer Chain Governance",description:'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.',source:"@site/versioned_docs/version-v3.3.0/consumer-development/consumer-chain-governance.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-chain-governance",permalink:"/interchain-security/legacy/v3.3.0/consumer-development/consumer-chain-governance",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/legacy/v3.3.0/consumer-development/app-integration"},next:{title:"Onboarding Checklist",permalink:"/interchain-security/legacy/v3.3.0/consumer-development/onboarding"}},s={},l=[{value:"Democracy module",id:"democracy-module",level:2},{value:"CosmWasm",id:"cosmwasm",level:2},{value:"The Whitelist",id:"the-whitelist",level:2}],m={toc:l},u="wrapper";function h(e){let{components:n,...t}=e;return(0,o.kt)(u,(0,r.Z)({},m,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-chain-governance"},"Consumer Chain Governance"),(0,o.kt)("p",null,'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.'),(0,o.kt)("h2",{id:"democracy-module"},"Democracy module"),(0,o.kt)("p",null,"The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy."),(0,o.kt)("p",null,"Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus."),(0,o.kt)("p",null,"For an example, see the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy"},"Democracy Consumer")),(0,o.kt)("h2",{id:"cosmwasm"},"CosmWasm"),(0,o.kt)("p",null,"There are several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain."),(0,o.kt)("p",null,"For an example, see ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/neutron-org/neutron/"},"Neutron"),"."),(0,o.kt)("h2",{id:"the-whitelist"},"The Whitelist"),(0,o.kt)("p",null,"Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/neutron-org/neutron/blob/main/app/proposals_allowlisting.go"},"Neutron's")," whitelist."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/9fe5be76.d25fa769.js b/legacy/assets/js/9fe5be76.d25fa769.js new file mode 100644 index 0000000000..4630cce199 --- /dev/null +++ b/legacy/assets/js/9fe5be76.d25fa769.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4391],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>g});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function l(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function o(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),d=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},p=function(e){var t=d(e.components);return n.createElement(c.Provider,{value:t},e.children)},s="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),s=d(r),m=a,g=s["".concat(c,".").concat(m)]||s[m]||u[m]||i;return r?n.createElement(g,l(l({ref:t},p),{},{components:r})):n.createElement(g,l({ref:t},p))}));function g(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,l=new Array(i);l[0]=m;var o={};for(var c in t)hasOwnProperty.call(t,c)&&(o[c]=t[c]);o.originalType=e,o[s]="string"==typeof e?e:a,l[1]=o;for(var d=2;d<i;d++)l[d]=r[d];return n.createElement.apply(null,l)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},7182:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>l,default:()=>u,frontMatter:()=>i,metadata:()=>o,toc:()=>d});var n=r(7462),a=(r(7294),r(3905));const i={sidebar_position:1,title:"ADRs"},l="Architecture Decision Records (ADR)",o={unversionedId:"adrs/intro",id:"version-v3.3.0/adrs/intro",title:"ADRs",description:"This is a location to record all high-level architecture decisions in the Interchain Security project.",source:"@site/versioned_docs/version-v3.3.0/adrs/intro.md",sourceDirName:"adrs",slug:"/adrs/intro",permalink:"/interchain-security/legacy/v3.3.0/adrs/intro",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:1,frontMatter:{sidebar_position:1,title:"ADRs"},sidebar:"tutorialSidebar",previous:{title:"Frequently Asked Questions",permalink:"/interchain-security/legacy/v3.3.0/faq"},next:{title:"ADR Template",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-prop"}},c={},d=[{value:"Table of Contents",id:"table-of-contents",level:2}],p={toc:d},s="wrapper";function u(e){let{components:t,...r}=e;return(0,a.kt)(s,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"architecture-decision-records-adr"},"Architecture Decision Records (ADR)"),(0,a.kt)("p",null,"This is a location to record all high-level architecture decisions in the Interchain Security project."),(0,a.kt)("p",null,"You can read more about the ADR concept in this ",(0,a.kt)("a",{parentName:"p",href:"https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0#.78xhdix6t"},"blog post"),"."),(0,a.kt)("p",null,"An ADR should provide:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Context on the relevant goals and the current state"),(0,a.kt)("li",{parentName:"ul"},"Proposed changes to achieve the goals"),(0,a.kt)("li",{parentName:"ul"},"Summary of pros and cons"),(0,a.kt)("li",{parentName:"ul"},"References"),(0,a.kt)("li",{parentName:"ul"},"Changelog")),(0,a.kt)("p",null,"Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and\njustification for a change in architecture, or for the architecture of something\nnew. The spec is much more compressed and streamlined summary of everything as\nit is or should be."),(0,a.kt)("p",null,"If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match."),(0,a.kt)("p",null,"Note the context/background should be written in the present tense."),(0,a.kt)("p",null,"To suggest an ADR, please make use of the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/adrs/adr-template"},"ADR template")," provided."),(0,a.kt)("h2",{id:"table-of-contents"},"Table of Contents"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"ADR ","#"),(0,a.kt)("th",{parentName:"tr",align:null},"Description"),(0,a.kt)("th",{parentName:"tr",align:null},"Status"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.3.0/adrs/adr-001-key-assignment"},"001")),(0,a.kt)("td",{parentName:"tr",align:null},"Consumer chain key assignment"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.3.0/adrs/adr-002-throttle"},"002")),(0,a.kt)("td",{parentName:"tr",align:null},"Jail Throttling"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.3.0/adrs/adr-003-equivocation-gov-proposal"},"003")),(0,a.kt)("td",{parentName:"tr",align:null},"Equivocation governance proposal"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"./adr-004-denom-dos-fixes"},"004")),(0,a.kt)("td",{parentName:"tr",align:null},"Denom DOS fixes"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.3.0/adrs/adr-005-cryptographic-equivocation-verification"},"005")),(0,a.kt)("td",{parentName:"tr",align:null},"Cryptographic verification of equivocation evidence"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, In-progress")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-prop"},"007")),(0,a.kt)("td",{parentName:"tr",align:null},"Pause validator unbonding during equivocation proposal"),(0,a.kt)("td",{parentName:"tr",align:null},"Proposed")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.3.0/adrs/adr-008-throttle-retries"},"008")),(0,a.kt)("td",{parentName:"tr",align:null},"Throttle with retries"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, In-progress")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.3.0/adrs/adr-009-soft-opt-out"},"009")),(0,a.kt)("td",{parentName:"tr",align:null},"Soft Opt-out"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.3.0/adrs/adr-010-standalone-changeover"},"010")),(0,a.kt)("td",{parentName:"tr",align:null},"Standalone to Consumer Changeover"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.3.0/adrs/adr-011-improving-test-confidence"},"011")),(0,a.kt)("td",{parentName:"tr",align:null},"Improving testing and increasing confidence"),(0,a.kt)("td",{parentName:"tr",align:null},"Proposed")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.3.0/adrs/adr-012-separate-releasing"},"012")),(0,a.kt)("td",{parentName:"tr",align:null},"Separate Releasing"),(0,a.kt)("td",{parentName:"tr",align:null},"Proposed")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.3.0/adrs/adr-013-equivocation-slashing"},"013")),(0,a.kt)("td",{parentName:"tr",align:null},"Slashing on the provider for consumer equivocation"),(0,a.kt)("td",{parentName:"tr",align:null},"Proposed")))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/9fecc647.8f3743c2.js b/legacy/assets/js/9fecc647.8f3743c2.js new file mode 100644 index 0000000000..03aed4ba72 --- /dev/null +++ b/legacy/assets/js/9fecc647.8f3743c2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8194],{3905:(t,e,n)=>{n.d(e,{Zo:()=>p,kt:()=>g});var a=n(7294);function i(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function r(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,a)}return n}function l(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?r(Object(n),!0).forEach((function(e){i(t,e,n[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))}))}return t}function s(t,e){if(null==t)return{};var n,a,i=function(t,e){if(null==t)return{};var n,a,i={},r=Object.keys(t);for(a=0;a<r.length;a++)n=r[a],e.indexOf(n)>=0||(i[n]=t[n]);return i}(t,e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);for(a=0;a<r.length;a++)n=r[a],e.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(i[n]=t[n])}return i}var o=a.createContext({}),u=function(t){var e=a.useContext(o),n=e;return t&&(n="function"==typeof t?t(e):l(l({},e),t)),n},p=function(t){var e=u(t.components);return a.createElement(o.Provider,{value:e},t.children)},d="mdxType",c={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},m=a.forwardRef((function(t,e){var n=t.components,i=t.mdxType,r=t.originalType,o=t.parentName,p=s(t,["components","mdxType","originalType","parentName"]),d=u(n),m=i,g=d["".concat(o,".").concat(m)]||d[m]||c[m]||r;return n?a.createElement(g,l(l({ref:e},p),{},{components:n})):a.createElement(g,l({ref:e},p))}));function g(t,e){var n=arguments,i=e&&e.mdxType;if("string"==typeof t||i){var r=n.length,l=new Array(r);l[0]=m;var s={};for(var o in e)hasOwnProperty.call(e,o)&&(s[o]=e[o]);s.originalType=t,s[d]="string"==typeof t?t:i,l[1]=s;for(var u=2;u<r;u++)l[u]=n[u];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},689:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>o,contentTitle:()=>l,default:()=>c,frontMatter:()=>r,metadata:()=>s,toc:()=>u});var a=n(7462),i=(n(7294),n(3905));const r={sidebar_position:12,title:"Improving testing and increasing confidence"},l="ADR 11: Improving testing and increasing confidence",s={unversionedId:"adrs/adr-011-improving-test-confidence",id:"version-v3.3.1-lsm/adrs/adr-011-improving-test-confidence",title:"Improving testing and increasing confidence",description:"Changelog",source:"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-011-improving-test-confidence.md",sourceDirName:"adrs",slug:"/adrs/adr-011-improving-test-confidence",permalink:"/interchain-security/legacy/adrs/adr-011-improving-test-confidence",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:12,frontMatter:{sidebar_position:12,title:"Improving testing and increasing confidence"},sidebar:"tutorialSidebar",previous:{title:"Standalone to Consumer Changeover",permalink:"/interchain-security/legacy/adrs/adr-010-standalone-changeover"},next:{title:"Separate Releasing",permalink:"/interchain-security/legacy/adrs/adr-012-separate-releasing"}},o={},u=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Current state of testing",id:"current-state-of-testing",level:4},{value:"Unit testing",id:"unit-testing",level:3},{value:"Integration testing",id:"integration-testing",level:3},{value:"End-to-end testing",id:"end-to-end-testing",level:3},{value:"Decision",id:"decision",level:2},{value:"1. Connect specifications to code and tooling",id:"1-connect-specifications-to-code-and-tooling",level:3},{value:"Decision context and hypothesis",id:"decision-context-and-hypothesis",level:4},{value:"Main benefit",id:"main-benefit",level:4},{value:"2. Improve e2e tooling",id:"2-improve-e2e-tooling",level:3},{value:"Matrix tests",id:"matrix-tests",level:4},{value:"Introducing e2e regression testing",id:"introducing-e2e-regression-testing",level:4},{value:"Introducing e2e CometMock tests",id:"introducing-e2e-cometmock-tests",level:4},{value:"3. Introduce innovative testing approaches",id:"3-introduce-innovative-testing-approaches",level:3},{value:"Model",id:"model",level:4},{value:"Driver",id:"driver",level:4},{value:"Harness",id:"harness",level:4},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],p={toc:u},d="wrapper";function c(t){let{components:e,...r}=t;return(0,i.kt)(d,(0,a.Z)({},p,r,{components:e,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"adr-11-improving-testing-and-increasing-confidence"},"ADR 11: Improving testing and increasing confidence"),(0,i.kt)("h2",{id:"changelog"},"Changelog"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"2023-08-11: Proposed, first draft of ADR.")),(0,i.kt)("h2",{id:"status"},"Status"),(0,i.kt)("p",null,"Proposed"),(0,i.kt)("h2",{id:"context"},"Context"),(0,i.kt)("p",null,"Testing, QA, and maintenance of interchain-security libraries is an ever-evolving area of software engineering we have to keep incrementally improving. The purpose of the QA process is to catch bugs as early as possible. In an ideal development workflow a bug should never reach production. A bug found in the specification stage is a lot cheaper to resolve than a bug discovered in production (or even in testnet). Ideally, all bugs should be found during the CI execution, and we hope that no bugs will ever even reach the testnet (although nothing can replace actual system stress test under load interacting with users)."),(0,i.kt)("p",null,"During development and testnet operation the following types of bugs were the most commonly found:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"improper iterator usage"),(0,i.kt)("li",{parentName:"ul"},"unbounded array access/iteration"),(0,i.kt)("li",{parentName:"ul"},"improper input handling and validation"),(0,i.kt)("li",{parentName:"ul"},"improper cached context usage"),(0,i.kt)("li",{parentName:"ul"},"non-determinism check (improper use of maps in go, relying on random values)"),(0,i.kt)("li",{parentName:"ul"},"KV store management and/or how keys are defined"),(0,i.kt)("li",{parentName:"ul"},"deserialization issues arising from consumer/provider versioning mismatch")),(0,i.kt)("p",null,"Such bugs can be discovered earlier with better tooling. Some of these bugs can induce increases in block times, chain halts, state corruption, or introduce an attack surface which is difficult to remove if other systems have started depending on that behavior."),(0,i.kt)("h4",{id:"current-state-of-testing"},"Current state of testing"),(0,i.kt)("p",null,"Our testing suites consist of multiple parts, each with their own trade-offs and benefits with regards to code coverage, complexity and confidence they provide."),(0,i.kt)("h3",{id:"unit-testing"},"Unit testing"),(0,i.kt)("p",null,"Unit testing is employed mostly for testing single-module functionality. It is the first step in testing and often the most practical. While highly important, unit tests often ",(0,i.kt)("strong",{parentName:"p"},"test a single piece of code")," and don't test relationships between different moving parts, this makes them less valuable when dealing with multi-module interactions."),(0,i.kt)("p",null,"Unit tests often employ mocks to abstract parts of the system that are not under test. Mocks are not equivalent to actual models and should not be treated as such."),(0,i.kt)("p",null,"Out of all the approaches used, unit testing has the most tools available and the coverage can simply be displayed as % of code lines tested. Although this is a very nice and very easy to understand metric, it does not speak about the quality of the test coverage."),(0,i.kt)("p",null,"Since distributed systems testing is a lot more involved, unit tests are oftentimes not sufficient to cover complex interactions. Unit tests are still necessary and helpful, but in cases where unit tests are not helpful e2e or integration tests should be favored."),(0,i.kt)("h3",{id:"integration-testing"},"Integration testing"),(0,i.kt)("p",null,"With integration testing we ",(0,i.kt)("strong",{parentName:"p"},"test the multi-module interactions")," while isolating them from the remainder of the system.\nIntegration tests can uncover bugs that are often missed by unit tests."),(0,i.kt)("p",null,"It is very difficult to gauge the actual test coverage imparted by integration tests and the available tooling is limited.\nIn interchain-security we employ the ",(0,i.kt)("inlineCode",{parentName:"p"},"ibc-go/testing")," framework to test interactions in-memory."),(0,i.kt)("p",null,"At present, integration testing does not involve the consensus layer - it is only concerned with application level state and logic."),(0,i.kt)("h3",{id:"end-to-end-testing"},"End-to-end testing"),(0,i.kt)("p",null,"In our context end-to-end testing comprises of tests that use the actual application binaries in an isolated environment (e.g. docker container). During test execution the inputs are meant to simulate actual user interaction, either by submitting transactions/queries using the command line or using gRPC/REST APIs and checking for state changes after an action has been performed. With this testing strategy we also include the consensus layer in all of our runs. This is the closest we can get to testing user interactions without starting a full testnet."),(0,i.kt)("p",null,"End-to-end testing strategies vary between different teams and projects and we strive to unify our approach to the best of our ability (at least for ICS and gaia)."),(0,i.kt)("p",null,"The available tooling does not give us significant (or relevant) line of code coverage information since most of the tools are geared towards analyzing unit tests and simple code branch evaluation."),(0,i.kt)("p",null,"We aim to adapt our best practices by learning from other similar systems and projects such as cosmos-sdk, ibc-go and CometBFT."),(0,i.kt)("h2",{id:"decision"},"Decision"),(0,i.kt)("h3",{id:"1-connect-specifications-to-code-and-tooling"},"1. Connect specifications to code and tooling"),(0,i.kt)("p",null,"Oftentimes, specifications are disconnected from the development and QA processes. This gives rise to problems where the specification does not reflect the actual state of the system and vice-versa.\nUsually specifications are just text files that are rarely used and go unmaintained after a while, resulting in consistency issues and misleading instructions/expectations about system behavior."),(0,i.kt)("h4",{id:"decision-context-and-hypothesis"},"Decision context and hypothesis"),(0,i.kt)("p",null,"Specifications written in a dedicated and executable specification language are easier to maintain than the ones written entirely in text.\nAdditionally, we can create models based on the specification OR make the model equivalent to a specification."),(0,i.kt)("p",null,"Models do not care about the intricacies of implementation and neither do specifications. Since both models and specifications care about concisely and accurately describing a system (such as a finite state machine), we see a benefit of adding model based tools (such as ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/informalsystems/quint"},"quint"),") to our testing and development workflows."),(0,i.kt)("h4",{id:"main-benefit"},"Main benefit"),(0,i.kt)("p",null,"MBT tooling can be used to generate test traces that can be executed by multiple different testing setups."),(0,i.kt)("h3",{id:"2-improve-e2e-tooling"},"2. Improve e2e tooling"),(0,i.kt)("h4",{id:"matrix-tests"},"Matrix tests"),(0,i.kt)("p",null,"Instead of only running tests against current ",(0,i.kt)("inlineCode",{parentName:"p"},"main")," branch we should adopt an approach where we also:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"run regression tests against different released software versions")," (",(0,i.kt)("inlineCode",{parentName:"li"},"ICS v1 vs v2 vs v3"),")"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"run non-determinism tests to uncover issues quickly"))),(0,i.kt)("p",null,"Matrix tests can be implemented using ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/informalsystems/CometMock"},"CometMock")," and refactoring our current e2e CI setup."),(0,i.kt)("h4",{id:"introducing-e2e-regression-testing"},"Introducing e2e regression testing"),(0,i.kt)("p",null,"This e2e test suite would execute using a cronjob in our CI (nightly, multiple times a day etc.)"),(0,i.kt)("p",null,"Briefly, the same set of traces is run against different ",(0,i.kt)("strong",{parentName:"p"},"maintained")," versions of the software and the ",(0,i.kt)("inlineCode",{parentName:"p"},"main")," branch.\nThis would allow us to discover potential issues during development instead of in a testnet scenarios."),(0,i.kt)("p",null,"The most valuable issues that can be discovered in this way are ",(0,i.kt)("strong",{parentName:"p"},"state breaking changes"),", ",(0,i.kt)("strong",{parentName:"p"},"regressions")," and ",(0,i.kt)("strong",{parentName:"p"},"version incompatibilities"),"."),(0,i.kt)("p",null,"The setup is illustrated by the image below.\n",(0,i.kt)("img",{alt:"e2e matrix tests",src:n(1366).Z,width:"2170",height:"1624"})),(0,i.kt)("p",null,"This table explains which versions are tested against each other for the same set of test traces:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"\u2705 marks a passing test"),(0,i.kt)("li",{parentName:"ul"},"\u274c marks a failing test")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"USES: ICS v1 PROVIDER")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"start chain")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"add key")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"delegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"undelegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"redelegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"downtime")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"equivocation")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"stop chain")))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"v1 consumer (sdk45,ibc4.3)")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"v2 consumer (sdk45, ibc4.4)")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"v3 consumer (sdk47, ibc7)")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"main consumer")),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"neutron")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"stride")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c")))),(0,i.kt)("h4",{id:"introducing-e2e-cometmock-tests"},"Introducing e2e CometMock tests"),(0,i.kt)("p",null,"CometMock is a mock implementation of the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft"},"CometBFT")," consensus engine. It supports most operations performed by CometBFT while also being lightweight and relatively easy to use."),(0,i.kt)("p",null,'CometMock tests allow more nuanced control of test scenarios because CometMock can "fool" the blockchain app into thinking that a certain number of blocks had passed.\n',(0,i.kt)("strong",{parentName:"p"},"This allows us to test very nuanced scenarios, difficult edge cases and long-running operations (such as unbonding operations).")),(0,i.kt)("p",null,"Examples of tests made easier with CometMock are listed below:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"regression tests"),(0,i.kt)("li",{parentName:"ul"},"non-determinism tests"),(0,i.kt)("li",{parentName:"ul"},"upgrade tests"),(0,i.kt)("li",{parentName:"ul"},"state-breaking changes")),(0,i.kt)("p",null,"With CometMock, the ",(0,i.kt)("strong",{parentName:"p"},"matrix test")," approach can also be used. The image below illustrates a CometMock setup that can be used to discover non-deterministic behavior and state-breaking changes.\n",(0,i.kt)("img",{alt:"e2e matrix tests",src:n(3809).Z,width:"3714",height:"2082"})),(0,i.kt)("p",null,"This table explains which versions are tested against each other for the same set of test traces:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"\u2705 marks a passing test"),(0,i.kt)("li",{parentName:"ul"},"\u274c marks a failing test")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"SCENARIO")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"start chain")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"add key")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"delegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"undelegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"redelegate")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"downtime")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"equivocation")),(0,i.kt)("th",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"th"},"stop chain")))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"v3 provi + v3 consu")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"main provi + main consu")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"commit provi + commit consu")),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u2705"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c"),(0,i.kt)("td",{parentName:"tr",align:null},"\u274c")))),(0,i.kt)("p",null,"Briefly; multiple versions of the application are run against the same CometMock instance and any deviations in app behavior would result in ",(0,i.kt)("inlineCode",{parentName:"p"},"app hash")," errors (the apps would be in different states after performing the same set of actions)."),(0,i.kt)("h3",{id:"3-introduce-innovative-testing-approaches"},"3. Introduce innovative testing approaches"),(0,i.kt)("p",null,"When discussing e2e testing, some very important patterns emerge - especially if test traces are used instead of ad-hoc tests written by hand."),(0,i.kt)("p",null,"We see a unique opportunity to clearly identify concerns and modularize the testing architecture. "),(0,i.kt)("p",null,"The e2e testing frameworks can be split into a ",(0,i.kt)("strong",{parentName:"p"},"pipeline consisting of 3 parts: model, driver and harness"),"."),(0,i.kt)("h4",{id:"model"},"Model"),(0,i.kt)("p",null,"Model is the part of the system that can emulate the behavior of the system under test.\nIdeally, it is very close to the specification and is written in a specification language such as quint, TLA+ or similar.\nOne of the purposes of the model is that it can be used to generate test traces. "),(0,i.kt)("h4",{id:"driver"},"Driver"),(0,i.kt)("p",null,"The purpose of the driver is to accept test traces (generated by the model or written by hand), process them and provide inputs to the next part of the pipeline."),(0,i.kt)("p",null,"Basically, the driver sits between the model and the actual infrastructure on which the test traces are being executed on."),(0,i.kt)("h4",{id:"harness"},"Harness"),(0,i.kt)("p",null,"Harness is the infrastructure layer of the pipeline that accepts inputs from the driver."),(0,i.kt)("p",null,"There can be multiple harnesses as long as they can perform four things:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"bootstrap a test execution environment (local, docker, k8s\u2026)"),(0,i.kt)("li",{parentName:"ul"},"accept inputs from drivers"),(0,i.kt)("li",{parentName:"ul"},"perform the action specified by the driver"),(0,i.kt)("li",{parentName:"ul"},"report results after performing actions")),(0,i.kt)("h2",{id:"consequences"},"Consequences"),(0,i.kt)("p",null,"The procedure outlined in this ADR is not an all-or-nothing approach. Concepts introduced here do not rely on each other, so this ADR may only be applied partially without negative impact on test coverage and code confidence."),(0,i.kt)("h3",{id:"positive"},"Positive"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"introduction of maintainable MBT solutions")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},'improvement over the current "difftest" setup that relies on an opinionated typescript model and go driver')),(0,i.kt)("ol",{start:2},(0,i.kt)("li",{parentName:"ol"},"increased code coverage and confidence")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"using CometMock allows us to run more tests in less time"),(0,i.kt)("li",{parentName:"ul"},"adding matrix e2e tests allows us to quickly pinpoint differences between code versions")),(0,i.kt)("h3",{id:"negative"},"Negative"),(0,i.kt)("p",null,"It might be easier to forgo the MBT tooling and instead focus on pure property based testing"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/667"},"PBT proof of concept")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/flyingmutant/rapid"},"property based testing in go"))),(0,i.kt)("p",null,'The solutions are potentially expensive if we increase usage of the CI pipeline - this is fixed by running "expensive" tests using a cronjob, instead of running them on every commit.'),(0,i.kt)("h3",{id:"neutral"},"Neutral"),(0,i.kt)("p",null,"The process of changing development and testing process is not something that can be thought of and delivered quickly. Luckily, the changes can be rolled out incrementally without impacting existing workflows."),(0,i.kt)("h2",{id:"references"},"References"),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/gaia/issues/2427"},"https://github.com/cosmos/gaia/issues/2427")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/gaia/issues/2420"},"https://github.com/cosmos/gaia/issues/2420")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/ibc-go/tree/main/e2e"},"ibc-go e2e tests"))))}c.isMDXComponent=!0},3809:(t,e,n)=>{n.d(e,{Z:()=>a});const a=n.p+"assets/images/cometmock_matrix_test-714f36252aff9df4214823e3145d0ef5.png"},1366:(t,e,n)=>{n.d(e,{Z:()=>a});const a=n.p+"assets/images/matrix_e2e_tests-30681305077301daaf3097e1952b54bb.png"}}]); \ No newline at end of file diff --git a/legacy/assets/js/a2707102.645ad012.js b/legacy/assets/js/a2707102.645ad012.js new file mode 100644 index 0000000000..d73101bb45 --- /dev/null +++ b/legacy/assets/js/a2707102.645ad012.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[457],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>g});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function l(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function o(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),d=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},p=function(e){var t=d(e.components);return n.createElement(c.Provider,{value:t},e.children)},s="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),s=d(r),m=a,g=s["".concat(c,".").concat(m)]||s[m]||u[m]||i;return r?n.createElement(g,l(l({ref:t},p),{},{components:r})):n.createElement(g,l({ref:t},p))}));function g(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,l=new Array(i);l[0]=m;var o={};for(var c in t)hasOwnProperty.call(t,c)&&(o[c]=t[c]);o.originalType=e,o[s]="string"==typeof e?e:a,l[1]=o;for(var d=2;d<i;d++)l[d]=r[d];return n.createElement.apply(null,l)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},1663:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>l,default:()=>u,frontMatter:()=>i,metadata:()=>o,toc:()=>d});var n=r(7462),a=(r(7294),r(3905));const i={sidebar_position:1,title:"ADRs"},l="Architecture Decision Records (ADR)",o={unversionedId:"adrs/intro",id:"adrs/intro",title:"ADRs",description:"This is a location to record all high-level architecture decisions in the Interchain Security project.",source:"@site/docs/adrs/intro.md",sourceDirName:"adrs",slug:"/adrs/intro",permalink:"/interchain-security/legacy/adrs/intro",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1,title:"ADRs"},sidebar:"tutorialSidebar",previous:{title:"Frequently Asked Questions",permalink:"/interchain-security/legacy/faq"},next:{title:"ADR Template",permalink:"/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop"}},c={},d=[{value:"Table of Contents",id:"table-of-contents",level:2}],p={toc:d},s="wrapper";function u(e){let{components:t,...r}=e;return(0,a.kt)(s,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"architecture-decision-records-adr"},"Architecture Decision Records (ADR)"),(0,a.kt)("p",null,"This is a location to record all high-level architecture decisions in the Interchain Security project."),(0,a.kt)("p",null,"You can read more about the ADR concept in this ",(0,a.kt)("a",{parentName:"p",href:"https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0#.78xhdix6t"},"blog post"),"."),(0,a.kt)("p",null,"An ADR should provide:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Context on the relevant goals and the current state"),(0,a.kt)("li",{parentName:"ul"},"Proposed changes to achieve the goals"),(0,a.kt)("li",{parentName:"ul"},"Summary of pros and cons"),(0,a.kt)("li",{parentName:"ul"},"References"),(0,a.kt)("li",{parentName:"ul"},"Changelog")),(0,a.kt)("p",null,"Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and\njustification for a change in architecture, or for the architecture of something\nnew. The spec is much more compressed and streamlined summary of everything as\nit is or should be."),(0,a.kt)("p",null,"If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match."),(0,a.kt)("p",null,"Note the context/background should be written in the present tense."),(0,a.kt)("p",null,"To suggest an ADR, please make use of the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/adrs/adr-template"},"ADR template")," provided."),(0,a.kt)("h2",{id:"table-of-contents"},"Table of Contents"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"ADR ","#"),(0,a.kt)("th",{parentName:"tr",align:null},"Description"),(0,a.kt)("th",{parentName:"tr",align:null},"Status"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-001-key-assignment"},"001")),(0,a.kt)("td",{parentName:"tr",align:null},"Consumer chain key assignment"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-002-throttle"},"002")),(0,a.kt)("td",{parentName:"tr",align:null},"Jail Throttling"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposal"},"003")),(0,a.kt)("td",{parentName:"tr",align:null},"Equivocation governance proposal"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"./adr-004-denom-dos-fixes"},"004")),(0,a.kt)("td",{parentName:"tr",align:null},"Denom DOS fixes"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification"},"005")),(0,a.kt)("td",{parentName:"tr",align:null},"Cryptographic verification of equivocation evidence"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, In-progress")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop"},"007")),(0,a.kt)("td",{parentName:"tr",align:null},"Pause validator unbonding during equivocation proposal"),(0,a.kt)("td",{parentName:"tr",align:null},"Proposed")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-008-throttle-retries"},"008")),(0,a.kt)("td",{parentName:"tr",align:null},"Throttle with retries"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, In-progress")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-009-soft-opt-out"},"009")),(0,a.kt)("td",{parentName:"tr",align:null},"Soft Opt-out"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-010-standalone-changeover"},"010")),(0,a.kt)("td",{parentName:"tr",align:null},"Standalone to Consumer Changeover"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-011-improving-test-confidence"},"011")),(0,a.kt)("td",{parentName:"tr",align:null},"Improving testing and increasing confidence"),(0,a.kt)("td",{parentName:"tr",align:null},"Proposed")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-012-separate-releasing"},"012")),(0,a.kt)("td",{parentName:"tr",align:null},"Separate Releasing"),(0,a.kt)("td",{parentName:"tr",align:null},"Proposed")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/adrs/adr-013-equivocation-slashing"},"013")),(0,a.kt)("td",{parentName:"tr",align:null},"Slashing on the provider for consumer equivocation"),(0,a.kt)("td",{parentName:"tr",align:null},"Proposed")))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/a31f1e88.25172256.js b/legacy/assets/js/a31f1e88.25172256.js new file mode 100644 index 0000000000..16de0196af --- /dev/null +++ b/legacy/assets/js/a31f1e88.25172256.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6255],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},o=Object.keys(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(r),m=i,f=d["".concat(l,".").concat(m)]||d[m]||u[m]||o;return r?n.createElement(f,a(a({ref:t},p),{},{components:r})):n.createElement(f,a({ref:t},p))}));function f(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=r.length,a=new Array(o);a[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:i,a[1]=s;for(var c=2;c<o;c++)a[c]=r[c];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},8958:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var n=r(7462),i=(r(7294),r(3905));const o={sidebar_position:6},a="Joining Stride",s={unversionedId:"validators/joining-stride",id:"version-v3.2.0/validators/joining-stride",title:"Joining Stride",description:"Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.",source:"@site/versioned_docs/version-v3.2.0/validators/joining-stride.md",sourceDirName:"validators",slug:"/validators/joining-stride",permalink:"/interchain-security/legacy/v3.2.0/validators/joining-stride",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"tutorialSidebar",previous:{title:"Joining Neutron",permalink:"/interchain-security/legacy/v3.2.0/validators/joining-neutron"},next:{title:"Frequently Asked Questions",permalink:"/interchain-security/legacy/v3.2.0/faq"}},l={},c=[{value:"Note",id:"note",level:2},{value:"Resources",id:"resources",level:2}],p={toc:c},d="wrapper";function u(e){let{components:t,...r}=e;return(0,i.kt)(d,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"joining-stride"},"Joining Stride"),(0,i.kt)("p",null,"Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using ",(0,i.kt)("inlineCode",{parentName:"p"},"cosmoshub-4")," validator set."),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"stride-1")," network (mainnet) will perform a software upgrade and at height ",(0,i.kt)("inlineCode",{parentName:"p"},"4616678")," that will transition the network to using the Cosmos Hub's (",(0,i.kt)("inlineCode",{parentName:"p"},"cosmoshub-4"),") validator set."),(0,i.kt)("p",null," You can find instructions about the Stride consumer chain launch and joining the mainnet ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/Stride-Labs/mainnet/tree/main/ics-instructions"},"here"),"."),(0,i.kt)("p",null," This ",(0,i.kt)("a",{parentName:"p",href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt"},"Excalidraw graphic")," explains the timeline of Stride's changeover procedure."),(0,i.kt)("h2",{id:"note"},"Note"),(0,i.kt)("p",null,"Stride re-uses an existing ",(0,i.kt)("inlineCode",{parentName:"p"},"transfer")," channel to send consumer rewards to the provider chain, in order to preserve existing transfer IBC denom between ",(0,i.kt)("inlineCode",{parentName:"p"},"stride-1")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"cosmoshub-4"),"."),(0,i.kt)("h2",{id:"resources"},"Resources"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://docs.stride.zone/docs"},"Stride docs")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt"},"Changeover procedure timeline")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/Stride-Labs/mainnet/tree/main/ics-instructions"},"Changeover upgrade docs"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/a486c914.4dc177eb.js b/legacy/assets/js/a486c914.4dc177eb.js new file mode 100644 index 0000000000..7de72432db --- /dev/null +++ b/legacy/assets/js/a486c914.4dc177eb.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7988],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>m});var i=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,i,r=function(e,t){if(null==e)return{};var n,i,r={},a=Object.keys(e);for(i=0;i<a.length;i++)n=a[i],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i<a.length;i++)n=a[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=i.createContext({}),l=function(e){var t=i.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=l(e.components);return i.createElement(c.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},h=i.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=l(n),h=r,m=d["".concat(c,".").concat(h)]||d[h]||p[h]||a;return n?i.createElement(m,o(o({ref:t},u),{},{components:n})):i.createElement(m,o({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,o=new Array(a);o[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var l=2;l<a;l++)o[l]=n[l];return i.createElement.apply(null,o)}return i.createElement.apply(null,n)}h.displayName="MDXCreateElement"},5131:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>p,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var i=n(7462),r=(n(7294),n(3905));const a={sidebar_position:4},o="Consumer Initiated Slashing",s={unversionedId:"features/slashing",id:"version-v3.3.1-lsm/features/slashing",title:"Consumer Initiated Slashing",description:"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.",source:"@site/versioned_docs/version-v3.3.1-lsm/features/slashing.md",sourceDirName:"features",slug:"/features/slashing",permalink:"/interchain-security/legacy/features/slashing",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"ICS Provider Proposals",permalink:"/interchain-security/legacy/features/proposals"},next:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/legacy/consumer-development/app-integration"}},c={},l=[{value:"Downtime infractions",id:"downtime-infractions",level:2}],u={toc:l},d="wrapper";function p(e){let{components:t,...n}=e;return(0,r.kt)(d,(0,i.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"consumer-initiated-slashing"},"Consumer Initiated Slashing"),(0,r.kt)("p",null,"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.\nIn essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake)."),(0,r.kt)("p",null,"To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized.\nAny infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains."),(0,r.kt)("p",null,"In the current implementation there are 2 important changes brought by the interchain security module:"),(0,r.kt)("h2",{id:"downtime-infractions"},"Downtime infractions"),(0,r.kt)("p",null,"reported by consumer chains are acted upon on the provider as soon as the provider receives the infraction evidence."),(0,r.kt)("p",null,"Instead of slashing, the provider will only jail offending validator for the duration of time established in the chain parameters."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Slash throttling (sometimes called jail throttling) mechanism ensures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider.")),(0,r.kt)("h1",{id:"cryptographic-verification-of-equivocation-and-slashing"},"Cryptographic verification of equivocation and slashing"),(0,r.kt)("p",null,"The Cryptographic verification of equivocation allows external agents to submit evidences of light client and double signing attacks observed on a consumer chain. When valid evidence is received, the malicious validators will be slashed, jailed, and tombstoned on the provider."),(0,r.kt)("p",null,"The feature is outlined in ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification"},"ADR-005")," and ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/adrs/adr-013-equivocation-slashing"},"ADR-013"),"."),(0,r.kt)("p",null,"By sending a ",(0,r.kt)("inlineCode",{parentName:"p"},"MsgSubmitConsumerMisbehaviour")," or a ",(0,r.kt)("inlineCode",{parentName:"p"},"MsgSubmitConsumerDoubleVoting")," transaction, the provider will\nverify the reported equivocation and, if successful, slash, jail, and tombstone the malicious validator."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/a8d2c030.3892c3ef.js b/legacy/assets/js/a8d2c030.3892c3ef.js new file mode 100644 index 0000000000..bac33d1d25 --- /dev/null +++ b/legacy/assets/js/a8d2c030.3892c3ef.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[137],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>y});var i=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,i)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){n(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,i,n=function(e,t){if(null==e)return{};var r,i,n={},o=Object.keys(e);for(i=0;i<o.length;i++)r=o[i],t.indexOf(r)>=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i<o.length;i++)r=o[i],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=i.createContext({}),l=function(e){var t=i.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},u=function(e){var t=l(e.components);return i.createElement(s.Provider,{value:t},e.children)},h="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},p=i.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),h=l(r),p=n,y=h["".concat(s,".").concat(p)]||h[p]||d[p]||o;return r?i.createElement(y,a(a({ref:t},u),{},{components:r})):i.createElement(y,a({ref:t},u))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,a=new Array(o);a[0]=p;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[h]="string"==typeof e?e:n,a[1]=c;for(var l=2;l<o;l++)a[l]=r[l];return i.createElement.apply(null,a)}return i.createElement.apply(null,r)}p.displayName="MDXCreateElement"},8540:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>d,frontMatter:()=>o,metadata:()=>c,toc:()=>l});var i=r(7462),n=(r(7294),r(3905));const o={sidebar_position:2},a="Terminology",c={unversionedId:"introduction/terminology",id:"version-v3.3.1-lsm/introduction/terminology",title:"Terminology",description:"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.",source:"@site/versioned_docs/version-v3.3.1-lsm/introduction/terminology.md",sourceDirName:"introduction",slug:"/introduction/terminology",permalink:"/interchain-security/legacy/introduction/terminology",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/legacy/introduction/overview"},next:{title:"Interchain Security Parameters",permalink:"/interchain-security/legacy/introduction/params"}},s={},l=[{value:"Shared Security",id:"shared-security",level:2},{value:"Interchain Security",id:"interchain-security",level:2},{value:"Replicated Security",id:"replicated-security",level:2},{value:"Mesh security",id:"mesh-security",level:2},{value:"Consumer Chain",id:"consumer-chain",level:2},{value:"Standalone Chain",id:"standalone-chain",level:2},{value:"Changeover Procedure",id:"changeover-procedure",level:2}],u={toc:l},h="wrapper";function d(e){let{components:t,...r}=e;return(0,n.kt)(h,(0,i.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"terminology"},"Terminology"),(0,n.kt)("p",null,"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions."),(0,n.kt)("h2",{id:"shared-security"},"Shared Security"),(0,n.kt)("p",null,"Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share its proof-of-stake security with another blockchain or off-chain process."),(0,n.kt)("h2",{id:"interchain-security"},"Interchain Security"),(0,n.kt)("p",null,"Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC."),(0,n.kt)("h2",{id:"replicated-security"},"Replicated Security"),(0,n.kt)("p",null,'A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC. Note this documentation is focused on explaining the concepts from replicated security.'),(0,n.kt)("h2",{id:"mesh-security"},"Mesh security"),(0,n.kt)("p",null,"A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see ",(0,n.kt)("a",{parentName:"p",href:"https://informal.systems/blog/replicated-vs-mesh-security"},"Replicated vs. Mesh Security on the Informal Blog"),"."),(0,n.kt)("h2",{id:"consumer-chain"},"Consumer Chain"),(0,n.kt)("p",null,"Chain that is secured by the validator set of the provider, instead of its own.\nReplicated security allows the provider chain validator set to validate blocks on the consumer chain."),(0,n.kt)("h2",{id:"standalone-chain"},"Standalone Chain"),(0,n.kt)("p",null,"Chain that is secured by its own validator set. This chain does not participate in replicated security."),(0,n.kt)("p",null,'Standalone chains may sometimes be called "sovereign" - the terms are synonymous.'),(0,n.kt)("h2",{id:"changeover-procedure"},"Changeover Procedure"),(0,n.kt)("p",null,"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the ",(0,n.kt)("strong",{parentName:"p"},"changeover procedure")," and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/a9646977.2a0404d5.js b/legacy/assets/js/a9646977.2a0404d5.js new file mode 100644 index 0000000000..81fa7286fa --- /dev/null +++ b/legacy/assets/js/a9646977.2a0404d5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[608],{3905:(e,r,t)=>{t.d(r,{Zo:()=>d,kt:()=>f});var n=t(7294);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function o(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?i(Object(t),!0).forEach((function(r){a(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function c(e,r){if(null==e)return{};var t,n,a=function(e,r){if(null==e)return{};var t,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=n.createContext({}),u=function(e){var r=n.useContext(s),t=r;return e&&(t="function"==typeof e?e(r):o(o({},r),e)),t},d=function(e){var r=u(e.components);return n.createElement(s.Provider,{value:r},e.children)},l="mdxType",m={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},p=n.forwardRef((function(e,r){var t=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,d=c(e,["components","mdxType","originalType","parentName"]),l=u(t),p=a,f=l["".concat(s,".").concat(p)]||l[p]||m[p]||i;return t?n.createElement(f,o(o({ref:r},d),{},{components:t})):n.createElement(f,o({ref:r},d))}));function f(e,r){var t=arguments,a=r&&r.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=p;var c={};for(var s in r)hasOwnProperty.call(r,s)&&(c[s]=r[s]);c.originalType=e,c[l]="string"==typeof e?e:a,o[1]=c;for(var u=2;u<i;u++)o[u]=t[u];return n.createElement.apply(null,o)}return n.createElement.apply(null,t)}p.displayName="MDXCreateElement"},2307:(e,r,t)=>{t.d(r,{Z:()=>i});var n=t(7294);const a=function(e){return n.createElement("a",{href:e.href,className:"border shadow rounded-sm border-stone-200 dark:border-stone-800 dark:bg-neutral-900 hover:border-stone-300 hover:shadow-lg dark:hover:border-stone-200 transition-all duration-200 no-underline"},n.createElement("div",{className:"p-6"},n.createElement("h2",{className:""},e.header),n.createElement("p",{className:""},e.summary)))};const i=function(e){return n.createElement("div",{className:"card-section grid grid-cols-1 lg:grid-cols-2 gap-4 no-underline"},e.cards.map(((e,r)=>n.createElement(a,{key:r,href:e.href,header:e.header,summary:e.summary}))))}},8758:(e,r,t)=>{t.d(r,{Z:()=>n});const n=[{href:"/interchain-security/introduction/overview",header:"Basic concepts",summary:"Get started with the basic concepts and ideas."},{href:"/interchain-security/consumer-development/app-integration",header:"Start building",summary:"Click here to start building with Interchain security"},{href:"/interchain-security/features/key-assignment",header:"Feature: Key Assignment",summary:"Learn about the key assignment feature"},{href:"/interchain-security/features/reward-distribution",header:"Feature: Reward Distribution",summary:"Learn about consumer chain rewards distribution"},{href:"/interchain-security/consumer-development/onboarding",header:"Onboarding Checklist",summary:"Checklist to help you integrate Interchain Security, get support and onboard validators"},{href:"/interchain-security/faq",header:"FAQ",summary:"Frequently asked questions about the protocol and its implications"}]},1234:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>d,contentTitle:()=>s,default:()=>f,frontMatter:()=>c,metadata:()=>u,toc:()=>l});var n=t(7462),a=(t(7294),t(3905)),i=t(2307),o=t(8758);const c={sidebar_position:1},s="Interchain Security Docs",u={unversionedId:"index",id:"version-v3.3.0/index",title:"Interchain Security Docs",description:"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.",source:"@site/versioned_docs/version-v3.3.0/index.mdx",sourceDirName:".",slug:"/",permalink:"/interchain-security/legacy/v3.3.0/",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",next:{title:"Overview",permalink:"/interchain-security/legacy/v3.3.0/introduction/overview"}},d={},l=[],m={toc:l},p="wrapper";function f(e){let{components:r,...t}=e;return(0,a.kt)(p,(0,n.Z)({},m,t,{components:r,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"interchain-security-docs"},"Interchain Security Docs"),(0,a.kt)("p",null,"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains."),(0,a.kt)("p",null,"Here you can find information about replicated security, consumer chain development and instructions for validator onboarding."),(0,a.kt)(i.Z,{cards:o.Z,mdxType:"CardSection"}))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/ae63551b.e7e90402.js b/legacy/assets/js/ae63551b.e7e90402.js new file mode 100644 index 0000000000..7f0dea4268 --- /dev/null +++ b/legacy/assets/js/ae63551b.e7e90402.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5056],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,a=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(r),m=i,f=u["".concat(l,".").concat(m)]||u[m]||d[m]||a;return r?n.createElement(f,o(o({ref:t},p),{},{components:r})):n.createElement(f,o({ref:t},p))}));function f(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=r.length,o=new Array(a);o[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:i,o[1]=s;for(var c=2;c<a;c++)o[c]=r[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},1990:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>d,frontMatter:()=>a,metadata:()=>s,toc:()=>c});var n=r(7462),i=(r(7294),r(3905));const a={sidebar_position:6},o="Joining Stride",s={unversionedId:"validators/joining-stride",id:"validators/joining-stride",title:"Joining Stride",description:"Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.",source:"@site/docs/validators/joining-stride.md",sourceDirName:"validators",slug:"/validators/joining-stride",permalink:"/interchain-security/legacy/validators/joining-stride",draft:!1,tags:[],version:"current",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"tutorialSidebar",previous:{title:"Joining Neutron",permalink:"/interchain-security/legacy/validators/joining-neutron"},next:{title:"Frequently Asked Questions",permalink:"/interchain-security/legacy/faq"}},l={},c=[{value:"Note",id:"note",level:2},{value:"Resources",id:"resources",level:2}],p={toc:c},u="wrapper";function d(e){let{components:t,...r}=e;return(0,i.kt)(u,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"joining-stride"},"Joining Stride"),(0,i.kt)("p",null,"Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using ",(0,i.kt)("inlineCode",{parentName:"p"},"cosmoshub-4")," validator set."),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"stride-1")," network (mainnet) will perform a software upgrade and at height ",(0,i.kt)("inlineCode",{parentName:"p"},"4616678")," that will transition the network to using the Cosmos Hub's (",(0,i.kt)("inlineCode",{parentName:"p"},"cosmoshub-4"),") validator set."),(0,i.kt)("p",null," You can find instructions about the Stride consumer chain launch and joining the mainnet ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/Stride-Labs/mainnet/tree/main/ics-instructions"},"here"),"."),(0,i.kt)("p",null," This ",(0,i.kt)("a",{parentName:"p",href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt"},"Excalidraw graphic")," explains the timeline of Stride's changeover procedure."),(0,i.kt)("h2",{id:"note"},"Note"),(0,i.kt)("p",null,"Stride re-uses an existing ",(0,i.kt)("inlineCode",{parentName:"p"},"transfer")," channel to send consumer rewards to the provider chain, in order to preserve existing transfer IBC denom between ",(0,i.kt)("inlineCode",{parentName:"p"},"stride-1")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"cosmoshub-4"),"."),(0,i.kt)("h2",{id:"resources"},"Resources"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://docs.stride.zone/docs"},"Stride docs")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt"},"Changeover procedure timeline")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/Stride-Labs/mainnet/tree/main/ics-instructions"},"Changeover upgrade docs"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/aede9d74.6d8e2449.js b/legacy/assets/js/aede9d74.6d8e2449.js new file mode 100644 index 0000000000..bf823bc3d3 --- /dev/null +++ b/legacy/assets/js/aede9d74.6d8e2449.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1087],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var i=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,i,r=function(e,t){if(null==e)return{};var n,i,r={},o=Object.keys(e);for(i=0;i<o.length;i++)n=o[i],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i<o.length;i++)n=o[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=i.createContext({}),d=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=d(e.components);return i.createElement(l.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},m=i.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),c=d(n),m=r,h=c["".concat(l,".").concat(m)]||c[m]||u[m]||o;return n?i.createElement(h,a(a({ref:t},p),{},{components:n})):i.createElement(h,a({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,a=new Array(o);a[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:r,a[1]=s;for(var d=2;d<o;d++)a[d]=n[d];return i.createElement.apply(null,a)}return i.createElement.apply(null,n)}m.displayName="MDXCreateElement"},2040:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var i=n(7462),r=(n(7294),n(3905));const o={sidebar_position:3},a="Interchain Security Parameters",s={unversionedId:"introduction/params",id:"version-v3.1.0/introduction/params",title:"Interchain Security Parameters",description:"The parameters necessary for Interchain Security (ICS) are defined in",source:"@site/versioned_docs/version-v3.1.0/introduction/params.md",sourceDirName:"introduction",slug:"/introduction/params",permalink:"/interchain-security/legacy/v3.1.0/introduction/params",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Terminology",permalink:"/interchain-security/legacy/v3.1.0/introduction/terminology"},next:{title:"Technical Specification",permalink:"/interchain-security/legacy/v3.1.0/introduction/technical-specification"}},l={},d=[{value:"Time-based parameters",id:"time-based-parameters",level:2},{value:"ProviderUnbondingPeriod",id:"providerunbondingperiod",level:3},{value:"ConsumerUnbondingPeriod",id:"consumerunbondingperiod",level:3},{value:"TrustingPeriodFraction",id:"trustingperiodfraction",level:3},{value:"CCVTimeoutPeriod",id:"ccvtimeoutperiod",level:3},{value:"InitTimeoutPeriod",id:"inittimeoutperiod",level:3},{value:"<code>VscTimeoutPeriod</code>",id:"vsctimeoutperiod",level:3},{value:"BlocksPerDistributionTransmission",id:"blocksperdistributiontransmission",level:3},{value:"TransferPeriodTimeout",id:"transferperiodtimeout",level:3},{value:"Slash Throttle Parameters",id:"slash-throttle-parameters",level:2},{value:"SlashMeterReplenishPeriod",id:"slashmeterreplenishperiod",level:3},{value:"SlashMeterReplenishFraction",id:"slashmeterreplenishfraction",level:3},{value:"MaxThrottledPackets",id:"maxthrottledpackets",level:3}],p={toc:d},c="wrapper";function u(e){let{components:t,...n}=e;return(0,r.kt)(c,(0,i.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"interchain-security-parameters"},"Interchain Security Parameters"),(0,r.kt)("p",null,"The parameters necessary for Interchain Security (ICS) are defined in "),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"the ",(0,r.kt)("inlineCode",{parentName:"li"},"Params")," structure in ",(0,r.kt)("inlineCode",{parentName:"li"},"proto/interchain_security/ccv/provider/v1/provider.proto")," for the provider;"),(0,r.kt)("li",{parentName:"ul"},"the ",(0,r.kt)("inlineCode",{parentName:"li"},"Params")," structure in ",(0,r.kt)("inlineCode",{parentName:"li"},"proto/interchain_security/ccv/consumer/v1/consumer.proto")," for the consumer.")),(0,r.kt)("h2",{id:"time-based-parameters"},"Time-based parameters"),(0,r.kt)("p",null,"ICS relies on the following time-based parameters."),(0,r.kt)("h3",{id:"providerunbondingperiod"},"ProviderUnbondingPeriod"),(0,r.kt)("p",null,"is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance."),(0,r.kt)("h3",{id:"consumerunbondingperiod"},"ConsumerUnbondingPeriod"),(0,r.kt)("p",null,"is the unbonding period on the consumer chain."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerUnbondingPeriod")," is set via the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," governance proposal to add a new consumer chain.\nIt is recommended that every consumer chain set and unbonding period shorter than ",(0,r.kt)("inlineCode",{parentName:"p"},"ProviderUnbondingPeriod")),(0,r.kt)("br",null),(0,r.kt)("p",{parentName:"admonition"},"Example:"),(0,r.kt)("pre",{parentName:"admonition"},(0,r.kt)("code",{parentName:"pre"},"ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day\n"))),(0,r.kt)("p",null,"Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer."),(0,r.kt)("h3",{id:"trustingperiodfraction"},"TrustingPeriodFraction"),(0,r.kt)("p",null,"is used to calculate the ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriod")," of created IBC clients on both provider and consumer chains. "),(0,r.kt)("p",null,"Setting ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriodFraction")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"0.5")," would result in the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"TrustingPeriodFraction = 0.5\nProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5\nConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5\n")),(0,r.kt)("p",null,"Note that a light clients must be updated within the ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriod")," in order to avoid being frozen."),(0,r.kt)("p",null,"For more details, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/client/ics-007-tendermint-client/README.md"},"IBC specification of Tendermint clients"),"."),(0,r.kt)("h3",{id:"ccvtimeoutperiod"},"CCVTimeoutPeriod"),(0,r.kt)("p",null,"is the period used to compute the timeout timestamp when sending IBC packets. "),(0,r.kt)("p",null,"For more details, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/core/ics-004-channel-and-packet-semantics/README.md#sending-packets"},"IBC specification of Channel & Packet Semantics"),"."),(0,r.kt)("admonition",{type:"warning"},(0,r.kt)("p",{parentName:"admonition"},"If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed.")),(0,r.kt)("p",null,"CCVTimeoutPeriod may have different values on the provider and consumer chains."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"CCVTimeoutPeriod")," on the provider ",(0,r.kt)("strong",{parentName:"li"},"must")," be larger than ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerUnbondingPeriod")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"CCVTimeoutPeriod")," on the consumer is initial set via the ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal"))),(0,r.kt)("h3",{id:"inittimeoutperiod"},"InitTimeoutPeriod"),(0,r.kt)("p",null,"is the maximum allowed duration for CCV channel initialization to execute."),(0,r.kt)("p",null,"For any consumer chain, if the CCV channel is not established within ",(0,r.kt)("inlineCode",{parentName:"p"},"InitTimeoutPeriod")," then the consumer chain will be removed and therefore will not be secured by the provider chain."),(0,r.kt)("p",null,"The countdown starts when the ",(0,r.kt)("inlineCode",{parentName:"p"},"spawn_time")," specified in the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," is reached."),(0,r.kt)("h3",{id:"vsctimeoutperiod"},(0,r.kt)("inlineCode",{parentName:"h3"},"VscTimeoutPeriod")),(0,r.kt)("p",null,"is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live.\nIf the ",(0,r.kt)("inlineCode",{parentName:"p"},"VscTimeoutPeriod")," is ever reached for a consumer chain that chain will be considered not live and removed from interchain security."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"VscTimeoutPeriod")," MUST be larger than the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerUnbondingPeriod"),".")),(0,r.kt)("h3",{id:"blocksperdistributiontransmission"},"BlocksPerDistributionTransmission"),(0,r.kt)("p",null,"is the number of blocks between rewards transfers from the consumer to the provider."),(0,r.kt)("h3",{id:"transferperiodtimeout"},"TransferPeriodTimeout"),(0,r.kt)("p",null,"is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider."),(0,r.kt)("p",null,"If this timeout expires, then the transfer is attempted again after ",(0,r.kt)("inlineCode",{parentName:"p"},"BlocksPerDistributionTransmission")," blocks."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"TransferPeriodTimeout")," on the consumer is initial set via the ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal")," gov proposal to add the consumer"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"TransferPeriodTimeout")," should be smaller than ",(0,r.kt)("inlineCode",{parentName:"li"},"BlocksPerDistributionTransmission x avg_block_time"))),(0,r.kt)("h2",{id:"slash-throttle-parameters"},"Slash Throttle Parameters"),(0,r.kt)("h3",{id:"slashmeterreplenishperiod"},"SlashMeterReplenishPeriod"),(0,r.kt)("p",null,"exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed."),(0,r.kt)("p",null,"The meter is replenished to an amount equal to the slash meter allowance for that block, or ",(0,r.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction * CurrentTotalVotingPower"),"."),(0,r.kt)("h3",{id:"slashmeterreplenishfraction"},"SlashMeterReplenishFraction"),(0,r.kt)("p",null,"exists on the provider as the portion (in range ","[0, 1]",") of total voting power that is replenished to the slash meter when a replenishment occurs."),(0,r.kt)("p",null,"This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a ",(0,r.kt)("inlineCode",{parentName:"p"},"sdk.Dec")," when used."),(0,r.kt)("h3",{id:"maxthrottledpackets"},"MaxThrottledPackets"),(0,r.kt)("p",null,"exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value."),(0,r.kt)("p",null,"This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/afe2e479.1b9ff36d.js b/legacy/assets/js/afe2e479.1b9ff36d.js new file mode 100644 index 0000000000..960698b5bd --- /dev/null +++ b/legacy/assets/js/afe2e479.1b9ff36d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6108],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),m=c(n),d=o,f=m["".concat(l,".").concat(d)]||m[d]||u[d]||i;return n?r.createElement(f,a(a({ref:t},p),{},{components:n})):r.createElement(f,a({ref:t},p))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[m]="string"==typeof e?e:o,a[1]=s;for(var c=2;c<i;c++)a[c]=n[c];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},9646:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var r=n(7462),o=(n(7294),n(3905));const i={sidebar_position:5,title:"Offboarding Checklist"},a="Consumer Offboarding",s={unversionedId:"consumer-development/offboarding",id:"version-v3.1.0/consumer-development/offboarding",title:"Offboarding Checklist",description:"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).",source:"@site/versioned_docs/version-v3.1.0/consumer-development/offboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/offboarding",permalink:"/interchain-security/legacy/v3.1.0/consumer-development/offboarding",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:5,frontMatter:{sidebar_position:5,title:"Offboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Onboarding Checklist",permalink:"/interchain-security/legacy/v3.1.0/consumer-development/onboarding"},next:{title:"Overview",permalink:"/interchain-security/legacy/v3.1.0/validators/overview"}},l={},c=[],p={toc:c},m="wrapper";function u(e){let{components:t,...n}=e;return(0,o.kt)(m,(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-offboarding"},"Consumer Offboarding"),(0,o.kt)("p",null,"To offboard a consumer chain simply submit a ",(0,o.kt)("inlineCode",{parentName:"p"},"ConsumerRemovalProposal")," governance proposal listing a ",(0,o.kt)("inlineCode",{parentName:"p"},"stop_time"),". After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates)."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.\n// If it passes, all the consumer chain\'s state is removed from the provider chain. The outstanding unbonding\n// operation funds are released.\n{\n // the title of the proposal\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n}\n')),(0,o.kt)("p",null,"More information will be listed in a future version of this document."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/b06966f1.7bb1f6c3.js b/legacy/assets/js/b06966f1.7bb1f6c3.js new file mode 100644 index 0000000000..42f044c270 --- /dev/null +++ b/legacy/assets/js/b06966f1.7bb1f6c3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5011],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>m});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=c(n),h=a,m=d["".concat(s,".").concat(h)]||d[h]||p[h]||o;return n?r.createElement(m,i(i({ref:t},u),{},{components:n})):r.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,i[1]=l;for(var c=2;c<o;c++)i[c]=n[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}h.displayName="MDXCreateElement"},9432:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const o={sidebar_position:2,title:"ADR Template"},i="ADR {ADR-NUMBER}:",l={unversionedId:"adrs/adr-template",id:"version-v3.3.0/adrs/adr-template",title:"ADR Template",description:"Changelog",source:"@site/versioned_docs/version-v3.3.0/adrs/adr-template.md",sourceDirName:"adrs",slug:"/adrs/adr-template",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-template",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"ADR Template"},sidebar:"tutorialSidebar",previous:{title:"ADR Template",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-prop"},next:{title:"Key Assignment",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-001-key-assignment"}},s={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],u={toc:c},d="wrapper";function p(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-adr-number-title"},"ADR {ADR-NUMBER}: {TITLE}"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"{date}: {changelog}")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},'A decision may be "proposed" if it hasn\'t been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement.')),(0,a.kt)("p",null,"{Deprecated|Proposed|Accepted}"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution. ")),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"This section explains all of the details of the proposed solution, including implementation details.\nIt should also describe affects / corollary items that may need to be changed as a part of this.\nIf the proposed change will be large, please also indicate a way to do the change to maximize ease of review.\n(e.g. the optimal split of things to do between separate PR's)")),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},'This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones.')),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"{reference link}")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/b1bce14b.e249808f.js b/legacy/assets/js/b1bce14b.e249808f.js new file mode 100644 index 0000000000..caa81440db --- /dev/null +++ b/legacy/assets/js/b1bce14b.e249808f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7762],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>h});var r=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function s(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?s(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):s(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function i(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},s=Object.keys(e);for(r=0;r<s.length;r++)t=s[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r<s.length;r++)t=s[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var d=r.createContext({}),l=function(e){var n=r.useContext(d),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=l(e.components);return r.createElement(d.Provider,{value:n},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,s=e.originalType,d=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),c=l(t),m=a,h=c["".concat(d,".").concat(m)]||c[m]||p[m]||s;return t?r.createElement(h,o(o({ref:n},u),{},{components:t})):r.createElement(h,o({ref:n},u))}));function h(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var s=t.length,o=new Array(s);o[0]=m;var i={};for(var d in n)hasOwnProperty.call(n,d)&&(i[d]=n[d]);i.originalType=e,i[c]="string"==typeof e?e:a,o[1]=i;for(var l=2;l<s;l++)o[l]=t[l];return r.createElement.apply(null,o)}return r.createElement.apply(null,t)}m.displayName="MDXCreateElement"},9428:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>p,frontMatter:()=>s,metadata:()=>i,toc:()=>l});var r=t(7462),a=(t(7294),t(3905));const s={sidebar_position:3,title:"Key Assignment"},o="ADR 001: Key Assignment",i={unversionedId:"adrs/adr-001-key-assignment",id:"version-v3.3.1-lsm/adrs/adr-001-key-assignment",title:"Key Assignment",description:"Changelog",source:"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-001-key-assignment.md",sourceDirName:"adrs",slug:"/adrs/adr-001-key-assignment",permalink:"/interchain-security/legacy/adrs/adr-001-key-assignment",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Key Assignment"},sidebar:"tutorialSidebar",previous:{title:"ADR Template",permalink:"/interchain-security/legacy/adrs/adr-template"},next:{title:"Jail Throttling",permalink:"/interchain-security/legacy/adrs/adr-002-throttle"}},d={},l=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"State required",id:"state-required",level:3},{value:"Protocol overview",id:"protocol-overview",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],u={toc:l},c="wrapper";function p(e){let{components:n,...t}=e;return(0,a.kt)(c,(0,r.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-001-key-assignment"},"ADR 001: Key Assignment"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"2022-12-01: Initial Draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"It is possible to change the keys at any time by submitting a transaction (i.e., ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey"),")."),(0,a.kt)("h3",{id:"state-required"},"State required"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorConsumerPubKey")," - Stores the validator assigned keys for every consumer chain.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorByConsumerAddr")," - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"KeyAssignmentReplacements")," - Stores the key assignments that need to be replaced in the current block. Needed to apply the key assignments received in a block to the validator updates sent to the consumer chains.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"KeyAssignmentReplacementsBytePrefix | len(chainID) | chainID | providerConsAddress -> abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower},\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ConsumerAddrsToPrune")," - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ",(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorByConsumerAddr"),". ")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses\n")),(0,a.kt)("h3",{id:"protocol-overview"},"Protocol overview"),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey(chainID, providerAddr, consumerKey)")," message:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"// get validator from staking module \nvalidator, found := stakingKeeper.GetValidator(providerAddr)\nif !found {\n return ErrNoValidatorFound\n}\nproviderConsAddr := validator.GetConsAddr()\n\n// make sure consumer key is not in use\nconsumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)\nif _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {\n return ErrInvalidConsumerConsensusPubKey\n}\n\n// check whether the consumer chain is already registered\n// i.e., a client to the consumer was already created\nif _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {\n // get the previous key assigned for this validator on this consumer chain\n oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)\n if found {\n // mark this old consumer key as prunable once the VSCMaturedPacket\n // for the current VSC ID is received\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n vscID := GetValidatorSetUpdateId()\n AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)\n } else {\n // the validator had no key assigned on this consumer chain\n oldConsumerKey := validator.TmConsPublicKey()\n }\n\n // check whether the validator is valid, i.e., its power is positive\n if currentPower := stakingKeeper.GetLastValidatorPower(providerAddr); currentPower > 0 {\n // to enable multiple calls of AssignConsumerKey in the same block by the same validator\n // the key assignment replacement should not be overwritten\n if _, found := GetKeyAssignmentReplacement(chainID, providerConsAddr); !found {\n // store old key and power for modifying the valset update in EndBlock\n oldKeyAssignment := abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower}\n SetKeyAssignmentReplacement(chainID, providerConsAddr, oldKeyAssignment)\n }\n }\n} else {\n // if the consumer chain is not registered, then remove the previous reverse mapping\n if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)\n }\n}\n\n\n// set the mapping from this validator's provider address to the new consumer key\nSetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)\n\n// set the reverse mapping: from this validator's new consensus address \n// on the consumer to its consensus address on the provider\nSetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)\n")),(0,a.kt)("p",null,"When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see ",(0,a.kt)("inlineCode",{parentName:"p"},"MakeConsumerGenesis"),"). "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {\n // ...\n // get initial valset from the staking module\n var updates []abci.ValidatorUpdate{}\n stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {\n validator := stakingKeeper.GetValidator(providerAddr)\n providerKey := validator.TmConsPublicKey()\n updates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})\n return false\n })\n\n // applies the key assignment to the initial validator\n for i, update := range updates {\n providerAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)\n if consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {\n updates[i].PubKey = consumerKey\n }\n }\n gen.InitialValSet = updates\n\n // get a hash of the consumer validator set from the update\n updatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)\n hash := tendermint.NewValidatorSet(updatesAsValSet).Hash()\n\n return gen, hash, nil\n}\n")),(0,a.kt)("p",null,"On ",(0,a.kt)("inlineCode",{parentName:"p"},"EndBlock")," while queueing ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCPacket"),"s to send to registered consumer chains:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func QueueVSCPackets() {\n valUpdateID := GetValidatorSetUpdateId()\n // get the validator updates from the staking module\n valUpdates := stakingKeeper.GetValidatorUpdates()\n\n IterateConsumerChains(func(chainID, clientID string) (stop bool) {\n // apply the key assignment to the validator updates\n valUpdates := ApplyKeyAssignmentToValUpdates(chainID, valUpdates)\n // ..\n })\n // ...\n}\n\nfunc ApplyKeyAssignmentToValUpdates(\n chainID string, \n valUpdates []abci.ValidatorUpdate,\n) (newUpdates []abci.ValidatorUpdate) {\n for _, valUpdate := range valUpdates {\n providerAddr := utils.TMCryptoPublicKeyToConsAddr(valUpdate.PubKey)\n\n // if a key assignment replacement is found, then\n // remove the valupdate with the old consumer key\n // and create two new valupdates\n prevConsumerKey, _, found := GetKeyAssignmentReplacement(chainID, providerAddr)\n if found {\n // set the old consumer key's power to 0\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: prevConsumerKey,\n Power: 0,\n })\n // set the new consumer key's power to the power in the update\n newConsumerKey := GetValidatorConsumerPubKey(chainID, providerAddr)\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: newConsumerKey,\n Power: valUpdate.Power,\n })\n // delete key assignment replacement\n DeleteKeyAssignmentReplacement(chainID, providerAddr)\n } else {\n // there is no key assignment replacement;\n // check if the validator's key is assigned\n consumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr)\n if found {\n // replace the update containing the provider key \n // with an update containing the consumer key\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: consumerKey,\n Power: valUpdate.Power,\n })\n } else {\n // keep the same update\n newUpdates = append(newUpdates, valUpdate)\n }\n }\n }\n\n // iterate over the remaining key assignment replacements\n IterateKeyAssignmentReplacements(chainID, func(\n pAddr sdk.ConsAddress,\n prevCKey tmprotocrypto.PublicKey,\n power int64,\n ) (stop bool) {\n // set the old consumer key's power to 0\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: prevCKey,\n Power: 0,\n })\n // set the new consumer key's power to the power in key assignment replacement\n newConsumerKey := GetValidatorConsumerPubKey(chainID, pAddr)\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: newConsumerKey,\n Power: power,\n })\n return false\n })\n\n // remove all the key assignment replacements\n \n return newUpdates\n}\n")),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"SlashPacket")," from a consumer chain with id ",(0,a.kt)("inlineCode",{parentName:"p"},"chainID")," for a infraction of a validator ",(0,a.kt)("inlineCode",{parentName:"p"},"data.Validator"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {\n // ...\n // the slash packet validator address may be known only on the consumer chain;\n // in this case, it must be mapped back to the consensus address on the provider chain\n consumerAddr := sdk.ConsAddress(data.Validator.Address)\n providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)\n if !found {\n // the validator has the same key on the consumer as on the provider\n providerAddr = consumer\n }\n // ...\n}\n")),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCMatured"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {\n // ...\n // prune previous consumer validator address that are no longer needed\n consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n for _, addr := range consumerAddrs {\n DeleteValidatorByConsumerAddr(chainID, addr)\n }\n DeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n // ...\n}\n")),(0,a.kt)("p",null,"On stopping a consumer chain:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {\n // ...\n // deletes all the state needed for key assignments on this consumer chain\n // ...\n}\n")),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Validators can use different consensus keys on the consumer chains.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"None")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"The consensus state necessary to create a client to the consumer chain must use the hash returned by the ",(0,a.kt)("inlineCode",{parentName:"li"},"MakeConsumerGenesis")," method as the ",(0,a.kt)("inlineCode",{parentName:"li"},"nextValsHash"),"."),(0,a.kt)("li",{parentName:"ul"},"The consumer chain can no longer check the initial validator set against the consensus state on ",(0,a.kt)("inlineCode",{parentName:"li"},"InitGenesis"),".")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/26"},"Key assignment issue"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/b1ce16c0.7130eb69.js b/legacy/assets/js/b1ce16c0.7130eb69.js new file mode 100644 index 0000000000..9a082c403f --- /dev/null +++ b/legacy/assets/js/b1ce16c0.7130eb69.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7652],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>m});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=c(n),h=a,m=d["".concat(s,".").concat(h)]||d[h]||p[h]||o;return n?r.createElement(m,i(i({ref:t},u),{},{components:n})):r.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,i[1]=l;for(var c=2;c<o;c++)i[c]=n[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}h.displayName="MDXCreateElement"},8110:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const o={sidebar_position:2,title:"ADR Template"},i="ADR {ADR-NUMBER}:",l={unversionedId:"adrs/adr-template",id:"version-v2.0.0/adrs/adr-template",title:"ADR Template",description:"Changelog",source:"@site/versioned_docs/version-v2.0.0/adrs/adr-template.md",sourceDirName:"adrs",slug:"/adrs/adr-template",permalink:"/interchain-security/legacy/v2.0.0/adrs/adr-template",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"ADR Template"},sidebar:"tutorialSidebar",previous:{title:"ADRs",permalink:"/interchain-security/legacy/v2.0.0/adrs/intro"},next:{title:"Key Assignment",permalink:"/interchain-security/legacy/v2.0.0/adrs/adr-001-key-assignment"}},s={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],u={toc:c},d="wrapper";function p(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-adr-number-title"},"ADR {ADR-NUMBER}: {TITLE}"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"{date}: {changelog}")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},'A decision may be "proposed" if it hasn\'t been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement.')),(0,a.kt)("p",null,"{Deprecated|Proposed|Accepted}"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution. ")),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"This section explains all of the details of the proposed solution, including implementation details.\nIt should also describe affects / corollary items that may need to be changed as a part of this.\nIf the proposed change will be large, please also indicate a way to do the change to maximize ease of review.\n(e.g. the optimal split of things to do between separate PR's)")),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},'This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones.')),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Are there any relevant PR comments, issues that led up to this, or articles referrenced for why we made the given design choice? If so link them here!")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"{reference link}")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/b2cefb99.aa9036e6.js b/legacy/assets/js/b2cefb99.aa9036e6.js new file mode 100644 index 0000000000..42bdb5ae9c --- /dev/null +++ b/legacy/assets/js/b2cefb99.aa9036e6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3943],{3905:(e,r,t)=>{t.d(r,{Zo:()=>d,kt:()=>f});var n=t(7294);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function o(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?i(Object(t),!0).forEach((function(r){a(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function c(e,r){if(null==e)return{};var t,n,a=function(e,r){if(null==e)return{};var t,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=n.createContext({}),u=function(e){var r=n.useContext(s),t=r;return e&&(t="function"==typeof e?e(r):o(o({},r),e)),t},d=function(e){var r=u(e.components);return n.createElement(s.Provider,{value:r},e.children)},l="mdxType",m={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},p=n.forwardRef((function(e,r){var t=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,d=c(e,["components","mdxType","originalType","parentName"]),l=u(t),p=a,f=l["".concat(s,".").concat(p)]||l[p]||m[p]||i;return t?n.createElement(f,o(o({ref:r},d),{},{components:t})):n.createElement(f,o({ref:r},d))}));function f(e,r){var t=arguments,a=r&&r.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=p;var c={};for(var s in r)hasOwnProperty.call(r,s)&&(c[s]=r[s]);c.originalType=e,c[l]="string"==typeof e?e:a,o[1]=c;for(var u=2;u<i;u++)o[u]=t[u];return n.createElement.apply(null,o)}return n.createElement.apply(null,t)}p.displayName="MDXCreateElement"},2307:(e,r,t)=>{t.d(r,{Z:()=>i});var n=t(7294);const a=function(e){return n.createElement("a",{href:e.href,className:"border shadow rounded-sm border-stone-200 dark:border-stone-800 dark:bg-neutral-900 hover:border-stone-300 hover:shadow-lg dark:hover:border-stone-200 transition-all duration-200 no-underline"},n.createElement("div",{className:"p-6"},n.createElement("h2",{className:""},e.header),n.createElement("p",{className:""},e.summary)))};const i=function(e){return n.createElement("div",{className:"card-section grid grid-cols-1 lg:grid-cols-2 gap-4 no-underline"},e.cards.map(((e,r)=>n.createElement(a,{key:r,href:e.href,header:e.header,summary:e.summary}))))}},8758:(e,r,t)=>{t.d(r,{Z:()=>n});const n=[{href:"/interchain-security/introduction/overview",header:"Basic concepts",summary:"Get started with the basic concepts and ideas."},{href:"/interchain-security/consumer-development/app-integration",header:"Start building",summary:"Click here to start building with Interchain security"},{href:"/interchain-security/features/key-assignment",header:"Feature: Key Assignment",summary:"Learn about the key assignment feature"},{href:"/interchain-security/features/reward-distribution",header:"Feature: Reward Distribution",summary:"Learn about consumer chain rewards distribution"},{href:"/interchain-security/consumer-development/onboarding",header:"Onboarding Checklist",summary:"Checklist to help you integrate Interchain Security, get support and onboard validators"},{href:"/interchain-security/faq",header:"FAQ",summary:"Frequently asked questions about the protocol and its implications"}]},3349:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>d,contentTitle:()=>s,default:()=>f,frontMatter:()=>c,metadata:()=>u,toc:()=>l});var n=t(7462),a=(t(7294),t(3905)),i=t(2307),o=t(8758);const c={sidebar_position:1},s="Interchain Security Docs",u={unversionedId:"index",id:"version-v3.3.1-lsm/index",title:"Interchain Security Docs",description:"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.",source:"@site/versioned_docs/version-v3.3.1-lsm/index.mdx",sourceDirName:".",slug:"/",permalink:"/interchain-security/legacy/",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",next:{title:"Overview",permalink:"/interchain-security/legacy/introduction/overview"}},d={},l=[],m={toc:l},p="wrapper";function f(e){let{components:r,...t}=e;return(0,a.kt)(p,(0,n.Z)({},m,t,{components:r,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"interchain-security-docs"},"Interchain Security Docs"),(0,a.kt)("p",null,"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains."),(0,a.kt)("p",null,"Here you can find information about replicated security, consumer chain development and instructions for validator onboarding."),(0,a.kt)(i.Z,{cards:o.Z,mdxType:"CardSection"}))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/b2effb50.acdda8b6.js b/legacy/assets/js/b2effb50.acdda8b6.js new file mode 100644 index 0000000000..19209d0d0f --- /dev/null +++ b/legacy/assets/js/b2effb50.acdda8b6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5626],{943:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"v3.2.0","label":"v3.2.0","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-v3.2.0","isLast":false,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Interchain Security Docs","href":"/interchain-security/legacy/v3.2.0/","docId":"index"},{"type":"category","label":"Introduction","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/legacy/v3.2.0/introduction/overview","docId":"introduction/overview"},{"type":"link","label":"Terminology","href":"/interchain-security/legacy/v3.2.0/introduction/terminology","docId":"introduction/terminology"},{"type":"link","label":"Interchain Security Parameters","href":"/interchain-security/legacy/v3.2.0/introduction/params","docId":"introduction/params"},{"type":"link","label":"Technical Specification","href":"/interchain-security/legacy/v3.2.0/introduction/technical-specification","docId":"introduction/technical-specification"}]},{"type":"category","label":"Features","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Key Assignment","href":"/interchain-security/legacy/v3.2.0/features/key-assignment","docId":"features/key-assignment"},{"type":"link","label":"Reward distribution","href":"/interchain-security/legacy/v3.2.0/features/reward-distribution","docId":"features/reward-distribution"},{"type":"link","label":"ICS Provider Proposals","href":"/interchain-security/legacy/v3.2.0/features/proposals","docId":"features/proposals"},{"type":"link","label":"Consumer Initiated Slashing","href":"/interchain-security/legacy/v3.2.0/features/slashing","docId":"features/slashing"}]},{"type":"category","label":"Consumer Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Developing an ICS consumer chain","href":"/interchain-security/legacy/v3.2.0/consumer-development/app-integration","docId":"consumer-development/app-integration"},{"type":"link","label":"Consumer Chain Governance","href":"/interchain-security/legacy/v3.2.0/consumer-development/consumer-chain-governance","docId":"consumer-development/consumer-chain-governance"},{"type":"link","label":"Onboarding Checklist","href":"/interchain-security/legacy/v3.2.0/consumer-development/onboarding","docId":"consumer-development/onboarding"},{"type":"link","label":"Offboarding Checklist","href":"/interchain-security/legacy/v3.2.0/consumer-development/offboarding","docId":"consumer-development/offboarding"},{"type":"link","label":"Changeover Procedure","href":"/interchain-security/legacy/v3.2.0/consumer-development/changeover-procedure","docId":"consumer-development/changeover-procedure"}]},{"type":"category","label":"Validators Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/legacy/v3.2.0/validators/overview","docId":"validators/overview"},{"type":"link","label":"Joining Replicated Security testnet","href":"/interchain-security/legacy/v3.2.0/validators/joining-testnet","docId":"validators/joining-testnet"},{"type":"link","label":"Withdrawing consumer chain validator rewards","href":"/interchain-security/legacy/v3.2.0/validators/withdraw_rewards","docId":"validators/withdraw_rewards"},{"type":"link","label":"Validator instructions for Changeover Procedure","href":"/interchain-security/legacy/v3.2.0/validators/changeover-procedure","docId":"validators/changeover-procedure"},{"type":"link","label":"Joining Neutron","href":"/interchain-security/legacy/v3.2.0/validators/joining-neutron","docId":"validators/joining-neutron"},{"type":"link","label":"Joining Stride","href":"/interchain-security/legacy/v3.2.0/validators/joining-stride","docId":"validators/joining-stride"}]},{"type":"link","label":"Frequently Asked Questions","href":"/interchain-security/legacy/v3.2.0/faq","docId":"frequently-asked-questions"},{"type":"category","label":"ADRs","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"ADRs","href":"/interchain-security/legacy/v3.2.0/adrs/intro","docId":"adrs/intro"},{"type":"link","label":"ADR Template","href":"/interchain-security/legacy/v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop","docId":"adrs/adr-007-pause-unbonding-on-eqv-prop"},{"type":"link","label":"ADR Template","href":"/interchain-security/legacy/v3.2.0/adrs/adr-template","docId":"adrs/adr-template"},{"type":"link","label":"Key Assignment","href":"/interchain-security/legacy/v3.2.0/adrs/adr-001-key-assignment","docId":"adrs/adr-001-key-assignment"},{"type":"link","label":"Jail Throttling","href":"/interchain-security/legacy/v3.2.0/adrs/adr-002-throttle","docId":"adrs/adr-002-throttle"},{"type":"link","label":"Equivocation governance proposal","href":"/interchain-security/legacy/v3.2.0/adrs/adr-003-equivocation-gov-proposal","docId":"adrs/adr-003-equivocation-gov-proposal"},{"type":"link","label":"Cryptographic verification of equivocation evidence","href":"/interchain-security/legacy/v3.2.0/adrs/adr-005-cryptographic-equivocation-verification","docId":"adrs/adr-005-cryptographic-equivocation-verification"},{"type":"link","label":"Throttle with retries","href":"/interchain-security/legacy/v3.2.0/adrs/adr-008-throttle-retries","docId":"adrs/adr-008-throttle-retries"},{"type":"link","label":"Soft Opt-Out","href":"/interchain-security/legacy/v3.2.0/adrs/adr-009-soft-opt-out","docId":"adrs/adr-009-soft-opt-out"},{"type":"link","label":"Standalone to Consumer Changeover","href":"/interchain-security/legacy/v3.2.0/adrs/adr-010-standalone-changeover","docId":"adrs/adr-010-standalone-changeover"},{"type":"link","label":"Improving testing and increasing confidence","href":"/interchain-security/legacy/v3.2.0/adrs/adr-011-improving-test-confidence","docId":"adrs/adr-011-improving-test-confidence"},{"type":"link","label":"Separate Releasing","href":"/interchain-security/legacy/v3.2.0/adrs/adr-012-separate-releasing","docId":"adrs/adr-012-separate-releasing"},{"type":"link","label":"Slashing on the provider for consumer equivocation","href":"/interchain-security/legacy/v3.2.0/adrs/adr-013-equivocation-slashing","docId":"adrs/adr-013-equivocation-slashing"}]}]},"docs":{"adrs/adr-001-key-assignment":{"id":"adrs/adr-001-key-assignment","title":"Key Assignment","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-002-throttle":{"id":"adrs/adr-002-throttle","title":"Jail Throttling","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-003-equivocation-gov-proposal":{"id":"adrs/adr-003-equivocation-gov-proposal","title":"Equivocation governance proposal","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-005-cryptographic-equivocation-verification":{"id":"adrs/adr-005-cryptographic-equivocation-verification","title":"Cryptographic verification of equivocation evidence","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-007-pause-unbonding-on-eqv-prop":{"id":"adrs/adr-007-pause-unbonding-on-eqv-prop","title":"ADR Template","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-008-throttle-retries":{"id":"adrs/adr-008-throttle-retries","title":"Throttle with retries","description":"ADR 008: Throttle with retries","sidebar":"tutorialSidebar"},"adrs/adr-009-soft-opt-out":{"id":"adrs/adr-009-soft-opt-out","title":"Soft Opt-Out","description":"ADR 009: Soft Opt-Out","sidebar":"tutorialSidebar"},"adrs/adr-010-standalone-changeover":{"id":"adrs/adr-010-standalone-changeover","title":"Standalone to Consumer Changeover","description":"ADR 010: Standalone to Consumer Changeover","sidebar":"tutorialSidebar"},"adrs/adr-011-improving-test-confidence":{"id":"adrs/adr-011-improving-test-confidence","title":"Improving testing and increasing confidence","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-012-separate-releasing":{"id":"adrs/adr-012-separate-releasing","title":"Separate Releasing","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-013-equivocation-slashing":{"id":"adrs/adr-013-equivocation-slashing","title":"Slashing on the provider for consumer equivocation","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-template":{"id":"adrs/adr-template","title":"ADR Template","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/intro":{"id":"adrs/intro","title":"ADRs","description":"This is a location to record all high-level architecture decisions in the Interchain Security project.","sidebar":"tutorialSidebar"},"consumer-development/app-integration":{"id":"consumer-development/app-integration","title":"Developing an ICS consumer chain","description":"When developing an ICS consumer chain, besides just focusing on your chain\'s logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.","sidebar":"tutorialSidebar"},"consumer-development/changeover-procedure":{"id":"consumer-development/changeover-procedure","title":"Changeover Procedure","description":"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.","sidebar":"tutorialSidebar"},"consumer-development/consumer-chain-governance":{"id":"consumer-development/consumer-chain-governance","title":"Consumer Chain Governance","description":"Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the \\"Whitelist\\" section below.","sidebar":"tutorialSidebar"},"consumer-development/offboarding":{"id":"consumer-development/offboarding","title":"Offboarding Checklist","description":"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).","sidebar":"tutorialSidebar"},"consumer-development/onboarding":{"id":"consumer-development/onboarding","title":"Onboarding Checklist","description":"The following checklists will aid in onboarding a new consumer chain to replicated security.","sidebar":"tutorialSidebar"},"features/key-assignment":{"id":"features/key-assignment","title":"Key Assignment","description":"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.","sidebar":"tutorialSidebar"},"features/proposals":{"id":"features/proposals","title":"ICS Provider Proposals","description":"Interchain security module introduces 3 new proposal types to the provider.","sidebar":"tutorialSidebar"},"features/reward-distribution":{"id":"features/reward-distribution","title":"Reward distribution","description":"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.","sidebar":"tutorialSidebar"},"features/slashing":{"id":"features/slashing","title":"Consumer Initiated Slashing","description":"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.","sidebar":"tutorialSidebar"},"frequently-asked-questions":{"id":"frequently-asked-questions","title":"Frequently Asked Questions","description":"What is the meaning of Validator Set Replication?","sidebar":"tutorialSidebar"},"index":{"id":"index","title":"Interchain Security Docs","description":"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.","sidebar":"tutorialSidebar"},"introduction/overview":{"id":"introduction/overview","title":"Overview","description":"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.","sidebar":"tutorialSidebar"},"introduction/params":{"id":"introduction/params","title":"Interchain Security Parameters","description":"The parameters necessary for Interchain Security (ICS) are defined in","sidebar":"tutorialSidebar"},"introduction/technical-specification":{"id":"introduction/technical-specification","title":"Technical Specification","description":"For a technical deep dive into the replicated security protocol, see the specification.","sidebar":"tutorialSidebar"},"introduction/terminology":{"id":"introduction/terminology","title":"Terminology","description":"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.","sidebar":"tutorialSidebar"},"validators/changeover-procedure":{"id":"validators/changeover-procedure","title":"Validator instructions for Changeover Procedure","description":"More details available in Changeover Procedure documentation.","sidebar":"tutorialSidebar"},"validators/joining-neutron":{"id":"validators/joining-neutron","title":"Joining Neutron","description":"Neutron is the first consumer chain to implement ICS.","sidebar":"tutorialSidebar"},"validators/joining-stride":{"id":"validators/joining-stride","title":"Joining Stride","description":"Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.","sidebar":"tutorialSidebar"},"validators/joining-testnet":{"id":"validators/joining-testnet","title":"Joining Replicated Security testnet","description":"Introduction","sidebar":"tutorialSidebar"},"validators/overview":{"id":"validators/overview","title":"Overview","description":"We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.","sidebar":"tutorialSidebar"},"validators/withdraw_rewards":{"id":"validators/withdraw_rewards","title":"Withdrawing consumer chain validator rewards","description":"Here are example steps for withdrawing rewards from consumer chains in the provider chain","sidebar":"tutorialSidebar"}}}')}}]); \ No newline at end of file diff --git a/legacy/assets/js/b4bb90a1.06f97b20.js b/legacy/assets/js/b4bb90a1.06f97b20.js new file mode 100644 index 0000000000..6047bb4d59 --- /dev/null +++ b/legacy/assets/js/b4bb90a1.06f97b20.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8990],{3905:(e,r,n)=>{n.d(r,{Zo:()=>p,kt:()=>f});var t=n(7294);function o(e,r,n){return r in e?Object.defineProperty(e,r,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[r]=n,e}function i(e,r){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);r&&(t=t.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),n.push.apply(n,t)}return n}function a(e){for(var r=1;r<arguments.length;r++){var n=null!=arguments[r]?arguments[r]:{};r%2?i(Object(n),!0).forEach((function(r){o(e,r,n[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(n,r))}))}return e}function c(e,r){if(null==e)return{};var n,t,o=function(e,r){if(null==e)return{};var n,t,o={},i=Object.keys(e);for(t=0;t<i.length;t++)n=i[t],r.indexOf(n)>=0||(o[n]=e[n]);return o}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(t=0;t<i.length;t++)n=i[t],r.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=t.createContext({}),s=function(e){var r=t.useContext(u),n=r;return e&&(n="function"==typeof e?e(r):a(a({},r),e)),n},p=function(e){var r=s(e.components);return t.createElement(u.Provider,{value:r},e.children)},l="mdxType",m={inlineCode:"code",wrapper:function(e){var r=e.children;return t.createElement(t.Fragment,{},r)}},d=t.forwardRef((function(e,r){var n=e.components,o=e.mdxType,i=e.originalType,u=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),l=s(n),d=o,f=l["".concat(u,".").concat(d)]||l[d]||m[d]||i;return n?t.createElement(f,a(a({ref:r},p),{},{components:n})):t.createElement(f,a({ref:r},p))}));function f(e,r){var n=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var c={};for(var u in r)hasOwnProperty.call(r,u)&&(c[u]=r[u]);c.originalType=e,c[l]="string"==typeof e?e:o,a[1]=c;for(var s=2;s<i;s++)a[s]=n[s];return t.createElement.apply(null,a)}return t.createElement.apply(null,n)}d.displayName="MDXCreateElement"},4599:(e,r,n)=>{n.r(r),n.d(r,{assets:()=>u,contentTitle:()=>a,default:()=>m,frontMatter:()=>i,metadata:()=>c,toc:()=>s});var t=n(7462),o=(n(7294),n(3905));const i={sidebar_position:3},a="Upgrading Consumer Chains",c={unversionedId:"consumer-development/consumer-chain-upgrade-procedure",id:"version-v3.1.0/consumer-development/consumer-chain-upgrade-procedure",title:"Upgrading Consumer Chains",description:"",source:"@site/versioned_docs/version-v3.1.0/consumer-development/consumer-chain-upgrade-procedure.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-chain-upgrade-procedure",permalink:"/interchain-security/legacy/v3.1.0/consumer-development/consumer-chain-upgrade-procedure",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Consumer Chain Governance",permalink:"/interchain-security/legacy/v3.1.0/consumer-development/consumer-chain-governance"},next:{title:"Onboarding Checklist",permalink:"/interchain-security/legacy/v3.1.0/consumer-development/onboarding"}},u={},s=[],p={toc:s},l="wrapper";function m(e){let{components:r,...n}=e;return(0,o.kt)(l,(0,t.Z)({},p,n,{components:r,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"upgrading-consumer-chains"},"Upgrading Consumer Chains"))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/b7347dde.cdacfbbc.js b/legacy/assets/js/b7347dde.cdacfbbc.js new file mode 100644 index 0000000000..22152ae055 --- /dev/null +++ b/legacy/assets/js/b7347dde.cdacfbbc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2784],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),c=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),m=a,h=u["".concat(l,".").concat(m)]||u[m]||d[m]||i;return n?o.createElement(h,r(r({ref:t},p),{},{components:n})):o.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,r=new Array(i);r[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,r[1]=s;for(var c=2;c<i;c++)r[c]=n[c];return o.createElement.apply(null,r)}return o.createElement.apply(null,n)}m.displayName="MDXCreateElement"},5456:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var o=n(7462),a=(n(7294),n(3905));const i={sidebar_position:4,title:"Equivocation governance proposal"},r="ADR 003: Equivocation governance proposal",s={unversionedId:"adrs/adr-003-equivocation-gov-proposal",id:"version-v3.3.1-lsm/adrs/adr-003-equivocation-gov-proposal",title:"Equivocation governance proposal",description:"Changelog",source:"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-003-equivocation-gov-proposal.md",sourceDirName:"adrs",slug:"/adrs/adr-003-equivocation-gov-proposal",permalink:"/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposal",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Equivocation governance proposal"},sidebar:"tutorialSidebar",previous:{title:"Jail Throttling",permalink:"/interchain-security/legacy/adrs/adr-002-throttle"},next:{title:"Cryptographic verification of equivocation evidence",permalink:"/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification"}},l={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],p={toc:c},u="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-003-equivocation-governance-proposal"},"ADR 003: Equivocation governance proposal"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"2023-02-06: Initial draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain."),(0,a.kt)("p",null,"For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain."),(0,a.kt)("p",null,"A new kind of governance proposal is added to the ",(0,a.kt)("inlineCode",{parentName:"p"},"provider")," module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain."),(0,a.kt)("p",null,"If such proposal passes, the proposal handler delegates to the ",(0,a.kt)("inlineCode",{parentName:"p"},"evidence")," module to process the equivocation. This module ensures the evidence isn\u2019t too old, or else ignores it (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/21021b837882d1d40f1d79bcbc4fad2e79a3fefe/x/evidence/keeper/infraction.go#L54-L62"},"code"),"). ",(0,a.kt)("em",{parentName:"p"},"Too old")," is determined by 2 consensus params : "),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"evidence.max_age_duration")," number of nanoseconds before an evidence is considered too old"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"evidence.max_age_numblocks")," number of blocks before an evidence is considered too old.")),(0,a.kt)("p",null,"On the hub, those parameters are equals to "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682\n(...)\n"evidence": {\n "max_age_num_blocks": "1000000",\n "max_age_duration": "172800000000000",\n (...)\n},\n(...)\n')),(0,a.kt)("p",null,"A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the ",(0,a.kt)("inlineCode",{parentName:"p"},"evidence")," module when the proposal passes and is handled by the hub."),(0,a.kt)("p",null,"For ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks=1M"),", the parameter is big enough if we consider the hub produces 12k blocks per day (",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_year/365 = 436,0000/365"),"). The evidence can be up to 83 days old (",(0,a.kt)("inlineCode",{parentName:"p"},"1,000,000/12,000"),") and not be ignored."),(0,a.kt)("p",null,"For ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_duration=172,800,000,000,000"),", the parameter is too low, because the value is in nanoseconds so it\u2019s 2 days. Fortunately the condition that checks those 2 parameters uses a ",(0,a.kt)("strong",{parentName:"p"},"AND"),", so if ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks")," condition passes, the evidence won\u2019t be ignored."),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Remove the possibility from a malicious consumer chain to \u201cattack\u201d the provider chain by slashing/jailing validators."),(0,a.kt)("li",{parentName:"ul"},"Provide a more acceptable implementation for the validator community.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Punishment action of double-signing isn\u2019t \u201cautomated\u201d, a governance proposal is required which takes more time."),(0,a.kt)("li",{parentName:"ul"},"You need to pay 250ATOM to submit an equivocation evidence.")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"PR that ignores non downtime slash packet : ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/692"},"https://github.com/cosmos/interchain-security/pull/692")),(0,a.kt)("li",{parentName:"ul"},"PR that adds the governance slash proposal: ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/703"},"https://github.com/cosmos/interchain-security/pull/703"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/b74a2173.0d9b82cf.js b/legacy/assets/js/b74a2173.0d9b82cf.js new file mode 100644 index 0000000000..87f3cb21d9 --- /dev/null +++ b/legacy/assets/js/b74a2173.0d9b82cf.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2845],{3905:(e,n,t)=>{t.d(n,{Zo:()=>d,kt:()=>m});var i=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?r(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):r(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,i,a=function(e,n){if(null==e)return{};var t,i,a={},r=Object.keys(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=i.createContext({}),c=function(e){var n=i.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},d=function(e){var n=c(e.components);return i.createElement(l.Provider,{value:n},e.children)},p="mdxType",h={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},u=i.forwardRef((function(e,n){var t=e.components,a=e.mdxType,r=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),p=c(t),u=a,m=p["".concat(l,".").concat(u)]||p[u]||h[u]||r;return t?i.createElement(m,o(o({ref:n},d),{},{components:t})):i.createElement(m,o({ref:n},d))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var r=t.length,o=new Array(r);o[0]=u;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[p]="string"==typeof e?e:a,o[1]=s;for(var c=2;c<r;c++)o[c]=t[c];return i.createElement.apply(null,o)}return i.createElement.apply(null,t)}u.displayName="MDXCreateElement"},2628:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>c});var i=t(7462),a=(t(7294),t(3905));const r={sidebar_position:1},o="Overview",s={unversionedId:"validators/overview",id:"version-v2.4.0-lsm/validators/overview",title:"Overview",description:"We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.",source:"@site/versioned_docs/version-v2.4.0-lsm/validators/overview.md",sourceDirName:"validators",slug:"/validators/overview",permalink:"/interchain-security/legacy/v2.4.0-lsm/validators/overview",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Offboarding Checklist",permalink:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/offboarding"},next:{title:"Joining Replicated Security testnet",permalink:"/interchain-security/legacy/v2.4.0-lsm/validators/joining-testnet"}},l={},c=[{value:"Startup sequence overview",id:"startup-sequence-overview",level:2},{value:"1. Consumer Chain init + 2. Genesis generation",id:"1-consumer-chain-init--2-genesis-generation",level:3},{value:"3. Submit Proposal",id:"3-submit-proposal",level:3},{value:"4. CCV Genesis state generation",id:"4-ccv-genesis-state-generation",level:3},{value:"5. Updating the genesis file",id:"5-updating-the-genesis-file",level:3},{value:"6. Chain start",id:"6-chain-start",level:3},{value:"7. Creating IBC connections",id:"7-creating-ibc-connections",level:3},{value:"Downtime Infractions",id:"downtime-infractions",level:2},{value:"Double-signing Infractions",id:"double-signing-infractions",level:2},{value:"Key assignment",id:"key-assignment",level:2},{value:"References:",id:"references",level:2}],d={toc:c},p="wrapper";function h(e){let{components:n,...r}=e;return(0,a.kt)(p,(0,i.Z)({},d,r,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"overview"},"Overview"),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"We advise that you join the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security"},"Replicated Security testnet")," to gain hands-on experience with running consumer chains.")),(0,a.kt)("p",null,"At present, replicated security requires all validators of the provider chain (ie. Cosmos Hub) to run validator nodes for all governance-approved consumer chains."),(0,a.kt)("p",null,"Once a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," passes, validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains."),(0,a.kt)("p",null,"Provider chain and consumer chains represent standalone chains that only share the validator set ie. the same validator operators are tasked with running all chains."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 175 validators for Cosmos Hub).")),(0,a.kt)("h2",{id:"startup-sequence-overview"},"Startup sequence overview"),(0,a.kt)("p",null,"Consumer chains cannot start and be secured by the validator set of the provider unless a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," is passed.\nEach proposal contains defines a ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider."),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"Validators are required to run consumer chain binaries only after ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," has passed.")),(0,a.kt)("p",null,"Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains."),(0,a.kt)("p",null,"The image below illustrates the startup sequence\n",(0,a.kt)("img",{alt:"startup",src:t(7728).Z,width:"942",height:"632"})),(0,a.kt)("h3",{id:"1-consumer-chain-init--2-genesis-generation"},"1. Consumer Chain init + 2. Genesis generation"),(0,a.kt)("p",null,"Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")),(0,a.kt)("h3",{id:"3-submit-proposal"},"3. Submit Proposal"),(0,a.kt)("p",null,"Consumer chain team (or their advocates) submits a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal"),".\nThe most important parameters for validators are:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"spawn_time")," - the time after which the consumer chain must be started"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"genesis_hash")," - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and ",(0,a.kt)("inlineCode",{parentName:"li"},"spawn_time")," is reached"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"binary_hash")," - hash of the consumer chain binary used to validate the software builds")),(0,a.kt)("h3",{id:"4-ccv-genesis-state-generation"},"4. CCV Genesis state generation"),(0,a.kt)("p",null,"After reaching ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json"),". The CCV validator set consists of the validator set on the provider at ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time"),"."),(0,a.kt)("p",null,"The state can be queried on the provider chain (in this case the Cosmos Hub):"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json\n")),(0,a.kt)("p",null,"This is used by the launch coordinator to create the final ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," that will be distributed to validators in step 5."),(0,a.kt)("h3",{id:"5-updating-the-genesis-file"},"5. Updating the genesis file"),(0,a.kt)("p",null,"Upon reaching the ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," the initial validator set state will become available on the provider chain. The initial validator set is included in the ",(0,a.kt)("strong",{parentName:"p"},"final genesis.json")," of the consumer chain."),(0,a.kt)("h3",{id:"6-chain-start"},"6. Chain start"),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences.")),(0,a.kt)("p",null,"The new ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," to start their consumer chain node."),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"Please pay attention to any onboarding repositories provided by the consumer chain teams.\nRecommendations are available in ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/onboarding"},"Consumer Onboarding Checklist"),".\nAnother comprehensive guide is available in the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md"},"Replicated Security testnet repo"),".")),(0,a.kt)("h3",{id:"7-creating-ibc-connections"},"7. Creating IBC connections"),(0,a.kt)("p",null,"Finally, to fully establish replicated security an IBC relayer is used to establish connections and create the required channels."),(0,a.kt)("admonition",{type:"warning"},(0,a.kt)("p",{parentName:"admonition"},"The relayer can establish the connection only after the consumer chain starts producing blocks.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> \nhermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1\nhermes start\n")),(0,a.kt)("h2",{id:"downtime-infractions"},"Downtime Infractions"),(0,a.kt)("p",null,"At present, the consumer chain can report evidence about downtime infractions to the provider chain. The ",(0,a.kt)("inlineCode",{parentName:"p"},"min_signed_per_window")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"signed_blocks_window")," can be different on each consumer chain and are subject to changes via consumer chain governance."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains."),(0,a.kt)("p",{parentName:"admonition"},"To unjail, the validator must wait for the jailing period to elapse on the provider chain and ",(0,a.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html#unjail-validator"},"submit an unjail transaction")," on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains."),(0,a.kt)("p",{parentName:"admonition"},"More information is available in ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.4.0-lsm/features/slashing#downtime-infractions"},"Downtime Slashing documentation"))),(0,a.kt)("h2",{id:"double-signing-infractions"},"Double-signing Infractions"),(0,a.kt)("p",null,"To learn more about equivocation handling in replicated security check out the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.4.0-lsm/features/slashing"},"Slashing")," documentation section."),(0,a.kt)("h2",{id:"key-assignment"},"Key assignment"),(0,a.kt)("p",null,"Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use."),(0,a.kt)("p",null,"For more information check our the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.4.0-lsm/features/key-assignment"},"Key assignment overview and guide")),(0,a.kt)("h2",{id:"references"},"References:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-faq.html"},"Cosmos Hub Validators FAQ")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-setup.html"},"Cosmos Hub Running a validator")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md#chain-launch"},"Startup Sequence")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-setup.html#unjail-validator"},"Submit Unjailing Transaction"))))}h.isMDXComponent=!0},7728:(e,n,t)=>{t.d(n,{Z:()=>i});const i=t.p+"assets/images/hypha-consumer-start-process-2141109f76c584706dd994d7965fd692.svg"}}]); \ No newline at end of file diff --git a/legacy/assets/js/b9eeacc5.e10e338f.js b/legacy/assets/js/b9eeacc5.e10e338f.js new file mode 100644 index 0000000000..e0d1b8ffdb --- /dev/null +++ b/legacy/assets/js/b9eeacc5.e10e338f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7567],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>h});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=s(r),m=a,h=u["".concat(c,".").concat(m)]||u[m]||d[m]||i;return r?n.createElement(h,o(o({ref:t},p),{},{components:r})):n.createElement(h,o({ref:t},p))}));function h(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=m;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var s=2;s<i;s++)o[s]=r[s];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},4961:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var n=r(7462),a=(r(7294),r(3905));const i={sidebar_position:1,title:"ADRs"},o="Architecture Decision Records (ADR)",l={unversionedId:"adrs/intro",id:"version-v2.0.0/adrs/intro",title:"ADRs",description:"This is a location to record all high-level architecture decisions in the Interchain Security project.",source:"@site/versioned_docs/version-v2.0.0/adrs/intro.md",sourceDirName:"adrs",slug:"/adrs/intro",permalink:"/interchain-security/legacy/v2.0.0/adrs/intro",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:1,frontMatter:{sidebar_position:1,title:"ADRs"},sidebar:"tutorialSidebar",previous:{title:"Frequently Asked Questions",permalink:"/interchain-security/legacy/v2.0.0/faq"},next:{title:"ADR Template",permalink:"/interchain-security/legacy/v2.0.0/adrs/adr-template"}},c={},s=[{value:"Table of Contents",id:"table-of-contents",level:2}],p={toc:s},u="wrapper";function d(e){let{components:t,...r}=e;return(0,a.kt)(u,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"architecture-decision-records-adr"},"Architecture Decision Records (ADR)"),(0,a.kt)("p",null,"This is a location to record all high-level architecture decisions in the Interchain Security project."),(0,a.kt)("p",null,"You can read more about the ADR concept in this ",(0,a.kt)("a",{parentName:"p",href:"https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0#.78xhdix6t"},"blog post"),"."),(0,a.kt)("p",null,"An ADR should provide:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Context on the relevant goals and the current state"),(0,a.kt)("li",{parentName:"ul"},"Proposed changes to achieve the goals"),(0,a.kt)("li",{parentName:"ul"},"Summary of pros and cons"),(0,a.kt)("li",{parentName:"ul"},"References"),(0,a.kt)("li",{parentName:"ul"},"Changelog")),(0,a.kt)("p",null,"Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and\njustification for a change in architecture, or for the architecture of something\nnew. The spec is much more compressed and streamlined summary of everything as\nit is or should be."),(0,a.kt)("p",null,"If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match."),(0,a.kt)("p",null,"Note the context/background should be written in the present tense."),(0,a.kt)("p",null,"To suggest an ADR, please make use of the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.0.0/adrs/adr-template"},"ADR template")," provided."),(0,a.kt)("h2",{id:"table-of-contents"},"Table of Contents"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"ADR ","#"),(0,a.kt)("th",{parentName:"tr",align:null},"Description"),(0,a.kt)("th",{parentName:"tr",align:null},"Status"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v2.0.0/adrs/adr-001-key-assignment"},"001")),(0,a.kt)("td",{parentName:"tr",align:null},"Consumer chain key assignment"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v2.0.0/adrs/adr-002-throttle"},"002")),(0,a.kt)("td",{parentName:"tr",align:null},"Jail Throttling"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v2.0.0/adrs/adr-003-equivocation-gov-proposal"},"003")),(0,a.kt)("td",{parentName:"tr",align:null},"Equivocation governance proposal"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/bb11f0e8.aa98b53c.js b/legacy/assets/js/bb11f0e8.aa98b53c.js new file mode 100644 index 0000000000..062a6e3496 --- /dev/null +++ b/legacy/assets/js/bb11f0e8.aa98b53c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2293],{3905:(e,r,t)=>{t.d(r,{Zo:()=>c,kt:()=>w});var n=t(7294);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function o(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?i(Object(t),!0).forEach((function(r){a(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function s(e,r){if(null==e)return{};var t,n,a=function(e,r){if(null==e)return{};var t,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=n.createContext({}),d=function(e){var r=n.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):o(o({},r),e)),t},c=function(e){var r=d(e.components);return n.createElement(l.Provider,{value:r},e.children)},m="mdxType",p={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},u=n.forwardRef((function(e,r){var t=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),m=d(t),u=a,w=m["".concat(l,".").concat(u)]||m[u]||p[u]||i;return t?n.createElement(w,o(o({ref:r},c),{},{components:t})):n.createElement(w,o({ref:r},c))}));function w(e,r){var t=arguments,a=r&&r.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=u;var s={};for(var l in r)hasOwnProperty.call(r,l)&&(s[l]=r[l]);s.originalType=e,s[m]="string"==typeof e?e:a,o[1]=s;for(var d=2;d<i;d++)o[d]=t[d];return n.createElement.apply(null,o)}return n.createElement.apply(null,t)}u.displayName="MDXCreateElement"},6431:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>d});var n=t(7462),a=(t(7294),t(3905));const i={},o="Withdrawing consumer chain validator rewards",s={unversionedId:"validators/withdraw_rewards",id:"version-v3.1.0/validators/withdraw_rewards",title:"Withdrawing consumer chain validator rewards",description:"Here are example steps for withdrawing rewards from consumer chains in the provider chain",source:"@site/versioned_docs/version-v3.1.0/validators/withdraw_rewards.md",sourceDirName:"validators",slug:"/validators/withdraw_rewards",permalink:"/interchain-security/legacy/v3.1.0/validators/withdraw_rewards",draft:!1,tags:[],version:"v3.1.0",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Joining Replicated Security testnet",permalink:"/interchain-security/legacy/v3.1.0/validators/joining-testnet"},next:{title:"Frequently Asked Questions",permalink:"/interchain-security/legacy/v3.1.0/faq"}},l={},d=[{value:"Querying validator rewards",id:"querying-validator-rewards",level:2},{value:"Withdrawing rewards and commission",id:"withdrawing-rewards-and-commission",level:2},{value:"1. Withdraw rewards",id:"1-withdraw-rewards",level:3},{value:"2. Confirm withdrawal",id:"2-confirm-withdrawal",level:3}],c={toc:d},m="wrapper";function p(e){let{components:r,...t}=e;return(0,a.kt)(m,(0,n.Z)({},c,t,{components:r,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"withdrawing-consumer-chain-validator-rewards"},"Withdrawing consumer chain validator rewards"),(0,a.kt)("p",null,"Here are example steps for withdrawing rewards from consumer chains in the provider chain"),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The examples used are from ",(0,a.kt)("inlineCode",{parentName:"p"},"rs-testnet"),", the replicated security persistent testnet."),(0,a.kt)("p",{parentName:"admonition"},"Validator operator address: ",(0,a.kt)("inlineCode",{parentName:"p"},"cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6"),"\nSelf-delegation address: ",(0,a.kt)("inlineCode",{parentName:"p"},"cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf"))),(0,a.kt)("p",null,"Prior to withdrawing rewards, query balances for self-delegation address:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "1000000000000"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n')),(0,a.kt)("h2",{id:"querying-validator-rewards"},"Querying validator rewards"),(0,a.kt)("p",null,"Query rewards for the validator address:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6\n\nrewards:\n- amount: "158.069895000000000000"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "841842390516.072526500000000000"\n denom: uatom\n')),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD")," denom represents rewards from a consumer chain."),(0,a.kt)("h2",{id:"withdrawing-rewards-and-commission"},"Withdrawing rewards and commission"),(0,a.kt)("h3",{id:"1-withdraw-rewards"},"1. Withdraw rewards"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y\n\ntxhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A\n")),(0,a.kt)("h3",{id:"2-confirm-withdrawal"},"2. Confirm withdrawal"),(0,a.kt)("p",null,"After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "216"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "2233766225342"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n')))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/bb7b1385.f09fc6a6.js b/legacy/assets/js/bb7b1385.f09fc6a6.js new file mode 100644 index 0000000000..f9912e52ae --- /dev/null +++ b/legacy/assets/js/bb7b1385.f09fc6a6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8186],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>h});var r=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function s(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?s(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):s(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function i(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},s=Object.keys(e);for(r=0;r<s.length;r++)t=s[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r<s.length;r++)t=s[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var d=r.createContext({}),l=function(e){var n=r.useContext(d),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=l(e.components);return r.createElement(d.Provider,{value:n},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,s=e.originalType,d=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),c=l(t),m=a,h=c["".concat(d,".").concat(m)]||c[m]||p[m]||s;return t?r.createElement(h,o(o({ref:n},u),{},{components:t})):r.createElement(h,o({ref:n},u))}));function h(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var s=t.length,o=new Array(s);o[0]=m;var i={};for(var d in n)hasOwnProperty.call(n,d)&&(i[d]=n[d]);i.originalType=e,i[c]="string"==typeof e?e:a,o[1]=i;for(var l=2;l<s;l++)o[l]=t[l];return r.createElement.apply(null,o)}return r.createElement.apply(null,t)}m.displayName="MDXCreateElement"},7449:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>p,frontMatter:()=>s,metadata:()=>i,toc:()=>l});var r=t(7462),a=(t(7294),t(3905));const s={sidebar_position:3,title:"Key Assignment"},o="ADR 001: Key Assignment",i={unversionedId:"adrs/adr-001-key-assignment",id:"version-v3.2.0/adrs/adr-001-key-assignment",title:"Key Assignment",description:"Changelog",source:"@site/versioned_docs/version-v3.2.0/adrs/adr-001-key-assignment.md",sourceDirName:"adrs",slug:"/adrs/adr-001-key-assignment",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-001-key-assignment",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Key Assignment"},sidebar:"tutorialSidebar",previous:{title:"ADR Template",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-template"},next:{title:"Jail Throttling",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-002-throttle"}},d={},l=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"State required",id:"state-required",level:3},{value:"Protocol overview",id:"protocol-overview",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],u={toc:l},c="wrapper";function p(e){let{components:n,...t}=e;return(0,a.kt)(c,(0,r.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-001-key-assignment"},"ADR 001: Key Assignment"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"2022-12-01: Initial Draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"It is possible to change the keys at any time by submitting a transaction (i.e., ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey"),")."),(0,a.kt)("h3",{id:"state-required"},"State required"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorConsumerPubKey")," - Stores the validator assigned keys for every consumer chain.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorByConsumerAddr")," - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"KeyAssignmentReplacements")," - Stores the key assignments that need to be replaced in the current block. Needed to apply the key assignments received in a block to the validator updates sent to the consumer chains.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"KeyAssignmentReplacementsBytePrefix | len(chainID) | chainID | providerConsAddress -> abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower},\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ConsumerAddrsToPrune")," - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ",(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorByConsumerAddr"),". ")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses\n")),(0,a.kt)("h3",{id:"protocol-overview"},"Protocol overview"),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey(chainID, providerAddr, consumerKey)")," message:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"// get validator from staking module \nvalidator, found := stakingKeeper.GetValidator(providerAddr)\nif !found {\n return ErrNoValidatorFound\n}\nproviderConsAddr := validator.GetConsAddr()\n\n// make sure consumer key is not in use\nconsumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)\nif _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {\n return ErrInvalidConsumerConsensusPubKey\n}\n\n// check whether the consumer chain is already registered\n// i.e., a client to the consumer was already created\nif _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {\n // get the previous key assigned for this validator on this consumer chain\n oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)\n if found {\n // mark this old consumer key as prunable once the VSCMaturedPacket\n // for the current VSC ID is received\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n vscID := GetValidatorSetUpdateId()\n AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)\n } else {\n // the validator had no key assigned on this consumer chain\n oldConsumerKey := validator.TmConsPublicKey()\n }\n\n // check whether the validator is valid, i.e., its power is positive\n if currentPower := stakingKeeper.GetLastValidatorPower(providerAddr); currentPower > 0 {\n // to enable multiple calls of AssignConsumerKey in the same block by the same validator\n // the key assignment replacement should not be overwritten\n if _, found := GetKeyAssignmentReplacement(chainID, providerConsAddr); !found {\n // store old key and power for modifying the valset update in EndBlock\n oldKeyAssignment := abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower}\n SetKeyAssignmentReplacement(chainID, providerConsAddr, oldKeyAssignment)\n }\n }\n} else {\n // if the consumer chain is not registered, then remove the previous reverse mapping\n if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)\n }\n}\n\n\n// set the mapping from this validator's provider address to the new consumer key\nSetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)\n\n// set the reverse mapping: from this validator's new consensus address \n// on the consumer to its consensus address on the provider\nSetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)\n")),(0,a.kt)("p",null,"When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see ",(0,a.kt)("inlineCode",{parentName:"p"},"MakeConsumerGenesis"),"). "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {\n // ...\n // get initial valset from the staking module\n var updates []abci.ValidatorUpdate{}\n stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {\n validator := stakingKeeper.GetValidator(providerAddr)\n providerKey := validator.TmConsPublicKey()\n updates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})\n return false\n })\n\n // applies the key assignment to the initial validator\n for i, update := range updates {\n providerAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)\n if consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {\n updates[i].PubKey = consumerKey\n }\n }\n gen.InitialValSet = updates\n\n // get a hash of the consumer validator set from the update\n updatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)\n hash := tendermint.NewValidatorSet(updatesAsValSet).Hash()\n\n return gen, hash, nil\n}\n")),(0,a.kt)("p",null,"On ",(0,a.kt)("inlineCode",{parentName:"p"},"EndBlock")," while queueing ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCPacket"),"s to send to registered consumer chains:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func QueueVSCPackets() {\n valUpdateID := GetValidatorSetUpdateId()\n // get the validator updates from the staking module\n valUpdates := stakingKeeper.GetValidatorUpdates()\n\n IterateConsumerChains(func(chainID, clientID string) (stop bool) {\n // apply the key assignment to the validator updates\n valUpdates := ApplyKeyAssignmentToValUpdates(chainID, valUpdates)\n // ..\n })\n // ...\n}\n\nfunc ApplyKeyAssignmentToValUpdates(\n chainID string, \n valUpdates []abci.ValidatorUpdate,\n) (newUpdates []abci.ValidatorUpdate) {\n for _, valUpdate := range valUpdates {\n providerAddr := utils.TMCryptoPublicKeyToConsAddr(valUpdate.PubKey)\n\n // if a key assignment replacement is found, then\n // remove the valupdate with the old consumer key\n // and create two new valupdates\n prevConsumerKey, _, found := GetKeyAssignmentReplacement(chainID, providerAddr)\n if found {\n // set the old consumer key's power to 0\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: prevConsumerKey,\n Power: 0,\n })\n // set the new consumer key's power to the power in the update\n newConsumerKey := GetValidatorConsumerPubKey(chainID, providerAddr)\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: newConsumerKey,\n Power: valUpdate.Power,\n })\n // delete key assignment replacement\n DeleteKeyAssignmentReplacement(chainID, providerAddr)\n } else {\n // there is no key assignment replacement;\n // check if the validator's key is assigned\n consumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr)\n if found {\n // replace the update containing the provider key \n // with an update containing the consumer key\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: consumerKey,\n Power: valUpdate.Power,\n })\n } else {\n // keep the same update\n newUpdates = append(newUpdates, valUpdate)\n }\n }\n }\n\n // iterate over the remaining key assignment replacements\n IterateKeyAssignmentReplacements(chainID, func(\n pAddr sdk.ConsAddress,\n prevCKey tmprotocrypto.PublicKey,\n power int64,\n ) (stop bool) {\n // set the old consumer key's power to 0\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: prevCKey,\n Power: 0,\n })\n // set the new consumer key's power to the power in key assignment replacement\n newConsumerKey := GetValidatorConsumerPubKey(chainID, pAddr)\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: newConsumerKey,\n Power: power,\n })\n return false\n })\n\n // remove all the key assignment replacements\n \n return newUpdates\n}\n")),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"SlashPacket")," from a consumer chain with id ",(0,a.kt)("inlineCode",{parentName:"p"},"chainID")," for a infraction of a validator ",(0,a.kt)("inlineCode",{parentName:"p"},"data.Validator"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {\n // ...\n // the slash packet validator address may be known only on the consumer chain;\n // in this case, it must be mapped back to the consensus address on the provider chain\n consumerAddr := sdk.ConsAddress(data.Validator.Address)\n providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)\n if !found {\n // the validator has the same key on the consumer as on the provider\n providerAddr = consumer\n }\n // ...\n}\n")),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCMatured"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {\n // ...\n // prune previous consumer validator address that are no longer needed\n consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n for _, addr := range consumerAddrs {\n DeleteValidatorByConsumerAddr(chainID, addr)\n }\n DeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n // ...\n}\n")),(0,a.kt)("p",null,"On stopping a consumer chain:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {\n // ...\n // deletes all the state needed for key assignments on this consumer chain\n // ...\n}\n")),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Validators can use different consensus keys on the consumer chains.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"None")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"The consensus state necessary to create a client to the consumer chain must use the hash returned by the ",(0,a.kt)("inlineCode",{parentName:"li"},"MakeConsumerGenesis")," method as the ",(0,a.kt)("inlineCode",{parentName:"li"},"nextValsHash"),"."),(0,a.kt)("li",{parentName:"ul"},"The consumer chain can no longer check the initial validator set against the consensus state on ",(0,a.kt)("inlineCode",{parentName:"li"},"InitGenesis"),".")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/26"},"Key assignment issue"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/bbea31d2.bd6600ce.js b/legacy/assets/js/bbea31d2.bd6600ce.js new file mode 100644 index 0000000000..227dbb3eb7 --- /dev/null +++ b/legacy/assets/js/bbea31d2.bd6600ce.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[109],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>m});var i=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,i)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?r(Object(a),!0).forEach((function(t){n(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):r(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function l(e,t){if(null==e)return{};var a,i,n=function(e,t){if(null==e)return{};var a,i,n={},r=Object.keys(e);for(i=0;i<r.length;i++)a=r[i],t.indexOf(a)>=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)a=r[i],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var s=i.createContext({}),h=function(e){var t=i.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},d=function(e){var t=h(e.components);return i.createElement(s.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},u=i.forwardRef((function(e,t){var a=e.components,n=e.mdxType,r=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=h(a),u=n,m=c["".concat(s,".").concat(u)]||c[u]||p[u]||r;return a?i.createElement(m,o(o({ref:t},d),{},{components:a})):i.createElement(m,o({ref:t},d))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=a.length,o=new Array(r);o[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:n,o[1]=l;for(var h=2;h<r;h++)o[h]=a[h];return i.createElement.apply(null,o)}return i.createElement.apply(null,a)}u.displayName="MDXCreateElement"},1382:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>p,frontMatter:()=>r,metadata:()=>l,toc:()=>h});var i=a(7462),n=(a(7294),a(3905));const r={sidebar_position:3,title:"Jail Throttling"},o="ADR 002: Jail Throttling",l={unversionedId:"adrs/adr-002-throttle",id:"adrs/adr-002-throttle",title:"Jail Throttling",description:"Changelog",source:"@site/docs/adrs/adr-002-throttle.md",sourceDirName:"adrs",slug:"/adrs/adr-002-throttle",permalink:"/interchain-security/legacy/adrs/adr-002-throttle",draft:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Jail Throttling"},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/legacy/adrs/adr-001-key-assignment"},next:{title:"Equivocation governance proposal",permalink:"/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposal"}},s={},h=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"State Required - Slash Meter",id:"state-required---slash-meter",level:3},{value:"State Required - Global entry queue",id:"state-required---global-entry-queue",level:3},{value:"State Required - Per-chain data queue",id:"state-required---per-chain-data-queue",level:3},{value:"Reasoning - Multiple queues",id:"reasoning---multiple-queues",level:3},{value:"Protocol Overview - OnRecvSlashPacket",id:"protocol-overview---onrecvslashpacket",level:3},{value:"Protocol Overview - OnRecvVSCMaturedPacket",id:"protocol-overview---onrecvvscmaturedpacket",level:3},{value:"Endblocker Step 1 - Slash Meter Replenishment",id:"endblocker-step-1---slash-meter-replenishment",level:3},{value:"Endblocker Step 2 - HandleLeadingVSCMaturedPackets",id:"endblocker-step-2---handleleadingvscmaturedpackets",level:3},{value:"Endblocker Step 3 - HandleThrottleQueues",id:"endblocker-step-3---handlethrottlequeues",level:3},{value:"System Properties",id:"system-properties",level:3},{value:"Main Throttling Property",id:"main-throttling-property",level:3},{value:"How Unjailing Affects the Main Throttling Property",id:"how-unjailing-affects-the-main-throttling-property",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],d={toc:h},c="wrapper";function p(e){let{components:t,...a}=e;return(0,n.kt)(c,(0,i.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"adr-002-jail-throttling"},"ADR 002: Jail Throttling"),(0,n.kt)("h2",{id:"changelog"},"Changelog"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"2023-01-26: Initial Draft"),(0,n.kt)("li",{parentName:"ul"},"2023-02-07: Property refined, ADR ready to review/merge")),(0,n.kt)("h2",{id:"status"},"Status"),(0,n.kt)("p",null,"Accepted"),(0,n.kt)("h2",{id:"context"},"Context"),(0,n.kt)("p",null,"The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols. In practice, this assumption may not hold. A malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider."),(0,n.kt)("p",null,"Before the throttling feature was implemented, the following attack was possible. Attacker(s) would create provider validators just below the provider's active set. Using a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once. Control of the provider would then pass over to the attackers' validators. This enables the attacker(s) to halt the provider. Or even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC."),(0,n.kt)("h2",{id:"decision"},"Decision"),(0,n.kt)("p",null,"The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack. Ie. this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time."),(0,n.kt)("h3",{id:"state-required---slash-meter"},"State Required - Slash Meter"),(0,n.kt)("p",null,"There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time. This meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params."),(0,n.kt)("h3",{id:"state-required---global-entry-queue"},"State Required - Global entry queue"),(0,n.kt)("p",null,'There exists a single queue which stores "global slash entries". These entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering. This queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.'),(0,n.kt)("h3",{id:"state-required---per-chain-data-queue"},"State Required - Per-chain data queue"),(0,n.kt)("p",null,'For each established consumer, there exists a queue which stores "throttled packet data". Ie. pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering. Order is enforced by IBC sequence number. These "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.'),(0,n.kt)("h3",{id:"reasoning---multiple-queues"},"Reasoning - Multiple queues"),(0,n.kt)("p",null,"For reasoning on why this feature was implemented with multiple queues, see ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"spec"),". Specifically the section on ",(0,n.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order"),". There are other ways to ensure such a property (like a queue of linked lists, etc.), but the implemented protocol seemed to be the most understandable and easiest to implement with a KV store."),(0,n.kt)("h3",{id:"protocol-overview---onrecvslashpacket"},"Protocol Overview - OnRecvSlashPacket"),(0,n.kt)("p",null,"Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"A global slash entry is queued."),(0,n.kt)("li",{parentName:"ol"},"The data of such a packet is added to the per-chain queue.")),(0,n.kt)("h3",{id:"protocol-overview---onrecvvscmaturedpacket"},"Protocol Overview - OnRecvVSCMaturedPacket"),(0,n.kt)("p",null,"Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue."),(0,n.kt)("h3",{id:"endblocker-step-1---slash-meter-replenishment"},"Endblocker Step 1 - Slash Meter Replenishment"),(0,n.kt)("p",null,"Once the slash meter becomes not full, it'll be replenished after ",(0,n.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishPeriod (param)")," by incrementing the meter with its allowance for the replenishment block, where ",(0,n.kt)("inlineCode",{parentName:"p"},"allowance")," = ",(0,n.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction (param)")," * ",(0,n.kt)("inlineCode",{parentName:"p"},"currentTotalVotingPower"),". The slash meter will never exceed its current allowance (fn of the total voting power for the block) in value. Note a few things:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power. In such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods."),(0,n.kt)("li",{parentName:"ol"},"Total voting power of a chain changes over time, especially as validators are jailed. As validators are jailed, total voting power decreases, and so does the jailing allowance. See below for more detailed throttling property discussion."),(0,n.kt)("li",{parentName:"ol"},"The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1. If the ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction (param)")," is set too low, integer rounding will put this minimum value into effect. That is, if ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," * ",(0,n.kt)("inlineCode",{parentName:"li"},"currentTotalVotingPower")," < 1, then the effective allowance would be 1. This min value of allowance ensures that there's some packets handled over time, even if that is a very long time. It's a crude solution to an edge case caused by too small of a replenishment fraction.")),(0,n.kt)("p",null,"The behavior described above is achieved by executing ",(0,n.kt)("inlineCode",{parentName:"p"},"CheckForSlashMeterReplenishment()")," every endblock, BEFORE ",(0,n.kt)("inlineCode",{parentName:"p"},"HandleThrottleQueues()")," is executed."),(0,n.kt)("h3",{id:"endblocker-step-2---handleleadingvscmaturedpackets"},"Endblocker Step 2 - HandleLeadingVSCMaturedPackets"),(0,n.kt)("p",null,'Every block it is possible that VSCMatured packet data was queued before any slash packet data. Since this "leading" VSCMatured packet data does not have to be throttled (see ',(0,n.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order"),"), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes."),(0,n.kt)("h3",{id:"endblocker-step-3---handlethrottlequeues"},"Endblocker Step 3 - HandleThrottleQueues"),(0,n.kt)("p",null,"Every endblocker the following pseudo-code is executed to handle data from the throttle queues."),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-typescript"},"meter := getSlashMeter()\n\n// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist \nwhile meter.IsPositiveOrZero() && entriesExist() {\n // Get next entry in queue\n entry := getNextGlobalSlashEntry()\n // Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet\n valPower := entry.getValPower()\n meter = meter - valPower\n // Using the per-chain queue, handle the single slash packet using its queued data,\n // then handle all trailing VSCMatured packets for this consumer\n handleSlashPacketAndTrailingVSCMaturedPackets(entry)\n // Delete entry in global queue, delete handled data\n entry.Delete()\n deleteThrottledSlashPacketData()\n deleteTrailingVSCMaturedPacketData()\n}\n")),(0,n.kt)("h3",{id:"system-properties"},"System Properties"),(0,n.kt)("p",null,"All CCV system properties should be maintained by implementing this feature, see: ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"CCV spec - Consumer Initiated Slashing"),"."),(0,n.kt)("p",null,"One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than ",(0,n.kt)("inlineCode",{parentName:"p"},"MaxThrottledPackets (param)"),", then the provider binary will panic, and the provider chain will halt. Therefore this param should be set carefully. See ",(0,n.kt)("inlineCode",{parentName:"p"},"SetThrottledPacketDataSize"),". This behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators."),(0,n.kt)("h3",{id:"main-throttling-property"},"Main Throttling Property"),(0,n.kt)("p",null,"Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions."),(0,n.kt)("p",null,"First, we define the following:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},'A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.'),(0,n.kt)("li",{parentName:"ul"},'The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.'),(0,n.kt)("li",{parentName:"ul"},"There is a list of honest validators s.t if they are jailed, ",(0,n.kt)("inlineCode",{parentName:"li"},"X"),"% of the initial validator set will be jailed.")),(0,n.kt)("p",null,"For the following property to hold, these assumptions must be true:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack."),(0,n.kt)("li",{parentName:"ol"},"No validator has more than ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," of total voting power on the provider."),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," is large enough that ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," * ",(0,n.kt)("inlineCode",{parentName:"li"},"currentTotalVotingPower")," > 1. Ie. the replenish fraction is set high enough that we can ignore the effects of rounding."),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishPeriod")," is sufficiently longer than the time it takes to produce a block.")),(0,n.kt)("p",null,(0,n.kt)("em",{parentName:"p"},"Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined.")),(0,n.kt)("p",null,"Property:"),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"The time it takes to jail/tombstone ",(0,n.kt)("inlineCode",{parentName:"p"},"X"),"% of the initial validator set will be greater than or equal to ",(0,n.kt)("inlineCode",{parentName:"p"},"(X * SlashMeterReplenishPeriod / SlashMeterReplenishFraction) - 2 * SlashMeterReplenishPeriod"))),(0,n.kt)("p",null,"Intuition:"),(0,n.kt)("p",null,"Let's use the following notation:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"$C$: Number of replenishment cycles"),(0,n.kt)("li",{parentName:"ul"},"$P$: $\\text{SlashMeterReplenishPeriod}$"),(0,n.kt)("li",{parentName:"ul"},"$F$: $\\text{SlashMeterReplenishFraction}$"),(0,n.kt)("li",{parentName:"ul"},"$V_{\\mathit{max}}$: Max power of a validator as a fraction of total voting power")),(0,n.kt)("p",null,"In $C$ number of replenishment cycles, the fraction of total voting power that can be removed, $a$, is $a \\leq F \\cdot C + V",(0,n.kt)("em",{parentName:"p"},"{\\mathit{max}}$ (where $V"),"{\\mathit{max}}$ is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value)."),(0,n.kt)("p",null,"So, we need at least $C \\geq \\frac{a - V_{\\mathit{max}}}{F}$ cycles to remove $a$ fraction of the total voting power."),(0,n.kt)("p",null,"Since we defined the start of the attack to be the moment when the first slash request arrives, then $F$ fraction of the initial validator set can be jailed immediately. For the remaining $X - F$ fraction of the initial validator set to be jailed, it takes at least $C \\geq \\frac{(X - F) - V",(0,n.kt)("em",{parentName:"p"},"{\\mathit{max}}}{F}$ cycles. Using the assumption that $V"),"{\\mathit{max}} \\leq F$ (assumption 2), we get $C \\geq \\frac{X - 2F}{F}$ cycles."),(0,n.kt)("p",null,"In order to execute $C$ cycles, we need $C \\cdot P$ time."),(0,n.kt)("p",null,"Thus, jailing the remaining $X - F$ fraction of the initial validator set corresponds to $\\frac{P \\cdot (X - 2F)}{F}$ time."),(0,n.kt)("p",null,"In other words, the attack must take at least $\\frac{P \\cdot X}{F} - 2P$ time (in the units of replenish period $P$)."),(0,n.kt)("p",null,"This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests. For example, if ",(0,n.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction")," is set to 0.06, then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub. Note that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power."),(0,n.kt)("p",null,"Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings."),(0,n.kt)("h3",{id:"how-unjailing-affects-the-main-throttling-property"},"How Unjailing Affects the Main Throttling Property"),(0,n.kt)("p",null,"Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained."),(0,n.kt)("p",null,"If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider."),(0,n.kt)("p",null,"In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack."),(0,n.kt)("h2",{id:"consequences"},"Consequences"),(0,n.kt)("h3",{id:"positive"},"Positive"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"The described attack is slowed down in seemingly all cases."),(0,n.kt)("li",{parentName:"ul"},"If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded.")),(0,n.kt)("h3",{id:"negative"},"Negative"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below. However, this is sacrificing liveness in a edge case scenario for the sake of security. As an improvement, ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/713"},"using retries")," would fully prevent this attack vector.")),(0,n.kt)("h3",{id:"neutral"},"Neutral"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Additional state is introduced to the provider chain."),(0,n.kt)("li",{parentName:"ul"},"VSCMatured and slash packet data is not always handled in the same block that it is received.")),(0,n.kt)("h2",{id:"references"},"References"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/404"},"Original issue inspiring throttling feature")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/594"},"Issue on DOS vector")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/685"},"Consideration of another attack vector"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/bc17315d.f9026ef2.js b/legacy/assets/js/bc17315d.f9026ef2.js new file mode 100644 index 0000000000..8b2ebb22ec --- /dev/null +++ b/legacy/assets/js/bc17315d.f9026ef2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1534],{3905:(e,r,n)=>{n.d(r,{Zo:()=>p,kt:()=>f});var t=n(7294);function o(e,r,n){return r in e?Object.defineProperty(e,r,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[r]=n,e}function i(e,r){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);r&&(t=t.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),n.push.apply(n,t)}return n}function a(e){for(var r=1;r<arguments.length;r++){var n=null!=arguments[r]?arguments[r]:{};r%2?i(Object(n),!0).forEach((function(r){o(e,r,n[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(n,r))}))}return e}function c(e,r){if(null==e)return{};var n,t,o=function(e,r){if(null==e)return{};var n,t,o={},i=Object.keys(e);for(t=0;t<i.length;t++)n=i[t],r.indexOf(n)>=0||(o[n]=e[n]);return o}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(t=0;t<i.length;t++)n=i[t],r.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=t.createContext({}),u=function(e){var r=t.useContext(s),n=r;return e&&(n="function"==typeof e?e(r):a(a({},r),e)),n},p=function(e){var r=u(e.components);return t.createElement(s.Provider,{value:r},e.children)},l="mdxType",m={inlineCode:"code",wrapper:function(e){var r=e.children;return t.createElement(t.Fragment,{},r)}},d=t.forwardRef((function(e,r){var n=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),l=u(n),d=o,f=l["".concat(s,".").concat(d)]||l[d]||m[d]||i;return n?t.createElement(f,a(a({ref:r},p),{},{components:n})):t.createElement(f,a({ref:r},p))}));function f(e,r){var n=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var c={};for(var s in r)hasOwnProperty.call(r,s)&&(c[s]=r[s]);c.originalType=e,c[l]="string"==typeof e?e:o,a[1]=c;for(var u=2;u<i;u++)a[u]=n[u];return t.createElement.apply(null,a)}return t.createElement.apply(null,n)}d.displayName="MDXCreateElement"},6008:(e,r,n)=>{n.r(r),n.d(r,{assets:()=>s,contentTitle:()=>a,default:()=>m,frontMatter:()=>i,metadata:()=>c,toc:()=>u});var t=n(7462),o=(n(7294),n(3905));const i={sidebar_position:3},a="Upgrading Consumer Chains",c={unversionedId:"consumer-development/consumer-chain-upgrade-procedure",id:"version-v2.4.0-lsm/consumer-development/consumer-chain-upgrade-procedure",title:"Upgrading Consumer Chains",description:"",source:"@site/versioned_docs/version-v2.4.0-lsm/consumer-development/consumer-chain-upgrade-procedure.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-chain-upgrade-procedure",permalink:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/consumer-chain-upgrade-procedure",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Consumer Chain Governance",permalink:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/consumer-chain-governance"},next:{title:"Onboarding Checklist",permalink:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/onboarding"}},s={},u=[],p={toc:u},l="wrapper";function m(e){let{components:r,...n}=e;return(0,o.kt)(l,(0,t.Z)({},p,n,{components:r,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"upgrading-consumer-chains"},"Upgrading Consumer Chains"))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/bc700a7c.65ce008c.js b/legacy/assets/js/bc700a7c.65ce008c.js new file mode 100644 index 0000000000..fb3becc84c --- /dev/null +++ b/legacy/assets/js/bc700a7c.65ce008c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5202],{3905:(e,t,a)=>{a.d(t,{Zo:()=>h,kt:()=>m});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?i(Object(a),!0).forEach((function(t){r(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):i(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function s(e,t){if(null==e)return{};var a,n,r=function(e,t){if(null==e)return{};var a,n,r={},i=Object.keys(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),c=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},h=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,h=s(e,["components","mdxType","originalType","parentName"]),d=c(a),p=r,m=d["".concat(l,".").concat(p)]||d[p]||u[p]||i;return a?n.createElement(m,o(o({ref:t},h),{},{components:a})):n.createElement(m,o({ref:t},h))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=p;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var c=2;c<i;c++)o[c]=a[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,a)}p.displayName="MDXCreateElement"},9439:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var n=a(7462),r=(a(7294),a(3905));const i={sidebar_position:7,title:"Throttle with retries"},o=void 0,s={unversionedId:"adrs/adr-008-throttle-retries",id:"version-v3.1.0/adrs/adr-008-throttle-retries",title:"Throttle with retries",description:"ADR 008: Throttle with retries",source:"@site/versioned_docs/version-v3.1.0/adrs/adr-008-throttle-retries.md",sourceDirName:"adrs",slug:"/adrs/adr-008-throttle-retries",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-008-throttle-retries",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:7,frontMatter:{sidebar_position:7,title:"Throttle with retries"},sidebar:"tutorialSidebar",previous:{title:"Equivocation governance proposal",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-003-equivocation-gov-proposal"},next:{title:"Soft Opt-Out",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-009-soft-opt-out"}},l={},c=[{value:"ADR 008: Throttle with retries",id:"adr-008-throttle-with-retries",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consumer changes",id:"consumer-changes",level:3},{value:"Provider changes",id:"provider-changes",level:3},{value:"Why the provider can handle VSCMatured packets immediately",id:"why-the-provider-can-handle-vscmatured-packets-immediately",level:3},{value:"Splitting of PRs",id:"splitting-of-prs",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],h={toc:c},d="wrapper";function u(e){let{components:t,...a}=e;return(0,r.kt)(d,(0,n.Z)({},h,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"adr-008-throttle-with-retries"},"ADR 008: Throttle with retries"),(0,r.kt)("h2",{id:"changelog"},"Changelog"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"6/9/23: Initial draft")),(0,r.kt)("h2",{id:"status"},"Status"),(0,r.kt)("p",null,"Accepted"),(0,r.kt)("h2",{id:"context"},"Context"),(0,r.kt)("p",null,"For context on why the throttling mechanism exists, see ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.1.0/adrs/adr-002-throttle"},"ADR 002"),"."),(0,r.kt)("p",null,"Note the terms slash throttling and jail throttling are synonymous, since in replicated security a ",(0,r.kt)("inlineCode",{parentName:"p"},"SlashPacket")," simply jails a validator for downtime infractions. "),(0,r.kt)("p",null,"Currently the throttling mechanism is designed so that provider logic (slash meter, etc.) dictates how many slash packets can be handled over time. Throttled slash packets are persisted on the provider, leading to multiple possible issues. Namely:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"If slash or vsc matured packets are actually throttled/queued on the provider, state can grow and potentially lead to a DoS attack. We have short term solutions around this, but overall they come with their own weaknesses. See ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/594"},"#594"),"."),(0,r.kt)("li",{parentName:"ul"},"If a jailing attack described in ",(0,r.kt)("a",{parentName:"li",href:"/interchain-security/legacy/v3.1.0/adrs/adr-002-throttle"},"ADR 002")," were actually to be carried out with the current throttling design, we'd likely have to halt the provider, and perform an emergency upgrade and/or migration to clear the queues of slash packets that were deemed to be malicious. Alternatively, validators would just have to ",(0,r.kt)("em",{parentName:"li"},"tough it out")," and wait for the queues to clear, during which all/most validators would be jailed. Right after being jailed, vals would have to unjail themselves promptly to ensure safety. The synchronous coordination required to maintain safety in such a scenario is not ideal.")),(0,r.kt)("p",null,"So what's the solution? We can improve the throttling mechanism to instead queue/persist relevant data on each consumer, and have consumers retry slash requests as needed."),(0,r.kt)("h2",{id:"decision"},"Decision"),(0,r.kt)("h3",{id:"consumer-changes"},"Consumer changes"),(0,r.kt)("p",null,"Note the consumer already queues up both slash and vsc matured packets via ",(0,r.kt)("inlineCode",{parentName:"p"},"AppendPendingPacket"),". Those packets are dequeued every endblock in ",(0,r.kt)("inlineCode",{parentName:"p"},"SendPackets")," and sent to the provider."),(0,r.kt)("p",null,"Instead, we will now introduce the following logic on endblock:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Slash packets will always be sent to the provider once they're at the head of the queue. However, once sent, the consumer will not send any trailing vsc matured packets from the queue until the provider responds with an ack that the slash packet has been handled (ie. val was jailed). That is, slash packets block the sending of trailing vsc matured packets in the consumer queue."),(0,r.kt)("li",{parentName:"ul"},"If two slash packets are at the head of the queue, the consumer will send the first slash packet, and then wait for a success ack from the provider before sending the second slash packet. This seems like it'd simplify implementation."),(0,r.kt)("li",{parentName:"ul"},"VSC matured packets at the head of the queue (ie. NOT trailing a slash packet) can be sent immediately, and do not block any other packets in the queue, since the provider always handles them immediately.")),(0,r.kt)("p",null,"To prevent the provider from having to keep track of what slash packets have been rejected, the consumer will have to retry the sending of slash packets over some period of time. This can be achieved with an on-chain consumer param. The suggested param value would probably be 1/2 of the provider's ",(0,r.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishmentPeriod"),", although it doesn't matter too much as long as the param value is sane."),(0,r.kt)("p",null,"Note to prevent weird edge case behavior, a retry would not be attempted until either a success ack or failure ack has been recv from the provider."),(0,r.kt)("p",null,"With the behavior described, we maintain very similar behavior to the current throttling mechanism regarding the timing that slash and vsc matured packets are handled on the provider. Obviously the queueing and blocking logic is moved, and the two chains would have to send more messages between one another (only in the case the throttling mechanism is triggered)."),(0,r.kt)("p",null,"In the normal case, when no or a few slash packets are being sent, the VSCMaturedPackets will not be delayed, and hence unbonding will not be delayed."),(0,r.kt)("h3",{id:"provider-changes"},"Provider changes"),(0,r.kt)("p",null,"The main change needed for the provider is the removal of queuing logic for slash and vsc matured packets upon being received."),(0,r.kt)("p",null,"Instead, the provider will consult the slash meter to determine if a slash packet can be handled immediately. If not, the provider will return an ack message to the consumer communicating that the slash packet could not be handled, and needs to be sent again in the future (retried)."),(0,r.kt)("p",null,"VSCMatured packets will always be handled immediately upon being received by the provider."),(0,r.kt)("p",null,"Note ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"spec"),". Specifically the section on ",(0,r.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order"),". Previously the onus was on the provider to maintain this property via queuing packets and handling them FIFO."),(0,r.kt)("p",null,"Now this property will be maintained by the consumer sending packets in the correct order, and blocking the sending of VSCMatured packets as needed. Then, the ordered IBC channel will ensure that Slash/VSCMatured packets are received in the correct order on the provider."),(0,r.kt)("p",null,"The provider's main responsibility regarding throttling will now be to determine if a recv slash packet can be handled via slash meter etc., and appropriately ack to the sending consumer."),(0,r.kt)("h3",{id:"why-the-provider-can-handle-vscmatured-packets-immediately"},"Why the provider can handle VSCMatured packets immediately"),(0,r.kt)("p",null,"First we answer, what does a VSCMatured packet communicate to the provider? A VSCMatured packet communicates that a VSC has been applied to a consumer long enough that infractions committed on the consumer could have been submitted."),(0,r.kt)("p",null,"If the consumer is following the queuing/blocking protocol described. No bad behavior occurs, ",(0,r.kt)("inlineCode",{parentName:"p"},"VSC Maturity and Slashing Order")," property is maintained."),(0,r.kt)("p",null,"If a consumer sends VSCMatured packets too leniently: The consumer is malicious and sending duplicate vsc matured packets, or sending the packets sooner than the ccv protocol specifies. In this scenario, the provider needs to handle vsc matured packets immediately to prevent DOS, state bloat, or other issues. The only possible negative outcome is that the malicious consumer may not be able to jail a validator who should have been jailed. The malicious behavior only creates a negative outcome for the chain that is being malicious."),(0,r.kt)("p",null,"If a consumer blocks the sending of VSCMatured packets: The consumer is malicious and blocking vsc matured packets that should have been sent. This will block unbonding only up until the VSC timeout period has elapsed. At that time, the consumer is removed. Again the malicious behavior only creates a negative outcome for the chain that is being malicious."),(0,r.kt)("h3",{id:"splitting-of-prs"},"Splitting of PRs"),(0,r.kt)("p",null,"We could split this feature into two PRs, one affecting the consumer and one affecting the provider, along with a third PR which could setup a clever way to upgrade the provider in multiple steps, ensuring that queued slash packets at upgrade time are handled properly."),(0,r.kt)("h2",{id:"consequences"},"Consequences"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Consumers will now have to manage their own queues, and retry logic."),(0,r.kt)("li",{parentName:"ul"},"Consumers still aren't trustless, but the provider is now less susceptible to mismanaged or malicious consumers."),(0,r.kt)("li",{parentName:"ul"},'Recovering from the "jailing attack" is more elegant.'),(0,r.kt)("li",{parentName:"ul"},"Some issues like ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/1001"},"#1001")," will now be handled implicitly by the improved throttling mechanism."),(0,r.kt)("li",{parentName:"ul"},"Slash and vsc matured packets can be handled immediately once recv by the provider if the slash meter allows."),(0,r.kt)("li",{parentName:"ul"},"In general, we reduce the amount of computation that happens in the provider end-blocker.")),(0,r.kt)("h3",{id:"positive"},"Positive"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},'We no longer have to reason about a "global queue" and a "chain specific queue", and keeping those all in-sync. Now slash and vsc matured packet queuing is handled on each consumer individually.'),(0,r.kt)("li",{parentName:"ul"},"Due to the above, the throttling protocol becomes less complex overall."),(0,r.kt)("li",{parentName:"ul"},"We no longer have to worry about throttle related DoS attack on the provider, since no queuing exists on the provider.")),(0,r.kt)("h3",{id:"negative"},"Negative"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Increased number of IBC packets being relayed anytime throttling logic is triggered."),(0,r.kt)("li",{parentName:"ul"},"Consumer complexity increases, since consumers now have manage queuing themselves, and implement packet retry logic.")),(0,r.kt)("h3",{id:"neutral"},"Neutral"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Core throttling logic on the provider remains unchanged, ie. slash meter, replenishment cycles, etc.")),(0,r.kt)("h2",{id:"references"},"References"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/713"},"EPIC")," tracking the changes proposed by this ADR"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"/interchain-security/legacy/v3.1.0/adrs/adr-002-throttle"},"ADR 002: Jail Throttling")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/594"},"#594"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/bc8b8418.390b8795.js b/legacy/assets/js/bc8b8418.390b8795.js new file mode 100644 index 0000000000..52c1f2f3a5 --- /dev/null +++ b/legacy/assets/js/bc8b8418.390b8795.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4704],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>y});var i=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,i)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){n(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,i,n=function(e,t){if(null==e)return{};var r,i,n={},o=Object.keys(e);for(i=0;i<o.length;i++)r=o[i],t.indexOf(r)>=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i<o.length;i++)r=o[i],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=i.createContext({}),l=function(e){var t=i.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},u=function(e){var t=l(e.components);return i.createElement(s.Provider,{value:t},e.children)},h="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},p=i.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),h=l(r),p=n,y=h["".concat(s,".").concat(p)]||h[p]||d[p]||o;return r?i.createElement(y,a(a({ref:t},u),{},{components:r})):i.createElement(y,a({ref:t},u))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,a=new Array(o);a[0]=p;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[h]="string"==typeof e?e:n,a[1]=c;for(var l=2;l<o;l++)a[l]=r[l];return i.createElement.apply(null,a)}return i.createElement.apply(null,r)}p.displayName="MDXCreateElement"},1322:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>d,frontMatter:()=>o,metadata:()=>c,toc:()=>l});var i=r(7462),n=(r(7294),r(3905));const o={sidebar_position:2},a="Terminology",c={unversionedId:"introduction/terminology",id:"introduction/terminology",title:"Terminology",description:"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.",source:"@site/docs/introduction/terminology.md",sourceDirName:"introduction",slug:"/introduction/terminology",permalink:"/interchain-security/legacy/introduction/terminology",draft:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/legacy/introduction/overview"},next:{title:"Interchain Security Parameters",permalink:"/interchain-security/legacy/introduction/params"}},s={},l=[{value:"Shared Security",id:"shared-security",level:2},{value:"Interchain Security",id:"interchain-security",level:2},{value:"Replicated Security",id:"replicated-security",level:2},{value:"Mesh security",id:"mesh-security",level:2},{value:"Consumer Chain",id:"consumer-chain",level:2},{value:"Standalone Chain",id:"standalone-chain",level:2},{value:"Changeover Procedure",id:"changeover-procedure",level:2}],u={toc:l},h="wrapper";function d(e){let{components:t,...r}=e;return(0,n.kt)(h,(0,i.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"terminology"},"Terminology"),(0,n.kt)("p",null,"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions."),(0,n.kt)("h2",{id:"shared-security"},"Shared Security"),(0,n.kt)("p",null,"Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share its proof-of-stake security with another blockchain or off-chain process."),(0,n.kt)("h2",{id:"interchain-security"},"Interchain Security"),(0,n.kt)("p",null,"Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC."),(0,n.kt)("h2",{id:"replicated-security"},"Replicated Security"),(0,n.kt)("p",null,'A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC. Note this documentation is focused on explaining the concepts from replicated security.'),(0,n.kt)("h2",{id:"mesh-security"},"Mesh security"),(0,n.kt)("p",null,"A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see ",(0,n.kt)("a",{parentName:"p",href:"https://informal.systems/blog/replicated-vs-mesh-security"},"Replicated vs. Mesh Security on the Informal Blog"),"."),(0,n.kt)("h2",{id:"consumer-chain"},"Consumer Chain"),(0,n.kt)("p",null,"Chain that is secured by the validator set of the provider, instead of its own.\nReplicated security allows the provider chain validator set to validate blocks on the consumer chain."),(0,n.kt)("h2",{id:"standalone-chain"},"Standalone Chain"),(0,n.kt)("p",null,"Chain that is secured by its own validator set. This chain does not participate in replicated security."),(0,n.kt)("p",null,'Standalone chains may sometimes be called "sovereign" - the terms are synonymous.'),(0,n.kt)("h2",{id:"changeover-procedure"},"Changeover Procedure"),(0,n.kt)("p",null,"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the ",(0,n.kt)("strong",{parentName:"p"},"changeover procedure")," and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/c2cfb320.c4803ac7.js b/legacy/assets/js/c2cfb320.c4803ac7.js new file mode 100644 index 0000000000..9fcf6eba65 --- /dev/null +++ b/legacy/assets/js/c2cfb320.c4803ac7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1429],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>m});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),d=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=d(e.components);return a.createElement(l.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=d(n),h=i,m=p["".concat(l,".").concat(h)]||p[h]||u[h]||r;return n?a.createElement(m,o(o({ref:t},c),{},{components:n})):a.createElement(m,o({ref:t},c))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:i,o[1]=s;for(var d=2;d<r;d++)o[d]=n[d];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},6096:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>s,toc:()=>d});var a=n(7462),i=(n(7294),n(3905));const r={sidebar_position:4},o="Validator instructions for Changeover Procedure",s={unversionedId:"validators/changeover-procedure",id:"validators/changeover-procedure",title:"Validator instructions for Changeover Procedure",description:"More details available in Changeover Procedure documentation.",source:"@site/docs/validators/changeover-procedure.md",sourceDirName:"validators",slug:"/validators/changeover-procedure",permalink:"/interchain-security/legacy/validators/changeover-procedure",draft:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Withdrawing consumer chain validator rewards",permalink:"/interchain-security/legacy/validators/withdraw_rewards"},next:{title:"Joining Neutron",permalink:"/interchain-security/legacy/validators/joining-neutron"}},l={},d=[{value:"Timeline",id:"timeline",level:2},{value:"1. <code>ConsumerAdditionProposal</code> on provider chain",id:"1-consumeradditionproposal-on-provider-chain",level:3},{value:"2. <code>SoftwareUpgradeProposal</code> on the standalone/consumer chain",id:"2-softwareupgradeproposal-on-the-standaloneconsumer-chain",level:3},{value:"3. Assigning a consumer key",id:"3-assigning-a-consumer-key",level:3},{value:"4. Perform the software ugprade on standalone chain",id:"4-perform-the-software-ugprade-on-standalone-chain",level:3},{value:"FAQ",id:"faq",level:2},{value:"Can I reuse the same validator key for the <code>consumer</code> chain that I am already using on the <code>standalone</code> chain? Will I need to perform a <code>AssignConsumerKey</code> tx with this key before spawn time?",id:"can-i-reuse-the-same-validator-key-for-the-consumer-chain-that-i-am-already-using-on-the-standalone-chain-will-i-need-to-perform-a-assignconsumerkey-tx-with-this-key-before-spawn-time",level:3},{value:"Can I continue using the same node that was validating the <code>standalone</code> chain?",id:"can-i-continue-using-the-same-node-that-was-validating-the-standalone-chain",level:3},{value:"Can I set up a new node to validate the <code>standalone/consumer</code> chain after it transitions to replicated security?",id:"can-i-set-up-a-new-node-to-validate-the-standaloneconsumer-chain-after-it-transitions-to-replicated-security",level:3},{value:"What happens to the <code>standalone</code> validator set after it after it transitions to replicated security?",id:"what-happens-to-the-standalone-validator-set-after-it-after-it-transitions-to-replicated-security",level:3},{value:"Credits",id:"credits",level:2}],c={toc:d},p="wrapper";function u(e){let{components:t,...r}=e;return(0,i.kt)(p,(0,a.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"validator-instructions-for-changeover-procedure"},"Validator instructions for Changeover Procedure"),(0,i.kt)("p",null,"More details available in ",(0,i.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/changeover-procedure"},"Changeover Procedure documentation"),"."),(0,i.kt)("p",null,"A major difference betwen launching a new consumer chain vs. onboarding a standalone chain to ICS is that there is no consumer genesis available for the standalone chain. Since a standalone chain already exists, its state must be preserved once it transitions to being a consumer chain."),(0,i.kt)("h2",{id:"timeline"},"Timeline"),(0,i.kt)("p",null,"Upgrading standalone chains can be best visualised using a timeline, such as the one available ",(0,i.kt)("a",{parentName:"p",href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt"},"Excalidraw graphic by Stride"),"."),(0,i.kt)("p",null,"There is some flexibility with regards to how the changeover procedure is executed, so please make sure to follow the guides provided by the team doing the changeover."),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"Standalone to consumer transition timeline",src:n(8106).Z,width:"5307",height:"2157"})),(0,i.kt)("h3",{id:"1-consumeradditionproposal-on-provider-chain"},"1. ",(0,i.kt)("inlineCode",{parentName:"h3"},"ConsumerAdditionProposal")," on provider chain"),(0,i.kt)("p",null,"This step will add the standalone chain to the list of consumer chains secured by the provider.\nThis step dictates the ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time"),". After ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," the CCV state (initial validator set of the provider) will be available to the consumer."),(0,i.kt)("p",null,"To obtain it from the provider use:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad q provider consumer-genesis stride-1 -o json > ccv-state.json\njq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' genesis.json ccv-state.json > ccv.json\n")),(0,i.kt)("h3",{id:"2-softwareupgradeproposal-on-the-standaloneconsumer-chain"},"2. ",(0,i.kt)("inlineCode",{parentName:"h3"},"SoftwareUpgradeProposal")," on the standalone/consumer chain"),(0,i.kt)("p",null,"This upgrade proposal will introduce ICS to the standalone chain, making it a consumer."),(0,i.kt)("h3",{id:"3-assigning-a-consumer-key"},"3. Assigning a consumer key"),(0,i.kt)("p",null,"After ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time"),", make sure to assign a consumer key if you intend to use one."),(0,i.kt)("p",null,"Instructions are available ",(0,i.kt)("a",{parentName:"p",href:"/interchain-security/legacy/features/key-assignment"},"here")),(0,i.kt)("h3",{id:"4-perform-the-software-ugprade-on-standalone-chain"},"4. Perform the software ugprade on standalone chain"),(0,i.kt)("p",null,"Please use instructions provided by the standalone chain team and make sure to reach out if you are facing issues.\nThe upgrade preparation depends on your setup, so please make sure you prepare ahead of time."),(0,i.kt)("admonition",{type:"danger"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"ccv.json")," from step 1. must be made available on the machine running the standalone/consumer chain at standalone chain ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height"),". This file contains the initial validator set and parameters required for normal ICS operation."),(0,i.kt)("p",{parentName:"admonition"},"Usually, the file is placed in ",(0,i.kt)("inlineCode",{parentName:"p"},"$NODE_HOME/config")," but this is not a strict requirement. The exact details are available in the upgrade code of the standalone/consumer chain.")),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Performing this upgrade will transition the standalone chain to be a consumer chain.")),(0,i.kt)("p",null,'After 3 blocks, the standalone chain will stop using the "old" validator set and begin using the ',(0,i.kt)("inlineCode",{parentName:"p"},"provider")," validator set."),(0,i.kt)("h2",{id:"faq"},"FAQ"),(0,i.kt)("h3",{id:"can-i-reuse-the-same-validator-key-for-the-consumer-chain-that-i-am-already-using-on-the-standalone-chain-will-i-need-to-perform-a-assignconsumerkey-tx-with-this-key-before-spawn-time"},"Can I reuse the same validator key for the ",(0,i.kt)("inlineCode",{parentName:"h3"},"consumer")," chain that I am already using on the ",(0,i.kt)("inlineCode",{parentName:"h3"},"standalone")," chain? Will I need to perform a ",(0,i.kt)("inlineCode",{parentName:"h3"},"AssignConsumerKey")," tx with this key before spawn time?"),(0,i.kt)("p",null,"Validators must either assign a key or use the same key as on the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider"),"."),(0,i.kt)("p",null,"If you are validating both the ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," and the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider"),", you ",(0,i.kt)("strong",{parentName:"p"},"can")," use your current ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," key with some caveats:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"you must submit an ",(0,i.kt)("inlineCode",{parentName:"li"},"AssignConsumerKey")," tx with your current ",(0,i.kt)("inlineCode",{parentName:"li"},"standalone")," validator key"),(0,i.kt)("li",{parentName:"ul"},"it is best to submit ",(0,i.kt)("inlineCode",{parentName:"li"},"AssignConsumerKey")," tx before ",(0,i.kt)("inlineCode",{parentName:"li"},"spawn_time")),(0,i.kt)("li",{parentName:"ul"},"if you do not submit the Tx, it is assumed that you will be re-using your ",(0,i.kt)("inlineCode",{parentName:"li"},"provider")," key to validate the ",(0,i.kt)("inlineCode",{parentName:"li"},"standalone/consumer")," chain")),(0,i.kt)("h3",{id:"can-i-continue-using-the-same-node-that-was-validating-the-standalone-chain"},"Can I continue using the same node that was validating the ",(0,i.kt)("inlineCode",{parentName:"h3"},"standalone")," chain?"),(0,i.kt)("p",null,"Yes."),(0,i.kt)("p",null,"Please assign your consensus key as stated aboce."),(0,i.kt)("h3",{id:"can-i-set-up-a-new-node-to-validate-the-standaloneconsumer-chain-after-it-transitions-to-replicated-security"},"Can I set up a new node to validate the ",(0,i.kt)("inlineCode",{parentName:"h3"},"standalone/consumer")," chain after it transitions to replicated security?"),(0,i.kt)("p",null,"Yes."),(0,i.kt)("p",null,"If you are planning to do this please make sure that the node is synced with ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," network and to submit ",(0,i.kt)("inlineCode",{parentName:"p"},"AssignConsumerKey")," tx before ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time"),"."),(0,i.kt)("h3",{id:"what-happens-to-the-standalone-validator-set-after-it-after-it-transitions-to-replicated-security"},"What happens to the ",(0,i.kt)("inlineCode",{parentName:"h3"},"standalone")," validator set after it after it transitions to replicated security?"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," chain validators will stop being validators after the first 3 blocks are created while using replicated security. The ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," validators will become ",(0,i.kt)("strong",{parentName:"p"},"governors")," and still can receive delegations if the ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer")," chain is using the ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer-democracy")," module."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Governors DO NOT VALIDATE BLOCKS"),"."),(0,i.kt)("p",null,"Instead, they can participate in the governance process and take on other chain-specific roles."),(0,i.kt)("h2",{id:"credits"},"Credits"),(0,i.kt)("p",null,"Thank you Stride team for providing detailed instructions about the changeover procedure."))}u.isMDXComponent=!0},8106:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/ics_changeover_timeline_stride-9bcad1834fef24a0fea7f2c80c9ccd71.png"}}]); \ No newline at end of file diff --git a/legacy/assets/js/c2da6a7e.9945fe6d.js b/legacy/assets/js/c2da6a7e.9945fe6d.js new file mode 100644 index 0000000000..eb628fcbfa --- /dev/null +++ b/legacy/assets/js/c2da6a7e.9945fe6d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[155],{3905:(e,n,t)=>{t.d(n,{Zo:()=>m,kt:()=>d});var r=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function c(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function i(e,n){if(null==e)return{};var t,r,o=function(e,n){if(null==e)return{};var t,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var s=r.createContext({}),l=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):c(c({},n),e)),t},m=function(e){var n=l(e.components);return r.createElement(s.Provider,{value:n},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},p=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,m=i(e,["components","mdxType","originalType","parentName"]),u=l(t),p=o,d=u["".concat(s,".").concat(p)]||u[p]||h[p]||a;return t?r.createElement(d,c(c({ref:n},m),{},{components:t})):r.createElement(d,c({ref:n},m))}));function d(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,c=new Array(a);c[0]=p;var i={};for(var s in n)hasOwnProperty.call(n,s)&&(i[s]=n[s]);i.originalType=e,i[u]="string"==typeof e?e:o,c[1]=i;for(var l=2;l<a;l++)c[l]=t[l];return r.createElement.apply(null,c)}return r.createElement.apply(null,t)}p.displayName="MDXCreateElement"},9562:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>c,default:()=>h,frontMatter:()=>a,metadata:()=>i,toc:()=>l});var r=t(7462),o=(t(7294),t(3905));const a={sidebar_position:2},c="Consumer Chain Governance",i={unversionedId:"consumer-development/consumer-chain-governance",id:"version-v3.1.0/consumer-development/consumer-chain-governance",title:"Consumer Chain Governance",description:'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.',source:"@site/versioned_docs/version-v3.1.0/consumer-development/consumer-chain-governance.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-chain-governance",permalink:"/interchain-security/legacy/v3.1.0/consumer-development/consumer-chain-governance",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/legacy/v3.1.0/consumer-development/app-integration"},next:{title:"Upgrading Consumer Chains",permalink:"/interchain-security/legacy/v3.1.0/consumer-development/consumer-chain-upgrade-procedure"}},s={},l=[{value:"Democracy module",id:"democracy-module",level:2},{value:"CosmWasm",id:"cosmwasm",level:2},{value:"The Whitelist",id:"the-whitelist",level:2}],m={toc:l},u="wrapper";function h(e){let{components:n,...t}=e;return(0,o.kt)(u,(0,r.Z)({},m,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-chain-governance"},"Consumer Chain Governance"),(0,o.kt)("p",null,'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.'),(0,o.kt)("h2",{id:"democracy-module"},"Democracy module"),(0,o.kt)("p",null,"The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy."),(0,o.kt)("p",null,"Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus."),(0,o.kt)("p",null,"For an example, see the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy"},"Democracy Consumer")),(0,o.kt)("h2",{id:"cosmwasm"},"CosmWasm"),(0,o.kt)("p",null,"There several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain."),(0,o.kt)("p",null,"For an example, see ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/neutron-org/neutron/"},"Neutron"),"."),(0,o.kt)("h2",{id:"the-whitelist"},"The Whitelist"),(0,o.kt)("p",null,"Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/neutron-org/neutron/blob/main/app/proposals_allowlisting.go"},"Neutron's")," whitelist."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/c37f2705.419e8a23.js b/legacy/assets/js/c37f2705.419e8a23.js new file mode 100644 index 0000000000..cb88040b74 --- /dev/null +++ b/legacy/assets/js/c37f2705.419e8a23.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4695],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>m});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=c(n),h=a,m=p["".concat(s,".").concat(h)]||p[h]||d[h]||o;return n?r.createElement(m,i(i({ref:t},u),{},{components:n})):r.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:a,i[1]=l;for(var c=2;c<o;c++)i[c]=n[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}h.displayName="MDXCreateElement"},6705:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const o={sidebar_position:2,title:"ADR Template"},i="ADR {ADR-NUMBER}:",l={unversionedId:"adrs/adr-template",id:"adrs/adr-template",title:"ADR Template",description:"Changelog",source:"@site/docs/adrs/adr-template.md",sourceDirName:"adrs",slug:"/adrs/adr-template",permalink:"/interchain-security/legacy/adrs/adr-template",draft:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"ADR Template"},sidebar:"tutorialSidebar",previous:{title:"ADR Template",permalink:"/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop"},next:{title:"Key Assignment",permalink:"/interchain-security/legacy/adrs/adr-001-key-assignment"}},s={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],u={toc:c},p="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(p,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-adr-number-title"},"ADR {ADR-NUMBER}: {TITLE}"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"{date}: {changelog}")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},'A decision may be "proposed" if it hasn\'t been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement.')),(0,a.kt)("p",null,"{Deprecated|Proposed|Accepted}"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution. ")),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"This section explains all of the details of the proposed solution, including implementation details.\nIt should also describe affects / corollary items that may need to be changed as a part of this.\nIf the proposed change will be large, please also indicate a way to do the change to maximize ease of review.\n(e.g. the optimal split of things to do between separate PR's)")),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},'This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones.')),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"{reference link}")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/c566c0a4.3e13bfdc.js b/legacy/assets/js/c566c0a4.3e13bfdc.js new file mode 100644 index 0000000000..73d5e32eeb --- /dev/null +++ b/legacy/assets/js/c566c0a4.3e13bfdc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8976],{3905:(e,t,a)=>{a.d(t,{Zo:()=>h,kt:()=>m});var n=a(7294);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?r(Object(a),!0).forEach((function(t){i(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):r(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function s(e,t){if(null==e)return{};var a,n,i=function(e,t){if(null==e)return{};var a,n,i={},r=Object.keys(e);for(n=0;n<r.length;n++)a=r[n],t.indexOf(a)>=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n<r.length;n++)a=r[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var l=n.createContext({}),c=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},h=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,r=e.originalType,l=e.parentName,h=s(e,["components","mdxType","originalType","parentName"]),d=c(a),p=i,m=d["".concat(l,".").concat(p)]||d[p]||u[p]||r;return a?n.createElement(m,o(o({ref:t},h),{},{components:a})):n.createElement(m,o({ref:t},h))}));function m(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=a.length,o=new Array(r);o[0]=p;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:i,o[1]=s;for(var c=2;c<r;c++)o[c]=a[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,a)}p.displayName="MDXCreateElement"},449:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>s,toc:()=>c});var n=a(7462),i=(a(7294),a(3905));const r={sidebar_position:7,title:"Throttle with retries"},o=void 0,s={unversionedId:"adrs/adr-008-throttle-retries",id:"version-v3.2.0/adrs/adr-008-throttle-retries",title:"Throttle with retries",description:"ADR 008: Throttle with retries",source:"@site/versioned_docs/version-v3.2.0/adrs/adr-008-throttle-retries.md",sourceDirName:"adrs",slug:"/adrs/adr-008-throttle-retries",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-008-throttle-retries",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:7,frontMatter:{sidebar_position:7,title:"Throttle with retries"},sidebar:"tutorialSidebar",previous:{title:"Cryptographic verification of equivocation evidence",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-005-cryptographic-equivocation-verification"},next:{title:"Soft Opt-Out",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-009-soft-opt-out"}},l={},c=[{value:"ADR 008: Throttle with retries",id:"adr-008-throttle-with-retries",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consumer changes",id:"consumer-changes",level:3},{value:"Consumer pending packets storage optimization",id:"consumer-pending-packets-storage-optimization",level:3},{value:"Provider changes",id:"provider-changes",level:3},{value:"Why the provider can handle VSCMatured packets immediately",id:"why-the-provider-can-handle-vscmatured-packets-immediately",level:3},{value:"Splitting of PRs and Upgrade Order",id:"splitting-of-prs-and-upgrade-order",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],h={toc:c},d="wrapper";function u(e){let{components:t,...a}=e;return(0,i.kt)(d,(0,n.Z)({},h,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h2",{id:"adr-008-throttle-with-retries"},"ADR 008: Throttle with retries"),(0,i.kt)("h2",{id:"changelog"},"Changelog"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"6/9/23: Initial draft"),(0,i.kt)("li",{parentName:"ul"},"6/22/23: added note on consumer pending packets storage optimization"),(0,i.kt)("li",{parentName:"ul"},"7/14/23: Added note on upgrade order")),(0,i.kt)("h2",{id:"status"},"Status"),(0,i.kt)("p",null,"Accepted"),(0,i.kt)("h2",{id:"context"},"Context"),(0,i.kt)("p",null,"For context on why the throttling mechanism exists, see ",(0,i.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.2.0/adrs/adr-002-throttle"},"ADR 002"),"."),(0,i.kt)("p",null,"Note the terms slash throttling and jail throttling are synonymous, since in replicated security a ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPacket")," simply jails a validator for downtime infractions. "),(0,i.kt)("p",null,"Currently the throttling mechanism is designed so that provider logic (slash meter, etc.) dictates how many slash packets can be handled over time. Throttled slash packets are persisted on the provider, leading to multiple possible issues. Namely:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"If slash or vsc matured packets are actually throttled/queued on the provider, state can grow and potentially lead to a DoS attack. We have short term solutions around this, but overall they come with their own weaknesses. See ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/594"},"#594"),"."),(0,i.kt)("li",{parentName:"ul"},"If a jailing attack described in ",(0,i.kt)("a",{parentName:"li",href:"/interchain-security/legacy/v3.2.0/adrs/adr-002-throttle"},"ADR 002")," were actually to be carried out with the current throttling design, we'd likely have to halt the provider, and perform an emergency upgrade and/or migration to clear the queues of slash packets that were deemed to be malicious. Alternatively, validators would just have to ",(0,i.kt)("em",{parentName:"li"},"tough it out")," and wait for the queues to clear, during which all/most validators would be jailed. Right after being jailed, vals would have to unjail themselves promptly to ensure safety. The synchronous coordination required to maintain safety in such a scenario is not ideal.")),(0,i.kt)("p",null,"So what's the solution? We can improve the throttling mechanism to instead queue/persist relevant data on each consumer, and have consumers retry slash requests as needed."),(0,i.kt)("h2",{id:"decision"},"Decision"),(0,i.kt)("h3",{id:"consumer-changes"},"Consumer changes"),(0,i.kt)("p",null,"Note the consumer already queues up both slash and vsc matured packets via ",(0,i.kt)("inlineCode",{parentName:"p"},"AppendPendingPacket"),". Those packets are dequeued every endblock in ",(0,i.kt)("inlineCode",{parentName:"p"},"SendPackets")," and sent to the provider."),(0,i.kt)("p",null,"Instead, we will now introduce the following logic on endblock:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Slash packets will always be sent to the provider once they're at the head of the queue. However, once sent, the consumer will not send any trailing vsc matured packets from the queue until the provider responds with an ack that the slash packet has been handled (ie. val was jailed). That is, slash packets block the sending of trailing vsc matured packets in the consumer queue."),(0,i.kt)("li",{parentName:"ul"},"If two slash packets are at the head of the queue, the consumer will send the first slash packet, and then wait for a success ack from the provider before sending the second slash packet. This seems like it'd simplify implementation."),(0,i.kt)("li",{parentName:"ul"},"VSC matured packets at the head of the queue (ie. NOT trailing a slash packet) can be sent immediately, and do not block any other packets in the queue, since the provider always handles them immediately.")),(0,i.kt)("p",null,"To prevent the provider from having to keep track of what slash packets have been rejected, the consumer will have to retry the sending of slash packets over some period of time. This can be achieved with an on-chain consumer param. The suggested param value would probably be 1/2 of the provider's ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishmentPeriod"),", although it doesn't matter too much as long as the param value is sane."),(0,i.kt)("p",null,"Note to prevent weird edge case behavior, a retry would not be attempted until either a success ack or failure ack has been recv from the provider."),(0,i.kt)("p",null,"With the behavior described, we maintain very similar behavior to the current throttling mechanism regarding the timing that slash and vsc matured packets are handled on the provider. Obviously the queueing and blocking logic is moved, and the two chains would have to send more messages between one another (only in the case the throttling mechanism is triggered)."),(0,i.kt)("p",null,"In the normal case, when no or a few slash packets are being sent, the VSCMaturedPackets will not be delayed, and hence unbonding will not be delayed."),(0,i.kt)("p",null,"For implementation of this design, see ",(0,i.kt)("a",{parentName:"p",href:"../../../x/ccv/consumer/keeper/throttle_retry.go"},"throttle_retry.go"),"."),(0,i.kt)("h3",{id:"consumer-pending-packets-storage-optimization"},"Consumer pending packets storage optimization"),(0,i.kt)("p",null,"In addition to the mentioned consumer changes above. An optimization will need to be made to the consumer's pending packets storage to properly implement the feature from this ADR."),(0,i.kt)("p",null,'The consumer ccv module previously queued "pending packets" to be sent on each endblocker in ',(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/3bc4e7135066d848aac60b0787364c07157fd36d/x/ccv/consumer/keeper/relay.go#L178"},"SendPackets"),". These packets are queued in state with a protobuf list of ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerPacketData"),". For a single append operation, the entire list is deserialized, then a packet is appended to that list, and the list is serialized again. See older version of ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/05c2dae7c6372b1252b9e97215d07c6aa7618f33/x/ccv/consumer/keeper/keeper.go#L606"},"AppendPendingPacket"),". That is, a single append operation has O(N) complexity, where N is the size of the list."),(0,i.kt)("p",null,"This poor append performance isn't a problem when the pending packets list is small. But with this ADR being implemented, the pending packets list could potentially grow to the order of thousands of entries, in the scenario that a slash packet is bouncing."),(0,i.kt)("p",null,"We can improve the append time for this queue by converting it from a protobuf-esq list, to a queue implemented with sdk-esq code. The idea is to persist an uint64 index that will be incremented each time you queue up a packet. You can think of this as storing the tail of the queue. Then, packet data will be keyed by that index, making the data naturally ordered byte-wise for sdk's iterator. The index will also be stored in the packet data value bytes, so that the index can later be used to delete certain packets from the queue."),(0,i.kt)("p",null,"Two things are achieved with this approach:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"More efficient packet append/enqueue times"),(0,i.kt)("li",{parentName:"ul"},"The ability to delete select packets from the queue (previously all packets were deleted at once)")),(0,i.kt)("h3",{id:"provider-changes"},"Provider changes"),(0,i.kt)("p",null,"The main change needed for the provider is the removal of queuing logic for slash and vsc matured packets upon being received."),(0,i.kt)("p",null,"Instead, the provider will consult the slash meter to determine if a slash packet can be handled immediately. If not, the provider will return an ack message to the consumer communicating that the slash packet could not be handled, and needs to be sent again in the future (retried)."),(0,i.kt)("p",null,"VSCMatured packets will always be handled immediately upon being received by the provider."),(0,i.kt)("p",null,"Note ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"spec"),". Specifically the section on ",(0,i.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order"),". Previously the onus was on the provider to maintain this property via queuing packets and handling them FIFO."),(0,i.kt)("p",null,"Now this property will be maintained by the consumer sending packets in the correct order, and blocking the sending of VSCMatured packets as needed. Then, the ordered IBC channel will ensure that Slash/VSCMatured packets are received in the correct order on the provider."),(0,i.kt)("p",null,"The provider's main responsibility regarding throttling will now be to determine if a recv slash packet can be handled via slash meter etc., and appropriately ack to the sending consumer."),(0,i.kt)("h3",{id:"why-the-provider-can-handle-vscmatured-packets-immediately"},"Why the provider can handle VSCMatured packets immediately"),(0,i.kt)("p",null,"First we answer, what does a VSCMatured packet communicate to the provider? A VSCMatured packet communicates that a VSC has been applied to a consumer long enough that infractions committed on the consumer could have been submitted."),(0,i.kt)("p",null,"If the consumer is following the queuing/blocking protocol described. No bad behavior occurs, ",(0,i.kt)("inlineCode",{parentName:"p"},"VSC Maturity and Slashing Order")," property is maintained."),(0,i.kt)("p",null,"If a consumer sends VSCMatured packets too leniently: The consumer is malicious and sending duplicate vsc matured packets, or sending the packets sooner than the ccv protocol specifies. In this scenario, the provider needs to handle vsc matured packets immediately to prevent DOS, state bloat, or other issues. The only possible negative outcome is that the malicious consumer may not be able to jail a validator who should have been jailed. The malicious behavior only creates a negative outcome for the chain that is being malicious."),(0,i.kt)("p",null,"If a consumer blocks the sending of VSCMatured packets: The consumer is malicious and blocking vsc matured packets that should have been sent. This will block unbonding only up until the VSC timeout period has elapsed. At that time, the consumer is removed. Again the malicious behavior only creates a negative outcome for the chain that is being malicious."),(0,i.kt)("h3",{id:"splitting-of-prs-and-upgrade-order"},"Splitting of PRs and Upgrade Order"),(0,i.kt)("p",null,"This feature will implement consumer changes in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1024"},"#1024"),'. Note these changes should be deployed to prod for all consumers before the provider changes are deployed to prod. That is the consumer changes in #1024 are compatible with the current ("v1") provider implementation of throttling that\'s running on the Cosmos Hub as of July 2023.'),(0,i.kt)("p",null,"Once all consumers have deployed the changes in #1024, the provider changes from (TBD) can be deployed to prod, fully enabling v2 throttling."),(0,i.kt)("h2",{id:"consequences"},"Consequences"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Consumers will now have to manage their own queues, and retry logic."),(0,i.kt)("li",{parentName:"ul"},"Consumers still aren't trustless, but the provider is now less susceptible to mismanaged or malicious consumers."),(0,i.kt)("li",{parentName:"ul"},'Recovering from the "jailing attack" is more elegant.'),(0,i.kt)("li",{parentName:"ul"},"Some issues like ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/1001"},"#1001")," will now be handled implicitly by the improved throttling mechanism."),(0,i.kt)("li",{parentName:"ul"},"Slash and vsc matured packets can be handled immediately once recv by the provider if the slash meter allows."),(0,i.kt)("li",{parentName:"ul"},"In general, we reduce the amount of computation that happens in the provider end-blocker.")),(0,i.kt)("h3",{id:"positive"},"Positive"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},'We no longer have to reason about a "global queue" and a "chain specific queue", and keeping those all in-sync. Now slash and vsc matured packet queuing is handled on each consumer individually.'),(0,i.kt)("li",{parentName:"ul"},"Due to the above, the throttling protocol becomes less complex overall."),(0,i.kt)("li",{parentName:"ul"},"We no longer have to worry about throttle related DoS attack on the provider, since no queuing exists on the provider.")),(0,i.kt)("h3",{id:"negative"},"Negative"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Increased number of IBC packets being relayed anytime throttling logic is triggered."),(0,i.kt)("li",{parentName:"ul"},"Consumer complexity increases, since consumers now have manage queuing themselves, and implement packet retry logic.")),(0,i.kt)("h3",{id:"neutral"},"Neutral"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Core throttling logic on the provider remains unchanged, ie. slash meter, replenishment cycles, etc.")),(0,i.kt)("h2",{id:"references"},"References"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/713"},"EPIC")," tracking the changes proposed by this ADR"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/interchain-security/legacy/v3.2.0/adrs/adr-002-throttle"},"ADR 002: Jail Throttling")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/594"},"#594"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/c57e97ca.bb70d7e1.js b/legacy/assets/js/c57e97ca.bb70d7e1.js new file mode 100644 index 0000000000..66094d0a69 --- /dev/null +++ b/legacy/assets/js/c57e97ca.bb70d7e1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5731],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var i=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,i,r=function(e,t){if(null==e)return{};var n,i,r={},o=Object.keys(e);for(i=0;i<o.length;i++)n=o[i],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i<o.length;i++)n=o[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=i.createContext({}),d=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=d(e.components);return i.createElement(l.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},m=i.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),c=d(n),m=r,h=c["".concat(l,".").concat(m)]||c[m]||u[m]||o;return n?i.createElement(h,a(a({ref:t},p),{},{components:n})):i.createElement(h,a({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,a=new Array(o);a[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:r,a[1]=s;for(var d=2;d<o;d++)a[d]=n[d];return i.createElement.apply(null,a)}return i.createElement.apply(null,n)}m.displayName="MDXCreateElement"},9177:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var i=n(7462),r=(n(7294),n(3905));const o={sidebar_position:3},a="Interchain Security Parameters",s={unversionedId:"introduction/params",id:"version-v2.4.0-lsm/introduction/params",title:"Interchain Security Parameters",description:"The parameters necessary for Interchain Security (ICS) are defined in",source:"@site/versioned_docs/version-v2.4.0-lsm/introduction/params.md",sourceDirName:"introduction",slug:"/introduction/params",permalink:"/interchain-security/legacy/v2.4.0-lsm/introduction/params",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Terminology",permalink:"/interchain-security/legacy/v2.4.0-lsm/introduction/terminology"},next:{title:"Technical Specification",permalink:"/interchain-security/legacy/v2.4.0-lsm/introduction/technical-specification"}},l={},d=[{value:"Time-based parameters",id:"time-based-parameters",level:2},{value:"ProviderUnbondingPeriod",id:"providerunbondingperiod",level:3},{value:"ConsumerUnbondingPeriod",id:"consumerunbondingperiod",level:3},{value:"TrustingPeriodFraction",id:"trustingperiodfraction",level:3},{value:"CCVTimeoutPeriod",id:"ccvtimeoutperiod",level:3},{value:"InitTimeoutPeriod",id:"inittimeoutperiod",level:3},{value:"<code>VscTimeoutPeriod</code>",id:"vsctimeoutperiod",level:3},{value:"BlocksPerDistributionTransmission",id:"blocksperdistributiontransmission",level:3},{value:"TransferPeriodTimeout",id:"transferperiodtimeout",level:3},{value:"Slash Throttle Parameters",id:"slash-throttle-parameters",level:2},{value:"SlashMeterReplenishPeriod",id:"slashmeterreplenishperiod",level:3},{value:"SlashMeterReplenishFraction",id:"slashmeterreplenishfraction",level:3},{value:"MaxThrottledPackets",id:"maxthrottledpackets",level:3}],p={toc:d},c="wrapper";function u(e){let{components:t,...n}=e;return(0,r.kt)(c,(0,i.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"interchain-security-parameters"},"Interchain Security Parameters"),(0,r.kt)("p",null,"The parameters necessary for Interchain Security (ICS) are defined in "),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"the ",(0,r.kt)("inlineCode",{parentName:"li"},"Params")," structure in ",(0,r.kt)("inlineCode",{parentName:"li"},"proto/interchain_security/ccv/provider/v1/provider.proto")," for the provider;"),(0,r.kt)("li",{parentName:"ul"},"the ",(0,r.kt)("inlineCode",{parentName:"li"},"Params")," structure in ",(0,r.kt)("inlineCode",{parentName:"li"},"proto/interchain_security/ccv/consumer/v1/consumer.proto")," for the consumer.")),(0,r.kt)("h2",{id:"time-based-parameters"},"Time-based parameters"),(0,r.kt)("p",null,"ICS relies on the following time-based parameters."),(0,r.kt)("h3",{id:"providerunbondingperiod"},"ProviderUnbondingPeriod"),(0,r.kt)("p",null,"is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance."),(0,r.kt)("h3",{id:"consumerunbondingperiod"},"ConsumerUnbondingPeriod"),(0,r.kt)("p",null,"is the unbonding period on the consumer chain."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerUnbondingPeriod")," is set via the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," governance proposal to add a new consumer chain.\nIt is recommended that every consumer chain set and unbonding period shorter than ",(0,r.kt)("inlineCode",{parentName:"p"},"ProviderUnbondingPeriod")),(0,r.kt)("br",null),(0,r.kt)("p",{parentName:"admonition"},"Example:"),(0,r.kt)("pre",{parentName:"admonition"},(0,r.kt)("code",{parentName:"pre"},"ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day\n"))),(0,r.kt)("p",null,"Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer."),(0,r.kt)("h3",{id:"trustingperiodfraction"},"TrustingPeriodFraction"),(0,r.kt)("p",null,"is used to calculate the ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriod")," of created IBC clients on both provider and consumer chains. "),(0,r.kt)("p",null,"Setting ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriodFraction")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"0.5")," would result in the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"TrustingPeriodFraction = 0.5\nProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5\nConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5\n")),(0,r.kt)("p",null,"Note that a light clients must be updated within the ",(0,r.kt)("inlineCode",{parentName:"p"},"TrustingPeriod")," in order to avoid being frozen."),(0,r.kt)("p",null,"For more details, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/client/ics-007-tendermint-client/README.md"},"IBC specification of Tendermint clients"),"."),(0,r.kt)("h3",{id:"ccvtimeoutperiod"},"CCVTimeoutPeriod"),(0,r.kt)("p",null,"is the period used to compute the timeout timestamp when sending IBC packets. "),(0,r.kt)("p",null,"For more details, see the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/core/ics-004-channel-and-packet-semantics/README.md#sending-packets"},"IBC specification of Channel & Packet Semantics"),"."),(0,r.kt)("admonition",{type:"warning"},(0,r.kt)("p",{parentName:"admonition"},"If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed.")),(0,r.kt)("p",null,"CCVTimeoutPeriod may have different values on the provider and consumer chains."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"CCVTimeoutPeriod")," on the provider ",(0,r.kt)("strong",{parentName:"li"},"must")," be larger than ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerUnbondingPeriod")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"CCVTimeoutPeriod")," on the consumer is initial set via the ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal"))),(0,r.kt)("h3",{id:"inittimeoutperiod"},"InitTimeoutPeriod"),(0,r.kt)("p",null,"is the maximum allowed duration for CCV channel initialization to execute."),(0,r.kt)("p",null,"For any consumer chain, if the CCV channel is not established within ",(0,r.kt)("inlineCode",{parentName:"p"},"InitTimeoutPeriod")," then the consumer chain will be removed and therefore will not be secured by the provider chain."),(0,r.kt)("p",null,"The countdown starts when the ",(0,r.kt)("inlineCode",{parentName:"p"},"spawn_time")," specified in the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," is reached."),(0,r.kt)("h3",{id:"vsctimeoutperiod"},(0,r.kt)("inlineCode",{parentName:"h3"},"VscTimeoutPeriod")),(0,r.kt)("p",null,"is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live.\nIf the ",(0,r.kt)("inlineCode",{parentName:"p"},"VscTimeoutPeriod")," is ever reached for a consumer chain that chain will be considered not live and removed from interchain security."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"VscTimeoutPeriod")," MUST be larger than the ",(0,r.kt)("inlineCode",{parentName:"p"},"ConsumerUnbondingPeriod"),".")),(0,r.kt)("h3",{id:"blocksperdistributiontransmission"},"BlocksPerDistributionTransmission"),(0,r.kt)("p",null,"is the number of blocks between rewards transfers from the consumer to the provider."),(0,r.kt)("h3",{id:"transferperiodtimeout"},"TransferPeriodTimeout"),(0,r.kt)("p",null,"is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider."),(0,r.kt)("p",null,"If this timeout expires, then the transfer is attempted again after ",(0,r.kt)("inlineCode",{parentName:"p"},"BlocksPerDistributionTransmission")," blocks."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"TransferPeriodTimeout")," on the consumer is initial set via the ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal")," gov proposal to add the consumer"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"TransferPeriodTimeout")," should be smaller than ",(0,r.kt)("inlineCode",{parentName:"li"},"BlocksPerDistributionTransmission x avg_block_time"))),(0,r.kt)("h2",{id:"slash-throttle-parameters"},"Slash Throttle Parameters"),(0,r.kt)("h3",{id:"slashmeterreplenishperiod"},"SlashMeterReplenishPeriod"),(0,r.kt)("p",null,"exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed."),(0,r.kt)("p",null,"The meter is replenished to an amount equal to the slash meter allowance for that block, or ",(0,r.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction * CurrentTotalVotingPower"),"."),(0,r.kt)("h3",{id:"slashmeterreplenishfraction"},"SlashMeterReplenishFraction"),(0,r.kt)("p",null,"exists on the provider as the portion (in range ","[0, 1]",") of total voting power that is replenished to the slash meter when a replenishment occurs."),(0,r.kt)("p",null,"This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a ",(0,r.kt)("inlineCode",{parentName:"p"},"sdk.Dec")," when used."),(0,r.kt)("h3",{id:"maxthrottledpackets"},"MaxThrottledPackets"),(0,r.kt)("p",null,"exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value."),(0,r.kt)("p",null,"This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/c5de07d7.9759b93a.js b/legacy/assets/js/c5de07d7.9759b93a.js new file mode 100644 index 0000000000..579aaf640d --- /dev/null +++ b/legacy/assets/js/c5de07d7.9759b93a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[74],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>m});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),h=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=h(e.components);return r.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),d=h(n),p=a,m=d["".concat(c,".").concat(p)]||d[p]||u[p]||o;return n?r.createElement(m,i(i({ref:t},l),{},{components:n})):r.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=p;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:a,i[1]=s;for(var h=2;h<o;h++)i[h]=n[h];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}p.displayName="MDXCreateElement"},6584:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>h});var r=n(7462),a=(n(7294),n(3905));const o={sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},i=void 0,s={unversionedId:"frequently-asked-questions",id:"version-v3.2.0/frequently-asked-questions",title:"Frequently Asked Questions",description:"What is the meaning of Validator Set Replication?",source:"@site/versioned_docs/version-v3.2.0/frequently-asked-questions.md",sourceDirName:".",slug:"/faq",permalink:"/interchain-security/legacy/v3.2.0/faq",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:5,frontMatter:{sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},sidebar:"tutorialSidebar",previous:{title:"Joining Stride",permalink:"/interchain-security/legacy/v3.2.0/validators/joining-stride"},next:{title:"ADRs",permalink:"/interchain-security/legacy/v3.2.0/adrs/intro"}},c={},h=[{value:"What is the meaning of Validator Set Replication?",id:"what-is-the-meaning-of-validator-set-replication",level:2},{value:"What is a consumer chain?",id:"what-is-a-consumer-chain",level:2},{value:"What happens to consumer if provider is down?",id:"what-happens-to-consumer-if-provider-is-down",level:2},{value:"What happens to provider if consumer is down?",id:"what-happens-to-provider-if-consumer-is-down",level:2},{value:"Can I run the provider and consumer chains on the same machine?",id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine",level:2},{value:"Can the consumer chain have its own token?",id:"can-the-consumer-chain-have-its-own-token",level:2},{value:"How are Tx fees paid on consumer?",id:"how-are-tx-fees-paid-on-consumer",level:2},{value:"Are there any restrictions the consumer chains need to abide by?",id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by",level:2},{value:"What's in it for the validators and stakers?",id:"whats-in-it-for-the-validators-and-stakers",level:2},{value:"Can the consumer chain have its own governance?",id:"can-the-consumer-chain-have-its-own-governance",level:2},{value:"Can validators opt-out of replicated security?",id:"can-validators-opt-out-of-replicated-security",level:2},{value:"How does Equivocation Governance Slashing work?",id:"how-does-equivocation-governance-slashing-work",level:2},{value:"Can Consumer Chains perform Software Upgrades?",id:"can-consumer-chains-perform-software-upgrades",level:2},{value:"How can I connect to the testnets?",id:"how-can-i-connect-to-the-testnets",level:2},{value:"How do I start using ICS?",id:"how-do-i-start-using-ics",level:2},{value:"Which relayers are supported?",id:"which-relayers-are-supported",level:2},{value:"How does key delegation work in ICS?",id:"how-does-key-delegation-work-in-ics",level:2}],l={toc:h},d="wrapper";function u(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"what-is-the-meaning-of-validator-set-replication"},"What is the meaning of Validator Set Replication?"),(0,a.kt)("p",null,"VSR simply means that the same validator set is used to secure both the provider and consumer chains. VSR is ensured through ICS protocol which keeps consumers up to date with the validator set of the provider."),(0,a.kt)("h2",{id:"what-is-a-consumer-chain"},"What is a consumer chain?"),(0,a.kt)("p",null,"Consumer chain is blockchain operated by the same validator operators as the provider chain. The ICS protocol ensures the validator set replication properties (informs consumer chain about the current state of the validator set on the provider)"),(0,a.kt)("p",null,"Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements."),(0,a.kt)("h2",{id:"what-happens-to-consumer-if-provider-is-down"},"What happens to consumer if provider is down?"),(0,a.kt)("p",null,"In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set."),(0,a.kt)("p",null,"The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness."),(0,a.kt)("p",null,"However, if the ",(0,a.kt)("inlineCode",{parentName:"p"},"trusting_period")," (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain.\nThis means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about."),(0,a.kt)("p",null,'Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point.\nAt the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.'),(0,a.kt)("h2",{id:"what-happens-to-provider-if-consumer-is-down"},"What happens to provider if consumer is down?"),(0,a.kt)("p",null,"Consumer chains do not impact the provider chain.\nThe ICS protocol is concerned only with validator set replication and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events)."),(0,a.kt)("h2",{id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine"},"Can I run the provider and consumer chains on the same machine?"),(0,a.kt)("p",null,"Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation."),(0,a.kt)("h2",{id:"can-the-consumer-chain-have-its-own-token"},"Can the consumer chain have its own token?"),(0,a.kt)("p",null,"As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees."),(0,a.kt)("h2",{id:"how-are-tx-fees-paid-on-consumer"},"How are Tx fees paid on consumer?"),(0,a.kt)("p",null,"The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations."),(0,a.kt)("h2",{id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by"},"Are there any restrictions the consumer chains need to abide by?"),(0,a.kt)("p",null,"No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way.\nThe only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain."),(0,a.kt)("h2",{id:"whats-in-it-for-the-validators-and-stakers"},"What's in it for the validators and stakers?"),(0,a.kt)("p",null,"The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by ",(0,a.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction"),". The rewards are distributed (sent to the provider) every ",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission"),"."),(0,a.kt)("admonition",{type:"note"},(0,a.kt)("p",{parentName:"admonition"}," ",(0,a.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission")," are parameters defined in the ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," used to create the consumer chain. These parameters can be changed via consumer chain governance.")),(0,a.kt)("h2",{id:"can-the-consumer-chain-have-its-own-governance"},"Can the consumer chain have its own governance?"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Yes.")),(0,a.kt)("p",null,'In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.'),(0,a.kt)("p",null,"Validators can also be representatives but representatives are not required to run validator nodes."),(0,a.kt)("p",null,"This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance."),(0,a.kt)("h2",{id:"can-validators-opt-out-of-replicated-security"},"Can validators opt-out of replicated security?"),(0,a.kt)("p",null,"At present, the validators cannot opt-out of validating consumer chains."),(0,a.kt)("p",null,"There are multiple opt-out mechanisms under active research."),(0,a.kt)("h2",{id:"how-does-equivocation-governance-slashing-work"},"How does Equivocation Governance Slashing work?"),(0,a.kt)("p",null,"To avoid potential attacks directed at provider chain validators, a new mechanism was introduced:"),(0,a.kt)("p",null,"When a validator double-signs on the consumer chain, a special type of slash packet is relayed to the provider chain. The provider will store information about the double signing validator and allow a governance proposal to be submitted.\nIf the double-signing proposal passes, the offending validator will be slashed on the provider chain and tombstoned. Tombstoning will permanently exclude the validator from the active set of the provider."),(0,a.kt)("admonition",{type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"An equivocation proposal cannot be submitted for a validator that did not double sign on any of the consumer chains.")),(0,a.kt)("h2",{id:"can-consumer-chains-perform-software-upgrades"},"Can Consumer Chains perform Software Upgrades?"),(0,a.kt)("p",null,"Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM)."),(0,a.kt)("p",null,"Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module."),(0,a.kt)("h2",{id:"how-can-i-connect-to-the-testnets"},"How can I connect to the testnets?"),(0,a.kt)("p",null,"Check out the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.2.0/validators/joining-testnet"},"Joining Replicated Security testnet")," section."),(0,a.kt)("h2",{id:"how-do-i-start-using-ics"},"How do I start using ICS?"),(0,a.kt)("p",null,"To become a consumer chain use this ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.2.0/consumer-development/onboarding"},"checklist")," and check the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.2.0/consumer-development/app-integration"},"App integration section")),(0,a.kt)("h2",{id:"which-relayers-are-supported"},"Which relayers are supported?"),(0,a.kt)("p",null,"Currently supported versions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Hermes 1.4.1"),(0,a.kt)("li",{parentName:"ul"},"Support for the CCV module was added to the Go ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/relayer"},"relayer")," in v2.2.0 but v2.4.0 has significant performance fixes which makes it the earliest suggested version to use.")),(0,a.kt)("h2",{id:"how-does-key-delegation-work-in-ics"},"How does key delegation work in ICS?"),(0,a.kt)("p",null,"You can check the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.2.0/features/key-assignment"},"Key Assignment Guide")," for specific instructions."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/c880b3c7.b3d9e09c.js b/legacy/assets/js/c880b3c7.b3d9e09c.js new file mode 100644 index 0000000000..875c84f03e --- /dev/null +++ b/legacy/assets/js/c880b3c7.b3d9e09c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1564],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>y});var i=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,i)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){n(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,i,n=function(e,t){if(null==e)return{};var r,i,n={},o=Object.keys(e);for(i=0;i<o.length;i++)r=o[i],t.indexOf(r)>=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i<o.length;i++)r=o[i],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=i.createContext({}),l=function(e){var t=i.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},u=function(e){var t=l(e.components);return i.createElement(s.Provider,{value:t},e.children)},h="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},p=i.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),h=l(r),p=n,y=h["".concat(s,".").concat(p)]||h[p]||d[p]||o;return r?i.createElement(y,a(a({ref:t},u),{},{components:r})):i.createElement(y,a({ref:t},u))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,a=new Array(o);a[0]=p;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[h]="string"==typeof e?e:n,a[1]=c;for(var l=2;l<o;l++)a[l]=r[l];return i.createElement.apply(null,a)}return i.createElement.apply(null,r)}p.displayName="MDXCreateElement"},2610:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>d,frontMatter:()=>o,metadata:()=>c,toc:()=>l});var i=r(7462),n=(r(7294),r(3905));const o={sidebar_position:2},a="Terminology",c={unversionedId:"introduction/terminology",id:"version-v3.3.0/introduction/terminology",title:"Terminology",description:"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.",source:"@site/versioned_docs/version-v3.3.0/introduction/terminology.md",sourceDirName:"introduction",slug:"/introduction/terminology",permalink:"/interchain-security/legacy/v3.3.0/introduction/terminology",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/legacy/v3.3.0/introduction/overview"},next:{title:"Interchain Security Parameters",permalink:"/interchain-security/legacy/v3.3.0/introduction/params"}},s={},l=[{value:"Shared Security",id:"shared-security",level:2},{value:"Interchain Security",id:"interchain-security",level:2},{value:"Replicated Security",id:"replicated-security",level:2},{value:"Mesh security",id:"mesh-security",level:2},{value:"Consumer Chain",id:"consumer-chain",level:2},{value:"Standalone Chain",id:"standalone-chain",level:2},{value:"Changeover Procedure",id:"changeover-procedure",level:2}],u={toc:l},h="wrapper";function d(e){let{components:t,...r}=e;return(0,n.kt)(h,(0,i.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"terminology"},"Terminology"),(0,n.kt)("p",null,"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions."),(0,n.kt)("h2",{id:"shared-security"},"Shared Security"),(0,n.kt)("p",null,"Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share its proof-of-stake security with another blockchain or off-chain process."),(0,n.kt)("h2",{id:"interchain-security"},"Interchain Security"),(0,n.kt)("p",null,"Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC."),(0,n.kt)("h2",{id:"replicated-security"},"Replicated Security"),(0,n.kt)("p",null,'A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC. Note this documentation is focused on explaining the concepts from replicated security.'),(0,n.kt)("h2",{id:"mesh-security"},"Mesh security"),(0,n.kt)("p",null,"A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see ",(0,n.kt)("a",{parentName:"p",href:"https://informal.systems/blog/replicated-vs-mesh-security"},"Replicated vs. Mesh Security on the Informal Blog"),"."),(0,n.kt)("h2",{id:"consumer-chain"},"Consumer Chain"),(0,n.kt)("p",null,"Chain that is secured by the validator set of the provider, instead of its own.\nReplicated security allows the provider chain validator set to validate blocks on the consumer chain."),(0,n.kt)("h2",{id:"standalone-chain"},"Standalone Chain"),(0,n.kt)("p",null,"Chain that is secured by its own validator set. This chain does not participate in replicated security."),(0,n.kt)("p",null,'Standalone chains may sometimes be called "sovereign" - the terms are synonymous.'),(0,n.kt)("h2",{id:"changeover-procedure"},"Changeover Procedure"),(0,n.kt)("p",null,"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the ",(0,n.kt)("strong",{parentName:"p"},"changeover procedure")," and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/c99bfd69.92afb3d3.js b/legacy/assets/js/c99bfd69.92afb3d3.js new file mode 100644 index 0000000000..33738ebbc9 --- /dev/null +++ b/legacy/assets/js/c99bfd69.92afb3d3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3631],{3905:(e,n,t)=>{t.d(n,{Zo:()=>c,kt:()=>m});var o=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function r(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?i(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,o,a=function(e,n){if(null==e)return{};var t,o,a={},i=Object.keys(e);for(o=0;o<i.length;o++)t=i[o],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)t=i[o],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=o.createContext({}),p=function(e){var n=o.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):r(r({},n),e)),t},c=function(e){var n=p(e.components);return o.createElement(l.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},h=o.forwardRef((function(e,n){var t=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=p(t),h=a,m=d["".concat(l,".").concat(h)]||d[h]||u[h]||i;return t?o.createElement(m,r(r({ref:n},c),{},{components:t})):o.createElement(m,r({ref:n},c))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var i=t.length,r=new Array(i);r[0]=h;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:a,r[1]=s;for(var p=2;p<i;p++)r[p]=t[p];return o.createElement.apply(null,r)}return o.createElement.apply(null,t)}h.displayName="MDXCreateElement"},5137:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>r,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>p});var o=t(7462),a=(t(7294),t(3905));const i={sidebar_position:3},r="ICS Provider Proposals",s={unversionedId:"features/proposals",id:"version-v3.1.0/features/proposals",title:"ICS Provider Proposals",description:"Interchain security module introduces 3 new proposal types to the provider.",source:"@site/versioned_docs/version-v3.1.0/features/proposals.md",sourceDirName:"features",slug:"/features/proposals",permalink:"/interchain-security/legacy/v3.1.0/features/proposals",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Reward distribution",permalink:"/interchain-security/legacy/v3.1.0/features/reward-distribution"},next:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/legacy/v3.1.0/features/slashing"}},l={},p=[{value:"<code>ConsumerAdditionProposal</code>",id:"consumeradditionproposal",level:2},{value:"<code>ConsumerRemovalProposal</code>",id:"consumerremovalproposal",level:2},{value:"<code>EquivocationProposal</code>",id:"equivocationproposal",level:2},{value:"Notes",id:"notes",level:3},{value:"Gaia example:",id:"gaia-example",level:3}],c={toc:p},d="wrapper";function u(e){let{components:n,...t}=e;return(0,a.kt)(d,(0,o.Z)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"ics-provider-proposals"},"ICS Provider Proposals"),(0,a.kt)("p",null,"Interchain security module introduces 3 new proposal types to the provider."),(0,a.kt)("p",null,"The proposals are used to propose upcoming interchain security events through governance."),(0,a.kt)("h2",{id:"consumeradditionproposal"},(0,a.kt)("inlineCode",{parentName:"h2"},"ConsumerAdditionProposal")),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"If you are preparing a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," you can find more information in the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.1.0/consumer-development/onboarding"},"consumer onboarding checklist"),".")),(0,a.kt)("p",null,"Proposal type used to suggest adding a new consumer chain."),(0,a.kt)("p",null,"When proposals of this type are passed and the ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain."),(0,a.kt)("p",null,"Minimal example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'{\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n "title": "Add consumer chain",\n "description": ".md description of your chain and all other relevant information",\n "chain_id": "newchain-1",\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Unbonding period for the consumer chain.\n // It should should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n "transfer_timeout_period": 1800000000000,\n "consumer_redistribution_fraction": "0.75",\n "blocks_per_distribution_transmission": 1000,\n "historical_entries": 10000,\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1"\n // relevant for chains performing a sovereign to consumer changeover\n // in order to maintan the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123"\n}\n')),(0,a.kt)("p",null,"More examples can be found in the replicated security testnet repository ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/baryon-1/proposal-baryon-1.json"},"here")," and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/noble-1/start-proposal-noble-1.json"},"here"),"."),(0,a.kt)("h2",{id:"consumerremovalproposal"},(0,a.kt)("inlineCode",{parentName:"h2"},"ConsumerRemovalProposal")),(0,a.kt)("p",null,"Proposal type used to suggest removing an existing consumer chain."),(0,a.kt)("p",null,"When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain.\nAfter the consumer chain removal, the chain in question will no longer be secured by the provider's validator set."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain.\nAdditional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set.\nMore information will be made available in the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.1.0/consumer-development/offboarding"},"Consumer Offboarding Checklist"),".")),(0,a.kt)("p",null,"Minimal example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'{\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details"\n}\n')),(0,a.kt)("h2",{id:"equivocationproposal"},(0,a.kt)("inlineCode",{parentName:"h2"},"EquivocationProposal")),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},(0,a.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," will only be accepted on the provider chain if at least one of the consumer chains submits equivocation evidence to the provider.\nSending equivocation evidence to the provider is handled automatically by the interchain security protocol when an equivocation infraction is detected on the consumer chain.")),(0,a.kt)("p",null,"Proposal type used to suggest slashing a validator for double signing on consumer chain.\nWhen proposals of this type are passed, the validator in question will be slashed for equivocation on the provider chain."),(0,a.kt)("admonition",{type:"warning"},(0,a.kt)("p",{parentName:"admonition"},"Take note that an equivocation slash causes a validator to be tombstoned (can never re-enter the active set).\nTombstoning a validator on the provider chain will remove the validator from the validator set of all consumer chains.")),(0,a.kt)("p",null,"Minimal example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'{\n "title": "Validator-1 double signed on consumerchain-1",\n "description": "Here is more information about the infraction so you can verify it yourself",\n // the list of equivocations that will be processed\n "equivocations": [\n {\n "height": 14444680,\n "time": "2023-02-28T20:40:00.000000Z",\n "power": 5500000,\n "consensus_address": "<consensus address ON THE PROVIDER>"\n }\n ]\n}\n')),(0,a.kt)("h3",{id:"notes"},"Notes"),(0,a.kt)("p",null,"When submitting equivocation evidence through an ",(0,a.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," please take note that you need to use the consensus address (",(0,a.kt)("inlineCode",{parentName:"p"},"valcons"),") of the offending validator on the ",(0,a.kt)("strong",{parentName:"p"},"provider chain"),".\nBesides that, the ",(0,a.kt)("inlineCode",{parentName:"p"},"height")," and the ",(0,a.kt)("inlineCode",{parentName:"p"},"time")," fields should be mapped to the ",(0,a.kt)("strong",{parentName:"p"},"provider chain")," to avoid your evidence being rejected."),(0,a.kt)("p",null,"Before submitting the proposal please check that the evidence is not outdated by comparing the infraction height with the ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_duration")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks")," consensus parameters of the ",(0,a.kt)("strong",{parentName:"p"},"provider chain"),"."),(0,a.kt)("h3",{id:"gaia-example"},"Gaia example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'\u279c ~ cat genesis.json | jq ".consensus_params"\n{\n "block": {\n ...\n },\n "evidence": {\n "max_age_duration": "172800000000000",\n "max_age_num_blocks": "1000000",\n "max_bytes": "50000"\n },\n "validator": {\n ...\n },\n "version": {}\n}\n')),(0,a.kt)("p",null,"Any ",(0,a.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," transactions that submit evidence with ",(0,a.kt)("inlineCode",{parentName:"p"},"height")," older than ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"time")," older than ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_duration")," will be considered invalid."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/c9ae8e5c.765b1dd1.js b/legacy/assets/js/c9ae8e5c.765b1dd1.js new file mode 100644 index 0000000000..734c360b3e --- /dev/null +++ b/legacy/assets/js/c9ae8e5c.765b1dd1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7428],{3905:(e,t,r)=>{r.d(t,{Zo:()=>l,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},l=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),p=u(r),f=o,m=p["".concat(s,".").concat(f)]||p[f]||d[f]||i;return r?n.createElement(m,a(a({ref:t},l),{},{components:r})):n.createElement(m,a({ref:t},l))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[p]="string"==typeof e?e:o,a[1]=c;for(var u=2;u<i;u++)a[u]=r[u];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},4482:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>d,frontMatter:()=>i,metadata:()=>c,toc:()=>u});var n=r(7462),o=(r(7294),r(3905));const i={sidebar_position:5},a="Joining Neutron",c={unversionedId:"validators/joining-neutron",id:"version-v3.2.0/validators/joining-neutron",title:"Joining Neutron",description:"Neutron is the first consumer chain to implement ICS.",source:"@site/versioned_docs/version-v3.2.0/validators/joining-neutron.md",sourceDirName:"validators",slug:"/validators/joining-neutron",permalink:"/interchain-security/legacy/v3.2.0/validators/joining-neutron",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Validator instructions for Changeover Procedure",permalink:"/interchain-security/legacy/v3.2.0/validators/changeover-procedure"},next:{title:"Joining Stride",permalink:"/interchain-security/legacy/v3.2.0/validators/joining-stride"}},s={},u=[{value:"Resources",id:"resources",level:2}],l={toc:u},p="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(p,(0,n.Z)({},l,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"joining-neutron"},"Joining Neutron"),(0,o.kt)("p",null,"Neutron is the first consumer chain to implement ICS."),(0,o.kt)("p",null,"You can find instructions on joining the mainnet ",(0,o.kt)("a",{parentName:"p",href:"https://docs.neutron.org/neutron/consumer-chain-launch"},"here"),"."),(0,o.kt)("p",null,"To join Neutron chain on the replicated security testnet check ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security/pion-1"},"here")),(0,o.kt)("h2",{id:"resources"},"Resources"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.neutron.org"},"Neutron docs"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/ccd1c519.e31286c5.js b/legacy/assets/js/ccd1c519.e31286c5.js new file mode 100644 index 0000000000..189dbd178b --- /dev/null +++ b/legacy/assets/js/ccd1c519.e31286c5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4115],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>v});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,r=function(e,t){if(null==e)return{};var n,o,r={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=o.createContext({}),l=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},d=function(e){var t=l(e.components);return o.createElement(c.Provider,{value:t},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,v=u["".concat(c,".").concat(h)]||u[h]||p[h]||i;return n?o.createElement(v,a(a({ref:t},d),{},{components:n})):o.createElement(v,a({ref:t},d))}));function v(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:r,a[1]=s;for(var l=2;l<i;l++)a[l]=n[l];return o.createElement.apply(null,a)}return o.createElement.apply(null,n)}h.displayName="MDXCreateElement"},9610:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var o=n(7462),r=(n(7294),n(3905));const i={sidebar_position:1},a="Overview",s={unversionedId:"introduction/overview",id:"version-v3.2.0/introduction/overview",title:"Overview",description:"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.",source:"@site/versioned_docs/version-v3.2.0/introduction/overview.md",sourceDirName:"introduction",slug:"/introduction/overview",permalink:"/interchain-security/legacy/v3.2.0/introduction/overview",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Docs",permalink:"/interchain-security/legacy/v3.2.0/"},next:{title:"Terminology",permalink:"/interchain-security/legacy/v3.2.0/introduction/terminology"}},c={},l=[{value:"Why Replicated Security?",id:"why-replicated-security",level:2},{value:"Core protocol",id:"core-protocol",level:2},{value:"Downtime Slashing",id:"downtime-slashing",level:3},{value:"Equivocation (Double Sign) Slashing",id:"equivocation-double-sign-slashing",level:3},{value:"Tokenomics and Rewards",id:"tokenomics-and-rewards",level:3}],d={toc:l},u="wrapper";function p(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"overview"},"Overview"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another."),(0,r.kt)("br",null),'Replicated security allows anyone to launch a "consumer" blockchain using the same validator set as the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit the full security and decentralization of the provider.'),(0,r.kt)("h2",{id:"why-replicated-security"},"Why Replicated Security?"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Full provider security. At launch, consumer chains are secured by the full validator set and market cap of the provider chain."),(0,r.kt)("li",{parentName:"ul"},"Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum."),(0,r.kt)("li",{parentName:"ul"},"Projects keep majority of gas fees. Depending on configuration, these fees either go to the project\u2019s community DAO, or can be used in the protocol in other ways."),(0,r.kt)("li",{parentName:"ul"},"No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. A governance vote will take place for a chain to get adopted by the provider validators which will encourage participation and signal strong buy-in into the project's long-term success."),(0,r.kt)("li",{parentName:"ul"},"Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set.")),(0,r.kt)("h2",{id:"core-protocol"},"Core protocol"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Protocol specification is available as ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md"},"ICS-028")," in the IBC repository.")),(0,r.kt)("p",null,"Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer."),(0,r.kt)("p",null,"To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider."),(0,r.kt)("h3",{id:"downtime-slashing"},"Downtime Slashing"),(0,r.kt)("p",null,"If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period."),(0,r.kt)("h3",{id:"equivocation-double-sign-slashing"},"Equivocation (Double Sign) Slashing"),(0,r.kt)("p",null,"Evidence of equivocation must be submitted to provider governance and be voted on. This behavior is an extra safeguard before a validator is slashed, and may be replaced by a more automated system in the future."),(0,r.kt)("h3",{id:"tokenomics-and-rewards"},"Tokenomics and Rewards"),(0,r.kt)("p",null,"Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/cdc1959e.fecc2b5f.js b/legacy/assets/js/cdc1959e.fecc2b5f.js new file mode 100644 index 0000000000..249efc73e6 --- /dev/null +++ b/legacy/assets/js/cdc1959e.fecc2b5f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6986],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>m});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),h=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=h(e.components);return r.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),d=h(n),p=a,m=d["".concat(c,".").concat(p)]||d[p]||u[p]||o;return n?r.createElement(m,i(i({ref:t},l),{},{components:n})):r.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=p;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:a,i[1]=s;for(var h=2;h<o;h++)i[h]=n[h];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}p.displayName="MDXCreateElement"},2875:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>h});var r=n(7462),a=(n(7294),n(3905));const o={sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},i=void 0,s={unversionedId:"frequently-asked-questions",id:"version-v3.3.1-lsm/frequently-asked-questions",title:"Frequently Asked Questions",description:"What is the meaning of Validator Set Replication?",source:"@site/versioned_docs/version-v3.3.1-lsm/frequently-asked-questions.md",sourceDirName:".",slug:"/faq",permalink:"/interchain-security/legacy/faq",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:5,frontMatter:{sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},sidebar:"tutorialSidebar",previous:{title:"Joining Stride",permalink:"/interchain-security/legacy/validators/joining-stride"},next:{title:"ADRs",permalink:"/interchain-security/legacy/adrs/intro"}},c={},h=[{value:"What is the meaning of Validator Set Replication?",id:"what-is-the-meaning-of-validator-set-replication",level:2},{value:"What is a consumer chain?",id:"what-is-a-consumer-chain",level:2},{value:"What happens to consumer if provider is down?",id:"what-happens-to-consumer-if-provider-is-down",level:2},{value:"What happens to provider if consumer is down?",id:"what-happens-to-provider-if-consumer-is-down",level:2},{value:"Can I run the provider and consumer chains on the same machine?",id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine",level:2},{value:"Can the consumer chain have its own token?",id:"can-the-consumer-chain-have-its-own-token",level:2},{value:"How are Tx fees paid on consumer?",id:"how-are-tx-fees-paid-on-consumer",level:2},{value:"Are there any restrictions the consumer chains need to abide by?",id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by",level:2},{value:"What's in it for the validators and stakers?",id:"whats-in-it-for-the-validators-and-stakers",level:2},{value:"Can the consumer chain have its own governance?",id:"can-the-consumer-chain-have-its-own-governance",level:2},{value:"Can validators opt-out of replicated security?",id:"can-validators-opt-out-of-replicated-security",level:2},{value:"How does Equivocation Governance Slashing work?",id:"how-does-equivocation-governance-slashing-work",level:2},{value:"Can Consumer Chains perform Software Upgrades?",id:"can-consumer-chains-perform-software-upgrades",level:2},{value:"How can I connect to the testnets?",id:"how-can-i-connect-to-the-testnets",level:2},{value:"How do I start using ICS?",id:"how-do-i-start-using-ics",level:2},{value:"Which relayers are supported?",id:"which-relayers-are-supported",level:2},{value:"How does key delegation work in ICS?",id:"how-does-key-delegation-work-in-ics",level:2}],l={toc:h},d="wrapper";function u(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"what-is-the-meaning-of-validator-set-replication"},"What is the meaning of Validator Set Replication?"),(0,a.kt)("p",null,"VSR simply means that the same validator set is used to secure both the provider and consumer chains. VSR is ensured through ICS protocol which keeps consumers up to date with the validator set of the provider."),(0,a.kt)("h2",{id:"what-is-a-consumer-chain"},"What is a consumer chain?"),(0,a.kt)("p",null,"Consumer chain is blockchain operated by the same validator operators as the provider chain. The ICS protocol ensures the validator set replication properties (informs consumer chain about the current state of the validator set on the provider)"),(0,a.kt)("p",null,"Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements."),(0,a.kt)("h2",{id:"what-happens-to-consumer-if-provider-is-down"},"What happens to consumer if provider is down?"),(0,a.kt)("p",null,"In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set."),(0,a.kt)("p",null,"The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness."),(0,a.kt)("p",null,"However, if the ",(0,a.kt)("inlineCode",{parentName:"p"},"trusting_period")," (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain.\nThis means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about."),(0,a.kt)("p",null,'Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point.\nAt the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.'),(0,a.kt)("h2",{id:"what-happens-to-provider-if-consumer-is-down"},"What happens to provider if consumer is down?"),(0,a.kt)("p",null,"Consumer chains do not impact the provider chain.\nThe ICS protocol is concerned only with validator set replication and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events)."),(0,a.kt)("h2",{id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine"},"Can I run the provider and consumer chains on the same machine?"),(0,a.kt)("p",null,"Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation."),(0,a.kt)("h2",{id:"can-the-consumer-chain-have-its-own-token"},"Can the consumer chain have its own token?"),(0,a.kt)("p",null,"As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees."),(0,a.kt)("h2",{id:"how-are-tx-fees-paid-on-consumer"},"How are Tx fees paid on consumer?"),(0,a.kt)("p",null,"The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations."),(0,a.kt)("h2",{id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by"},"Are there any restrictions the consumer chains need to abide by?"),(0,a.kt)("p",null,"No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way.\nThe only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain."),(0,a.kt)("h2",{id:"whats-in-it-for-the-validators-and-stakers"},"What's in it for the validators and stakers?"),(0,a.kt)("p",null,"The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by ",(0,a.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction"),". The rewards are distributed (sent to the provider) every ",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission"),"."),(0,a.kt)("admonition",{type:"note"},(0,a.kt)("p",{parentName:"admonition"}," ",(0,a.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission")," are parameters defined in the ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," used to create the consumer chain. These parameters can be changed via consumer chain governance.")),(0,a.kt)("h2",{id:"can-the-consumer-chain-have-its-own-governance"},"Can the consumer chain have its own governance?"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Yes.")),(0,a.kt)("p",null,'In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.'),(0,a.kt)("p",null,"Validators can also be representatives but representatives are not required to run validator nodes."),(0,a.kt)("p",null,"This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance."),(0,a.kt)("h2",{id:"can-validators-opt-out-of-replicated-security"},"Can validators opt-out of replicated security?"),(0,a.kt)("p",null,"At present, the validators cannot opt-out of validating consumer chains."),(0,a.kt)("p",null,"There are multiple opt-out mechanisms under active research."),(0,a.kt)("h2",{id:"how-does-equivocation-governance-slashing-work"},"How does Equivocation Governance Slashing work?"),(0,a.kt)("p",null,"To avoid potential attacks directed at provider chain validators, a new mechanism was introduced:"),(0,a.kt)("p",null,"When a validator double-signs on the consumer chain, a special type of slash packet is relayed to the provider chain. The provider will store information about the double signing validator and allow a governance proposal to be submitted.\nIf the double-signing proposal passes, the offending validator will be slashed on the provider chain and tombstoned. Tombstoning will permanently exclude the validator from the active set of the provider."),(0,a.kt)("admonition",{type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"An equivocation proposal cannot be submitted for a validator that did not double sign on any of the consumer chains.")),(0,a.kt)("h2",{id:"can-consumer-chains-perform-software-upgrades"},"Can Consumer Chains perform Software Upgrades?"),(0,a.kt)("p",null,"Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM)."),(0,a.kt)("p",null,"Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module."),(0,a.kt)("h2",{id:"how-can-i-connect-to-the-testnets"},"How can I connect to the testnets?"),(0,a.kt)("p",null,"Check out the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/validators/joining-testnet"},"Joining Replicated Security testnet")," section."),(0,a.kt)("h2",{id:"how-do-i-start-using-ics"},"How do I start using ICS?"),(0,a.kt)("p",null,"To become a consumer chain use this ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/onboarding"},"checklist")," and check the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/app-integration"},"App integration section")),(0,a.kt)("h2",{id:"which-relayers-are-supported"},"Which relayers are supported?"),(0,a.kt)("p",null,"Currently supported versions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Hermes 1.4.1"),(0,a.kt)("li",{parentName:"ul"},"Support for the CCV module was added to the Go ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/relayer"},"relayer")," in v2.2.0 but v2.4.0 has significant performance fixes which makes it the earliest suggested version to use.")),(0,a.kt)("h2",{id:"how-does-key-delegation-work-in-ics"},"How does key delegation work in ICS?"),(0,a.kt)("p",null,"You can check the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/features/key-assignment"},"Key Assignment Guide")," for specific instructions."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/ceabb0b9.11d69bef.js b/legacy/assets/js/ceabb0b9.11d69bef.js new file mode 100644 index 0000000000..2e8eae8a1a --- /dev/null +++ b/legacy/assets/js/ceabb0b9.11d69bef.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6703],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>v});var i=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function r(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,i,o=function(e,n){if(null==e)return{};var t,i,o={},a=Object.keys(e);for(i=0;i<a.length;i++)t=a[i],n.indexOf(t)>=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i<a.length;i++)t=a[i],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=i.createContext({}),u=function(e){var n=i.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):r(r({},n),e)),t},p=function(e){var n=u(e.components);return i.createElement(l.Provider,{value:n},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},h=i.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=u(t),h=o,v=d["".concat(l,".").concat(h)]||d[h]||c[h]||a;return t?i.createElement(v,r(r({ref:n},p),{},{components:t})):i.createElement(v,r({ref:n},p))}));function v(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,r=new Array(a);r[0]=h;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:o,r[1]=s;for(var u=2;u<a;u++)r[u]=t[u];return i.createElement.apply(null,r)}return i.createElement.apply(null,t)}h.displayName="MDXCreateElement"},9585:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>r,default:()=>c,frontMatter:()=>a,metadata:()=>s,toc:()=>u});var i=t(7462),o=(t(7294),t(3905));const a={sidebar_position:2,title:"ADR Template"},r="ADR 007: Pause validator unbonding during equivocation proposal",s={unversionedId:"adrs/adr-007-pause-unbonding-on-eqv-prop",id:"version-v3.3.1-lsm/adrs/adr-007-pause-unbonding-on-eqv-prop",title:"ADR Template",description:"Changelog",source:"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-007-pause-unbonding-on-eqv-prop.md",sourceDirName:"adrs",slug:"/adrs/adr-007-pause-unbonding-on-eqv-prop",permalink:"/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"ADR Template"},sidebar:"tutorialSidebar",previous:{title:"ADRs",permalink:"/interchain-security/legacy/adrs/intro"},next:{title:"ADR Template",permalink:"/interchain-security/legacy/adrs/adr-template"}},l={},u=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"How",id:"how",level:3},{value:"When pause",id:"when-pause",level:3},{value:"When unpause",id:"when-unpause",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],p={toc:u},d="wrapper";function c(e){let{components:n,...t}=e;return(0,o.kt)(d,(0,i.Z)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"adr-007-pause-validator-unbonding-during-equivocation-proposal"},"ADR 007: Pause validator unbonding during equivocation proposal"),(0,o.kt)("h2",{id:"changelog"},"Changelog"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"2023-05-16: Initial Draft")),(0,o.kt)("h2",{id:"status"},"Status"),(0,o.kt)("p",null,"Proposed"),(0,o.kt)("h2",{id:"context"},"Context"),(0,o.kt)("p",null,"Currently, if an equivocation slashing proposal is created after more than one\nweek has passed since the equivocation, it is possible that the validator in\nquestion could unbond and get away without being slashed, since the unbonding\nperiod is 3 weeks, and the voting period is 2 weeks. For this reason, it might\nbe good to pause unbondings for validators named in an equivocation slashing\nproposal until the proposal's voting period is over."),(0,o.kt)("h2",{id:"decision"},"Decision"),(0,o.kt)("h3",{id:"how"},"How"),(0,o.kt)("p",null,"Pausing the unbonding period is already possible thanks to the changes in the\n",(0,o.kt)("inlineCode",{parentName:"p"},"staking")," module of the cosmos-sdk:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"stakingKeeper.PutUnbondingOnHold")," pauses an unbonding period"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"stakingKeeper.UnbondingCanComplete")," unpauses an unbonding period")),(0,o.kt)("p",null,"These methods use a reference counter under the hood, that gets incremented\nevery time ",(0,o.kt)("inlineCode",{parentName:"p"},"PutUnbondingOnHold")," is called, and decreased when\n",(0,o.kt)("inlineCode",{parentName:"p"},"UnbondingCanComplete")," is called instead. A specific unbonding is considered\nfully unpaused when its underlying reference counter reaches 0. Therefore, as\nlong as we safeguard consistency - i.e. we make sure we eventually decrement\nthe reference counter for each time we have incremented it - we can safely use\nthis existing mechanism without conflicts with the ",(0,o.kt)("em",{parentName:"p"},"Completion of Unbonding\nOperations")," system."),(0,o.kt)("h3",{id:"when-pause"},"When pause"),(0,o.kt)("p",null,"The unbonding period (if there is any unbonding) should be paused once an\nequivocation proposal enters the voting period. For that, the ",(0,o.kt)("inlineCode",{parentName:"p"},"gov")," module's\nhook ",(0,o.kt)("inlineCode",{parentName:"p"},"AfterProposalDeposit")," can be used. "),(0,o.kt)("p",null,"If the hook is triggered with a an equivocation proposal in voting period, then\nfor each equivocation of the proposal, the unbonding operations of the related\nvalidator that were initiated after the equivocation block time must be paused"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"i.e. the underlying reference counter has to be increased.")),(0,o.kt)("p",null,"Note that even after the voting period has started, a proposal can receive\nadditional deposits. The hook is triggered however at arrival of a deposit, so\na check to verify that the proposal is not already in voting period is\nrequired."),(0,o.kt)("h3",{id:"when-unpause"},"When unpause"),(0,o.kt)("p",null,"We can use a ",(0,o.kt)("inlineCode",{parentName:"p"},"gov")," module's hook also here and it is\n",(0,o.kt)("inlineCode",{parentName:"p"},"AfterProposalVotingPeriodEnded"),"."),(0,o.kt)("p",null,"If the hook is triggered with an equivocation proposal, then for each\nassociated equivocation, the unbonding operations of the related validator that\nwere initiated between the equivocation block time and the start of the\nproposal voting period must be unpaused - i.e. decrease the underlying\nreference counter - regardless of the proposal outcome."),(0,o.kt)("h2",{id:"consequences"},"Consequences"),(0,o.kt)("h3",{id:"positive"},"Positive"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Validators subject to an equivocation proposal cannot finish unbonding\ntheir tokens before the end of the voting period.")),(0,o.kt)("h3",{id:"negative"},"Negative"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"A malicious consumer chain could forge slash packets enabling submission of\nan equivocation proposal on the provider chain, resulting in the freezing of\nvalidator's unbondings for an undeterminated amount of time."),(0,o.kt)("li",{parentName:"ul"},"Misbehavior on a consumer chain can potentially go unpunished, if no one\nsubmits an equivocation proposal in time, or if the proposal doesn't pass.")),(0,o.kt)("h3",{id:"neutral"},"Neutral"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"This feature can't be used for social slashing, because an equivocation\nproposal is only accepted if there's a slash log for the related\nvalidator(s), meaning the consumer chain has reported the equivocation to\nthe provider chain.")),(0,o.kt)("h2",{id:"references"},"References"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/747"},"https://github.com/cosmos/interchain-security/issues/747")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/791"},"https://github.com/cosmos/interchain-security/pull/791"))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/cf411473.6073d7f0.js b/legacy/assets/js/cf411473.6073d7f0.js new file mode 100644 index 0000000000..e72faf4eac --- /dev/null +++ b/legacy/assets/js/cf411473.6073d7f0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3153],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>y});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?c(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):c(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function a(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},c=Object.keys(e);for(r=0;r<c.length;r++)n=c[r],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(r=0;r<c.length;r++)n=c[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var p=r.createContext({}),s=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},l=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,c=e.originalType,p=e.parentName,l=a(e,["components","mdxType","originalType","parentName"]),u=s(n),d=i,y=u["".concat(p,".").concat(d)]||u[d]||f[d]||c;return n?r.createElement(y,o(o({ref:t},l),{},{components:n})):r.createElement(y,o({ref:t},l))}));function y(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var c=n.length,o=new Array(c);o[0]=d;var a={};for(var p in t)hasOwnProperty.call(t,p)&&(a[p]=t[p]);a.originalType=e,a[u]="string"==typeof e?e:i,o[1]=a;for(var s=2;s<c;s++)o[s]=n[s];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},2021:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>f,frontMatter:()=>c,metadata:()=>a,toc:()=>s});var r=n(7462),i=(n(7294),n(3905));const c={sidebar_position:4},o="Technical Specification",a={unversionedId:"introduction/technical-specification",id:"introduction/technical-specification",title:"Technical Specification",description:"For a technical deep dive into the replicated security protocol, see the specification.",source:"@site/docs/introduction/technical-specification.md",sourceDirName:"introduction",slug:"/introduction/technical-specification",permalink:"/interchain-security/legacy/introduction/technical-specification",draft:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Parameters",permalink:"/interchain-security/legacy/introduction/params"},next:{title:"Key Assignment",permalink:"/interchain-security/legacy/features/key-assignment"}},p={},s=[],l={toc:s},u="wrapper";function f(e){let{components:t,...n}=e;return(0,i.kt)(u,(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"technical-specification"},"Technical Specification"),(0,i.kt)("p",null,"For a technical deep dive into the replicated security protocol, see the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/README.md"},"specification"),"."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/d0d0ba0d.1e2f89a5.js b/legacy/assets/js/d0d0ba0d.1e2f89a5.js new file mode 100644 index 0000000000..3d02ced2c3 --- /dev/null +++ b/legacy/assets/js/d0d0ba0d.1e2f89a5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8772],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},d=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},h="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},p=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),h=c(n),p=r,m=h["".concat(l,".").concat(p)]||h[p]||u[p]||o;return n?a.createElement(m,s(s({ref:t},d),{},{components:n})):a.createElement(m,s({ref:t},d))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,s=new Array(o);s[0]=p;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[h]="string"==typeof e?e:r,s[1]=i;for(var c=2;c<o;c++)s[c]=n[c];return a.createElement.apply(null,s)}return a.createElement.apply(null,n)}p.displayName="MDXCreateElement"},6843:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>c});var a=n(7462),r=(n(7294),n(3905));const o={sidebar_position:11,title:"Standalone to Consumer Changeover"},s=void 0,i={unversionedId:"adrs/adr-010-standalone-changeover",id:"adrs/adr-010-standalone-changeover",title:"Standalone to Consumer Changeover",description:"ADR 010: Standalone to Consumer Changeover",source:"@site/docs/adrs/adr-010-standalone-changeover.md",sourceDirName:"adrs",slug:"/adrs/adr-010-standalone-changeover",permalink:"/interchain-security/legacy/adrs/adr-010-standalone-changeover",draft:!1,tags:[],version:"current",sidebarPosition:11,frontMatter:{sidebar_position:11,title:"Standalone to Consumer Changeover"},sidebar:"tutorialSidebar",previous:{title:"Soft Opt-Out",permalink:"/interchain-security/legacy/adrs/adr-009-soft-opt-out"},next:{title:"Improving testing and increasing confidence",permalink:"/interchain-security/legacy/adrs/adr-011-improving-test-confidence"}},l={},c=[{value:"ADR 010: Standalone to Consumer Changeover",id:"adr-010-standalone-to-consumer-changeover",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Process",id:"process",level:3},{value:"Changes to CCV Protocol",id:"changes-to-ccv-protocol",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}],d={toc:c},h="wrapper";function u(e){let{components:t,...n}=e;return(0,r.kt)(h,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"adr-010-standalone-to-consumer-changeover"},"ADR 010: Standalone to Consumer Changeover"),(0,r.kt)("h2",{id:"changelog"},"Changelog"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"6/30/23: Feature completed, first draft of ADR.")),(0,r.kt)("h2",{id:"status"},"Status"),(0,r.kt)("p",null,"Implemented"),(0,r.kt)("h2",{id:"context"},"Context"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/Stride-Labs/stride"},"Stride"),' will be the first consumer to "changeover" from a standalone cosmos blockchain, to a consumer chain secured by the Cosmos Hub. This document will outline the changes made to the replicated security protocol to support this changeover process.'),(0,r.kt)("h2",{id:"decision"},"Decision"),(0,r.kt)("h3",{id:"process"},"Process"),(0,r.kt)("p",null,'Prior to the changeover, the consumer chain will have an existing staking keeper and validator set, these may be referred to as the "standalone staking keeper" and "standalone validator set" respectively. '),(0,r.kt)("p",null,"The first step in the changeover process is to submit a ConsumerAdditionProposal. If the proposal passes, the provider will create a new IBC client for the consumer at spawn time, with the provider's validator set. A consumer genesis will also be constructed by the provider for validators to query. Within this consumer genesis contains the initial validator set for the consumer to apply after the changeover."),(0,r.kt)("p",null,"Next, the standalone consumer chain runs an upgrade which adds the CCV module, and is properly setup to execute changeover logic."),(0,r.kt)("p",null,"The consumer upgrade height must be reached after the provider has created the new IBC client. Any replicated security validators who will run the consumer, but are not a part of the sovereign validator set, must sync up a full node before the consumer upgrade height is reached. The disc state of said full node will be used to run the consumer chain after the changeover has completed."),(0,r.kt)("p",null,"The meat of the changeover logic is that the consumer chain validator set is updated to that which was specified by the provider via the queried consumer genesis. Validators which were a part of the old set, but not the new set, are given zero voting power. Once these validator updates are given to Comet, the set is committed, and in effect 2 blocks later (see ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/x/ccv/consumer/keeper/changeover.go#L19"},"FirstConsumerHeight"),")."),(0,r.kt)("p",null,"A relayer then establishes the new IBC connection between the provider and consumer. The CCV channel handshake is started on top of this connection. Once the CCV channel is established and VSC packets are being relayed, the consumer chain is secured by the provider."),(0,r.kt)("h3",{id:"changes-to-ccv-protocol"},"Changes to CCV Protocol"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Consumer Genesis state is updated to include a ",(0,r.kt)("inlineCode",{parentName:"li"},"PreCCV")," boolean. When this boolean is set true in the consumer genesis JSON, ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/x/ccv/consumer/keeper/changeover.go"},"special logic")," is executed on InitGenesis to trigger the changeover process on the consumer's first endblocker after the upgrade which adds the CCV module. Note that InitGenesis is not automatically called during chain upgrades, so the consumer must manually call the consumer's InitGenesis method in an upgrade handler."),(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"ConsumerAdditionProposal")," type is updated to include a ",(0,r.kt)("inlineCode",{parentName:"li"},"DistributionTransmissionChannel")," field. This field allows the consumer to use an existing IBC transfer channel to send rewards as a part of the CCV protocol. Consumers that're not changing over from a standalone chain will leave this field blank, indicating that a new transfer channel should be created on top of the same connection as the CCV channel."),(0,r.kt)("li",{parentName:"ul"},"The CCV consumer keeper is updated to contain an optional reference to the standalone staking keeper. The standalone staking keeper is used to slash for infractions that happened before the changeover was completed. Ie. any infraction from a block height before the changeover, that is submitted after the changeover, will call the standalone staking keeper's slash method. Note that a changeover consumer's standalone staking keeper becomes a democracy module keeper, so it is possible for a governance token to be slashed.")),(0,r.kt)("h2",{id:"consequences"},"Consequences"),(0,r.kt)("h3",{id:"positive"},"Positive"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Existing cosmos chains are now able to onboard over to a consumer chain secured by a provider."),(0,r.kt)("li",{parentName:"ul"},"The previous staking keepers for such chains can be transitioned to democracy staking module keepers.")),(0,r.kt)("h3",{id:"negative"},"Negative"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"The delineation between different types of consumers in this repo becomes less clear. Ie. there is code in the ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/app/consumer-democracy/app.go"},"democracy consumer's app.go")," that only applies to a previously standalone chain, but that file also serves as the base for a normal democracy consumer launched with RS from genesis.")),(0,r.kt)("h2",{id:"references"},"References"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"EPIC: Standalone to Consumer Changeover ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/756"},"#756")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt"},"Changeover diagram from Stride"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/d1daeca6.9aed11ad.js b/legacy/assets/js/d1daeca6.9aed11ad.js new file mode 100644 index 0000000000..1fd0af8893 --- /dev/null +++ b/legacy/assets/js/d1daeca6.9aed11ad.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3845],{3905:(e,n,t)=>{t.d(n,{Zo:()=>d,kt:()=>h});var o=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?r(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):r(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,o,a=function(e,n){if(null==e)return{};var t,o,a={},r=Object.keys(e);for(o=0;o<r.length;o++)t=r[o],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o<r.length;o++)t=r[o],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=o.createContext({}),p=function(e){var n=o.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},d=function(e){var n=p(e.components);return o.createElement(l.Provider,{value:n},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},m=o.forwardRef((function(e,n){var t=e.components,a=e.mdxType,r=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),c=p(t),m=a,h=c["".concat(l,".").concat(m)]||c[m]||u[m]||r;return t?o.createElement(h,i(i({ref:n},d),{},{components:t})):o.createElement(h,i({ref:n},d))}));function h(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var r=t.length,i=new Array(r);i[0]=m;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[c]="string"==typeof e?e:a,i[1]=s;for(var p=2;p<r;p++)i[p]=t[p];return o.createElement.apply(null,i)}return o.createElement.apply(null,t)}m.displayName="MDXCreateElement"},9265:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>r,metadata:()=>s,toc:()=>p});var o=t(7462),a=(t(7294),t(3905));const r={sidebar_position:3},i="ICS Provider Proposals",s={unversionedId:"features/proposals",id:"features/proposals",title:"ICS Provider Proposals",description:"Interchain security module introduces 3 new proposal types to the provider.",source:"@site/docs/features/proposals.md",sourceDirName:"features",slug:"/features/proposals",permalink:"/interchain-security/legacy/features/proposals",draft:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Reward distribution",permalink:"/interchain-security/legacy/features/reward-distribution"},next:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/legacy/features/slashing"}},l={},p=[{value:"<code>ConsumerAdditionProposal</code>",id:"consumeradditionproposal",level:2},{value:"<code>ConsumerRemovalProposal</code>",id:"consumerremovalproposal",level:2},{value:"<code>EquivocationProposal</code>",id:"equivocationproposal",level:2},{value:"ChangeRewardDenomProposal",id:"changerewarddenomproposal",level:2},{value:"Notes",id:"notes",level:3},{value:"Gaia example:",id:"gaia-example",level:3}],d={toc:p},c="wrapper";function u(e){let{components:n,...t}=e;return(0,a.kt)(c,(0,o.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"ics-provider-proposals"},"ICS Provider Proposals"),(0,a.kt)("p",null,"Interchain security module introduces 3 new proposal types to the provider."),(0,a.kt)("p",null,"The proposals are used to propose upcoming interchain security events through governance."),(0,a.kt)("h2",{id:"consumeradditionproposal"},(0,a.kt)("inlineCode",{parentName:"h2"},"ConsumerAdditionProposal")),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"If you are preparing a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," you can find more information in the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/onboarding"},"consumer onboarding checklist"),".")),(0,a.kt)("p",null,"Proposal type used to suggest adding a new consumer chain."),(0,a.kt)("p",null,"When proposals of this type are passed and the ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain."),(0,a.kt)("p",null,"Minimal example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'{\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n "title": "Add consumer chain",\n "description": ".md description of your chain and all other relevant information",\n "chain_id": "newchain-1",\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Unbonding period for the consumer chain.\n // It should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n "transfer_timeout_period": 1800000000000,\n "consumer_redistribution_fraction": "0.75",\n "blocks_per_distribution_transmission": 1000,\n "historical_entries": 10000,\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1"\n // relevant for chains performing a sovereign to consumer changeover\n // in order to maintain the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123"\n}\n')),(0,a.kt)("p",null,"More examples can be found in the replicated security testnet repository ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/stopped/baryon-1/proposal-baryon-1.json"},"here")," and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/stopped/noble-1/start-proposal-noble-1.json"},"here"),"."),(0,a.kt)("h2",{id:"consumerremovalproposal"},(0,a.kt)("inlineCode",{parentName:"h2"},"ConsumerRemovalProposal")),(0,a.kt)("p",null,"Proposal type used to suggest removing an existing consumer chain."),(0,a.kt)("p",null,"When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain.\nAfter the consumer chain removal, the chain in question will no longer be secured by the provider's validator set."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain.\nAdditional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set.\nMore information will be made available in the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/offboarding"},"Consumer Offboarding Checklist"),".")),(0,a.kt)("p",null,"Minimal example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'{\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details"\n}\n')),(0,a.kt)("h2",{id:"equivocationproposal"},(0,a.kt)("inlineCode",{parentName:"h2"},"EquivocationProposal")),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},(0,a.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," will only be accepted on the provider chain if at least one of the consumer chains submits equivocation evidence to the provider.\nSending equivocation evidence to the provider is handled automatically by the interchain security protocol when an equivocation infraction is detected on the consumer chain.")),(0,a.kt)("p",null,"Proposal type used to suggest slashing a validator for double signing on consumer chain.\nWhen proposals of this type are passed, the validator in question will be slashed for equivocation on the provider chain."),(0,a.kt)("admonition",{type:"warning"},(0,a.kt)("p",{parentName:"admonition"},"Take note that an equivocation slash causes a validator to be tombstoned (can never re-enter the active set).\nTombstoning a validator on the provider chain will remove the validator from the validator set of all consumer chains.")),(0,a.kt)("p",null,"Minimal example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'{\n "title": "Validator-1 double signed on consumerchain-1",\n "description": "Here is more information about the infraction so you can verify it yourself",\n // the list of equivocations that will be processed\n "equivocations": [\n {\n "height": 14444680,\n "time": "2023-02-28T20:40:00.000000Z",\n "power": 5500000,\n "consensus_address": "<consensus address ON THE PROVIDER>"\n }\n ]\n}\n')),(0,a.kt)("h2",{id:"changerewarddenomproposal"},"ChangeRewardDenomProposal"),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},(0,a.kt)("inlineCode",{parentName:"p"},"ChangeRewardDenomProposal")," will only be accepted on the provider chain if at least one of the denomsToAdd or denomsToRemove fields is populated with at least one denom. Also, a denom cannot be repeated in both sets.")),(0,a.kt)("p",null,"Proposal type used to mutate the set of denoms accepted by the provider as rewards."),(0,a.kt)("p",null,"Minimal example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'{\n "title": "Add untrn as a reward denom",\n "description": "Here is more information about the proposal",\n "denomsToAdd": ["untrn"],\n "denomsToRemove": []\n}\n')),(0,a.kt)("h3",{id:"notes"},"Notes"),(0,a.kt)("p",null,"When submitting equivocation evidence through an ",(0,a.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," please take note that you need to use the consensus address (",(0,a.kt)("inlineCode",{parentName:"p"},"valcons"),") of the offending validator on the ",(0,a.kt)("strong",{parentName:"p"},"provider chain"),".\nBesides that, the ",(0,a.kt)("inlineCode",{parentName:"p"},"height")," and the ",(0,a.kt)("inlineCode",{parentName:"p"},"time")," fields should be mapped to the ",(0,a.kt)("strong",{parentName:"p"},"provider chain")," to avoid your evidence being rejected."),(0,a.kt)("p",null,"Before submitting the proposal please check that the evidence is not outdated by comparing the infraction height with the ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_duration")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks")," consensus parameters of the ",(0,a.kt)("strong",{parentName:"p"},"provider chain"),"."),(0,a.kt)("h3",{id:"gaia-example"},"Gaia example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'\u279c ~ cat genesis.json | jq ".consensus_params"\n{\n "block": {\n ...\n },\n "evidence": {\n "max_age_duration": "172800000000000",\n "max_age_num_blocks": "1000000",\n "max_bytes": "50000"\n },\n "validator": {\n ...\n },\n "version": {}\n}\n')),(0,a.kt)("p",null,"Any ",(0,a.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," transactions that submit evidence with ",(0,a.kt)("inlineCode",{parentName:"p"},"height")," older than ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"time")," older than ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_duration")," will be considered invalid."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/d21f9ede.ffa95316.js b/legacy/assets/js/d21f9ede.ffa95316.js new file mode 100644 index 0000000000..7615f6008e --- /dev/null +++ b/legacy/assets/js/d21f9ede.ffa95316.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4932],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=p(n),m=r,h=d["".concat(s,".").concat(m)]||d[m]||c[m]||i;return n?a.createElement(h,o(o({ref:t},u),{},{components:n})):a.createElement(h,o({ref:t},u))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:r,o[1]=l;for(var p=2;p<i;p++)o[p]=n[p];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},3035:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=n(7462),r=(n(7294),n(3905));const i={sidebar_position:13,title:"Separate Releasing"},o="ADR 012: Separate Releasing",l={unversionedId:"adrs/adr-012-separate-releasing",id:"adrs/adr-012-separate-releasing",title:"Separate Releasing",description:"Changelog",source:"@site/docs/adrs/adr-012-separate-releasing.md",sourceDirName:"adrs",slug:"/adrs/adr-012-separate-releasing",permalink:"/interchain-security/legacy/adrs/adr-012-separate-releasing",draft:!1,tags:[],version:"current",sidebarPosition:13,frontMatter:{sidebar_position:13,title:"Separate Releasing"},sidebar:"tutorialSidebar",previous:{title:"Improving testing and increasing confidence",permalink:"/interchain-security/legacy/adrs/adr-011-improving-test-confidence"},next:{title:"Slashing on the provider for consumer equivocation",permalink:"/interchain-security/legacy/adrs/adr-013-equivocation-slashing"}},s={},p=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Spike results",id:"spike-results",level:3},{value:"Why go.mod split is not the way to go",id:"why-gomod-split-is-not-the-way-to-go",level:3},{value:"Why separate repos is cool but also not the way to go",id:"why-separate-repos-is-cool-but-also-not-the-way-to-go",level:3},{value:"Decision",id:"decision",level:2},{value:"Example release flow",id:"example-release-flow",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],u={toc:p},d="wrapper";function c(e){let{components:t,...n}=e;return(0,r.kt)(d,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"adr-012-separate-releasing"},"ADR 012: Separate Releasing"),(0,r.kt)("h2",{id:"changelog"},"Changelog"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"{8/18/22}: Initial draft of idea in ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/801"},"#801")),(0,r.kt)("li",{parentName:"ul"},"{8/22/22}: Put idea in this ADR"),(0,r.kt)("li",{parentName:"ul"},"{11/10/22}: Reject this ADR")),(0,r.kt)("h2",{id:"status"},"Status"),(0,r.kt)("p",null,"Rejected"),(0,r.kt)("h2",{id:"context"},"Context"),(0,r.kt)("h3",{id:"spike-results"},"Spike results"),(0,r.kt)("p",null,"I explored the idea of ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/issues/801"},"#801")," with this ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/shawn%2Fgo-mod-split-aug-spike"},"spike branch"),". Here's my conclusions:"),(0,r.kt)("p",null,"Splitting this repo to have multiple go.mods is possible. However there are various intricacies involved in decoupling the package hierarchy to have ",(0,r.kt)("inlineCode",{parentName:"p"},"x/ccv/types")," as the lowest level dep, with ",(0,r.kt)("inlineCode",{parentName:"p"},"x/ccv/consumer")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"x/ccv/provider")," being one dep layer above, with high-level tests depending on all three of the mentioned packages. I'd estimate this decoupling would take 2-5 workdays to finish, and require significant review effort."),(0,r.kt)("h3",{id:"why-gomod-split-is-not-the-way-to-go"},"Why go.mod split is not the way to go"),(0,r.kt)("p",null,"Let's take a step back and remember the issue we're trying to solve - ",(0,r.kt)("strong",{parentName:"p"},"We need a clean way to decouple semver/releasing for the consumer and provider modules"),". After more consideration, splitting up go.mods gives us little benefit in achieving this. Reasons:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"go.mod")," dependency system is tied to git tags for the entire repo (ex: ",(0,r.kt)("inlineCode",{parentName:"li"},"require github.com/cometbft/cometbft v0.37.2")," refers to a historical tag for the entire cometbft repo)."),(0,r.kt)("li",{parentName:"ul"},"It'd be an odd dev experience to allow modules to reference past releases of other modules in the same repo. When would we ever want the consumer module to reference a past release of the types module for example?"),(0,r.kt)("li",{parentName:"ul"},"If we allow for ",(0,r.kt)("inlineCode",{parentName:"li"},"go.mod")," replace statements to build from local source code, why split up the package deps at all?"),(0,r.kt)("li",{parentName:"ul"},"Splitting go.mods adds a bunch of complexity with ",(0,r.kt)("inlineCode",{parentName:"li"},"go.work")," files and all that shiz. VSCode does not play well with multiple module repos either.")),(0,r.kt)("h3",{id:"why-separate-repos-is-cool-but-also-not-the-way-to-go"},"Why separate repos is cool but also not the way to go"),(0,r.kt)("p",null,"All this considered, the cleanest solution to decoupling semver/releasing for the consumer and provider modules would be to have multiple repos, each with their own go.mod (3-4 repos total including high level tests). With this scheme we could separately tag each repo as changes are merged, they could share some code from ",(0,r.kt)("inlineCode",{parentName:"p"},"types")," being an external dep, etc."),(0,r.kt)("p",null,"I don't think any of us want to split up the monorepo, that's a lot of work and seems like bikeshedding. There's another solution that's very simple.. "),(0,r.kt)("h2",{id:"decision"},"Decision"),(0,r.kt)("p",null,"Slightly adapting ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/cca008d856e3ffc60ec1a486871d0faa702abe26/CONTRIBUTING.md#semantic-versioning"},"the current semver ruleset"),":"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"A library API breaking change to EITHER the provider or consumer module will result in an increase of the MAJOR version number for BOTH modules (X.y.z-provider AND X.y.z-consumer)."),(0,r.kt)("li",{parentName:"ul"},"A state breaking change (change requiring coordinated upgrade and/or state migration) will result in an increase of the MINOR version number for the AFFECTED module(s) (x.Y.z-provider AND/OR x.Y.z-consumer)."),(0,r.kt)("li",{parentName:"ul"},"Any other changes (including node API breaking changes) will result in an increase of the PATCH version number for the AFFECTED module(s) (x.y.Z-provider AND/OR x.y.Z-consumer).")),(0,r.kt)("h3",{id:"example-release-flow"},"Example release flow"),(0,r.kt)("p",null,"We upgrade ",(0,r.kt)("inlineCode",{parentName:"p"},"main")," to use a new version of SDK. This is a major version bump, triggering a new release for both the provider and consumer modules, ",(0,r.kt)("inlineCode",{parentName:"p"},"v5.0.0-provider")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"v5.0.0-consumer"),"."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"A state breaking change is merged to ",(0,r.kt)("inlineCode",{parentName:"li"},"main")," for the provider module. We release only a ",(0,r.kt)("inlineCode",{parentName:"li"},"v5.1.0-provider")," off main."),(0,r.kt)("li",{parentName:"ul"},"Another state breaking change is merged to ",(0,r.kt)("inlineCode",{parentName:"li"},"main")," for the provider module. We release only a ",(0,r.kt)("inlineCode",{parentName:"li"},"v5.2.0-provider")," off main."),(0,r.kt)("li",{parentName:"ul"},"At this point, the latest consumer version is still ",(0,r.kt)("inlineCode",{parentName:"li"},"v5.0.0-consumer"),". We now merge a state breaking change for the consumer module to ",(0,r.kt)("inlineCode",{parentName:"li"},"main"),", and consequently release ",(0,r.kt)("inlineCode",{parentName:"li"},"v5.1.0-consumer"),". Note that ",(0,r.kt)("inlineCode",{parentName:"li"},"v5.1.0-consumer")," is tagged off a LATER commit from main than ",(0,r.kt)("inlineCode",{parentName:"li"},"v5.2.0-provider"),". This is fine, as the consumer module should not be affected by the provider module's state breaking changes."),(0,r.kt)("li",{parentName:"ul"},"Once either module sees a library API breaking change, we bump the major version for both modules. For example, we merge a library API breaking change to ",(0,r.kt)("inlineCode",{parentName:"li"},"main")," for the provider module. We release ",(0,r.kt)("inlineCode",{parentName:"li"},"v6.0.0-provider")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"v6.0.0-consumer")," off main. Note that most often, a library API breaking change will affect both modules simultaneously (example being bumping sdk version).")),(0,r.kt)("h2",{id:"consequences"},"Consequences"),(0,r.kt)("h3",{id:"positive"},"Positive"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Consumer repos have clear communication of what tagged versions are relevant to them. Consumer devs should know to never reference an ICS version that starts with ",(0,r.kt)("inlineCode",{parentName:"li"},"provider"),", even if it'd technically build."),(0,r.kt)("li",{parentName:"ul"},"Consumer and provider modules do not deviate as long as we continually release off a shared main branch. Backporting remains relatively unchanged besides being explicit about what module(s) your changes should affect."),(0,r.kt)("li",{parentName:"ul"},"No code changes, just changes in process. Very simple.")),(0,r.kt)("h3",{id:"negative"},"Negative"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("del",{parentName:"li"},"Slightly more complexity."),"Considerably more complex to manage the ICS library.\nThis is because ICS needs to support multiple versions of SDK (e.g., 0.45, 0.47, 0.50).\nIn addition, ICS needs to support a special fork of SDK (with LSM included) for the Cosmos Hub.\nThis means that instead of focusing on main the development team needs to manage multiple release\nbranches with different dependency trees. "),(0,r.kt)("li",{parentName:"ul"},"This solution does not allow having provider and consumer on separate versions of e.g. the Cosmos SDK.")),(0,r.kt)("h3",{id:"neutral"},"Neutral"),(0,r.kt)("h2",{id:"references"},"References"),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},"Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/801"},"#801")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/801#issuecomment-1683349298"},"#801 comment"))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/d262fdd7.67fecee7.js b/legacy/assets/js/d262fdd7.67fecee7.js new file mode 100644 index 0000000000..5ce356be82 --- /dev/null +++ b/legacy/assets/js/d262fdd7.67fecee7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3842],{3905:(e,n,t)=>{t.d(n,{Zo:()=>d,kt:()=>m});var i=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function a(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?r(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):r(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,i,o=function(e,n){if(null==e)return{};var t,i,o={},r=Object.keys(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var c=i.createContext({}),l=function(e){var n=i.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):a(a({},n),e)),t},d=function(e){var n=l(e.components);return i.createElement(c.Provider,{value:n},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},h=i.forwardRef((function(e,n){var t=e.components,o=e.mdxType,r=e.originalType,c=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),u=l(t),h=o,m=u["".concat(c,".").concat(h)]||u[h]||p[h]||r;return t?i.createElement(m,a(a({ref:n},d),{},{components:t})):i.createElement(m,a({ref:n},d))}));function m(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var r=t.length,a=new Array(r);a[0]=h;var s={};for(var c in n)hasOwnProperty.call(n,c)&&(s[c]=n[c]);s.originalType=e,s[u]="string"==typeof e?e:o,a[1]=s;for(var l=2;l<r;l++)a[l]=t[l];return i.createElement.apply(null,a)}return i.createElement.apply(null,t)}h.displayName="MDXCreateElement"},5461:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>p,frontMatter:()=>r,metadata:()=>s,toc:()=>l});var i=t(7462),o=(t(7294),t(3905));const r={sidebar_position:4},a="Consumer Initiated Slashing",s={unversionedId:"features/slashing",id:"version-v3.1.0/features/slashing",title:"Consumer Initiated Slashing",description:"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of it's own chain.",source:"@site/versioned_docs/version-v3.1.0/features/slashing.md",sourceDirName:"features",slug:"/features/slashing",permalink:"/interchain-security/legacy/v3.1.0/features/slashing",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"ICS Provider Proposals",permalink:"/interchain-security/legacy/v3.1.0/features/proposals"},next:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/legacy/v3.1.0/consumer-development/app-integration"}},c={},l=[{value:"Downtime infractions",id:"downtime-infractions",level:2},{value:"Double-signing (equivocation)",id:"double-signing-equivocation",level:2}],d={toc:l},u="wrapper";function p(e){let{components:n,...t}=e;return(0,o.kt)(u,(0,i.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-initiated-slashing"},"Consumer Initiated Slashing"),(0,o.kt)("p",null,"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of it's own chain.\nIn essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake)."),(0,o.kt)("p",null,"To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized.\nAny infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains."),(0,o.kt)("p",null,"In the current implementation there are 2 important changes brought by the interchain security module:"),(0,o.kt)("h2",{id:"downtime-infractions"},"Downtime infractions"),(0,o.kt)("p",null,"reported by consumer chains are acted upon on the provider as soon as the provider receives the infraction evidence."),(0,o.kt)("p",null,"Instead of slashing, the provider will only jail offending validator for the duration of time established in the chain parameters."),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Slash throttling (sometimes called jail throttling) mechanism insures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider.")),(0,o.kt)("h2",{id:"double-signing-equivocation"},"Double-signing (equivocation)"),(0,o.kt)("p",null,"infractions are not acted upon immediately."),(0,o.kt)("p",null,"Upon receiving double signing evidence, the provider chain will take note of the evidence and allow for ",(0,o.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," to be submitted to slash the offending validator.\nAny ",(0,o.kt)("inlineCode",{parentName:"p"},"EquivocationProposal"),"s to slash a validator that has not double signed on any of the consumer chains will be automatically rejected by the provider chain."),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"The offending validator will only be slashed (and tombstoned) if an ",(0,o.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," is accepted and passed through governance."),(0,o.kt)("p",{parentName:"admonition"},"The offending validator will effectively get slashed and tombstoned on all consumer chains.")),(0,o.kt)("p",null,"You can find instructions on creating ",(0,o.kt)("inlineCode",{parentName:"p"},"EquivocationProposal"),"s ",(0,o.kt)("a",{parentName:"p",href:"./proposals#equivocationproposal"},"here"),"."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/d411b146.4015c836.js b/legacy/assets/js/d411b146.4015c836.js new file mode 100644 index 0000000000..6c41702bcc --- /dev/null +++ b/legacy/assets/js/d411b146.4015c836.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1081],{3905:(e,n,t)=>{t.d(n,{Zo:()=>d,kt:()=>m});var i=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function a(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?r(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):r(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,i,o=function(e,n){if(null==e)return{};var t,i,o={},r=Object.keys(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var c=i.createContext({}),l=function(e){var n=i.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):a(a({},n),e)),t},d=function(e){var n=l(e.components);return i.createElement(c.Provider,{value:n},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},h=i.forwardRef((function(e,n){var t=e.components,o=e.mdxType,r=e.originalType,c=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),u=l(t),h=o,m=u["".concat(c,".").concat(h)]||u[h]||p[h]||r;return t?i.createElement(m,a(a({ref:n},d),{},{components:t})):i.createElement(m,a({ref:n},d))}));function m(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var r=t.length,a=new Array(r);a[0]=h;var s={};for(var c in n)hasOwnProperty.call(n,c)&&(s[c]=n[c]);s.originalType=e,s[u]="string"==typeof e?e:o,a[1]=s;for(var l=2;l<r;l++)a[l]=t[l];return i.createElement.apply(null,a)}return i.createElement.apply(null,t)}h.displayName="MDXCreateElement"},2086:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>p,frontMatter:()=>r,metadata:()=>s,toc:()=>l});var i=t(7462),o=(t(7294),t(3905));const r={sidebar_position:4},a="Consumer Initiated Slashing",s={unversionedId:"features/slashing",id:"version-v2.0.0/features/slashing",title:"Consumer Initiated Slashing",description:"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of it's own chain.",source:"@site/versioned_docs/version-v2.0.0/features/slashing.md",sourceDirName:"features",slug:"/features/slashing",permalink:"/interchain-security/legacy/v2.0.0/features/slashing",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"ICS Provider Proposals",permalink:"/interchain-security/legacy/v2.0.0/features/proposals"},next:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/legacy/v2.0.0/consumer-development/app-integration"}},c={},l=[{value:"Downtime infractions",id:"downtime-infractions",level:2},{value:"Double-signing (equivocation)",id:"double-signing-equivocation",level:2}],d={toc:l},u="wrapper";function p(e){let{components:n,...t}=e;return(0,o.kt)(u,(0,i.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-initiated-slashing"},"Consumer Initiated Slashing"),(0,o.kt)("p",null,"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of it's own chain.\nIn essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake)."),(0,o.kt)("p",null,"To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized.\nAny infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains."),(0,o.kt)("p",null,"In the current implementation there are 2 important changes brought by the interchain security module:"),(0,o.kt)("h2",{id:"downtime-infractions"},"Downtime infractions"),(0,o.kt)("p",null,"reported by consumer chains are acted upon on the provider as soon as the provider receives the infraction evidence."),(0,o.kt)("p",null,"Instead of slashing, the provider will only jail offending validator for the duration of time established in the chain parameters."),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Slash throttling (sometimes called jail throttling) mechanism insures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider.")),(0,o.kt)("h2",{id:"double-signing-equivocation"},"Double-signing (equivocation)"),(0,o.kt)("p",null,"infractions are not acted upon immediately."),(0,o.kt)("p",null,"Upon receiving double signing evidence, the provider chain will take note of the evidence and allow for ",(0,o.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," to be submitted to slash the offending validator.\nAny ",(0,o.kt)("inlineCode",{parentName:"p"},"EquivocationProposal"),"s to slash a validator that has not double signed on any of the consumer chains will be automatically rejected by the provider chain."),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"The offending validator will only be slashed (and tombstoned) if an ",(0,o.kt)("inlineCode",{parentName:"p"},"EquivocationProposal")," is accepted and passed through governance."),(0,o.kt)("p",{parentName:"admonition"},"The offending validator will effectively get slashed and tombstoned on all consumer chains.")),(0,o.kt)("p",null,"You can find instructions on creating ",(0,o.kt)("inlineCode",{parentName:"p"},"EquivocationProposal"),"s ",(0,o.kt)("a",{parentName:"p",href:"./proposals#equivocationproposal"},"here"),"."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/d4f67fc8.1e4b370d.js b/legacy/assets/js/d4f67fc8.1e4b370d.js new file mode 100644 index 0000000000..cdad88fd11 --- /dev/null +++ b/legacy/assets/js/d4f67fc8.1e4b370d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9980],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>d});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?c(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):c(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function a(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},c=Object.keys(e);for(r=0;r<c.length;r++)n=c[r],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(r=0;r<c.length;r++)n=c[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=r.createContext({}),l=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=l(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,c=e.originalType,s=e.parentName,p=a(e,["components","mdxType","originalType","parentName"]),u=l(n),m=i,d=u["".concat(s,".").concat(m)]||u[m]||f[m]||c;return n?r.createElement(d,o(o({ref:t},p),{},{components:n})):r.createElement(d,o({ref:t},p))}));function d(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var c=n.length,o=new Array(c);o[0]=m;var a={};for(var s in t)hasOwnProperty.call(t,s)&&(a[s]=t[s]);a.originalType=e,a[u]="string"==typeof e?e:i,o[1]=a;for(var l=2;l<c;l++)o[l]=n[l];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},2153:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>f,frontMatter:()=>c,metadata:()=>a,toc:()=>l});var r=n(7462),i=(n(7294),n(3905));const c={sidebar_position:4},o="Technical Specification",a={unversionedId:"introduction/technical-specification",id:"version-v2.4.0-lsm/introduction/technical-specification",title:"Technical Specification",description:"For a technical deep dive into the replicated security protocol, see the specification.",source:"@site/versioned_docs/version-v2.4.0-lsm/introduction/technical-specification.md",sourceDirName:"introduction",slug:"/introduction/technical-specification",permalink:"/interchain-security/legacy/v2.4.0-lsm/introduction/technical-specification",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Parameters",permalink:"/interchain-security/legacy/v2.4.0-lsm/introduction/params"},next:{title:"Key Assignment",permalink:"/interchain-security/legacy/v2.4.0-lsm/features/key-assignment"}},s={},l=[],p={toc:l},u="wrapper";function f(e){let{components:t,...n}=e;return(0,i.kt)(u,(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"technical-specification"},"Technical Specification"),(0,i.kt)("p",null,"For a technical deep dive into the replicated security protocol, see the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/README.md"},"specification"),"."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/d63ae50e.b2d5797e.js b/legacy/assets/js/d63ae50e.b2d5797e.js new file mode 100644 index 0000000000..1288e7d482 --- /dev/null +++ b/legacy/assets/js/d63ae50e.b2d5797e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6318],{3905:(e,r,t)=>{t.d(r,{Zo:()=>l,kt:()=>f});var n=t(7294);function i(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function o(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function a(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?o(Object(t),!0).forEach((function(r){i(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function s(e,r){if(null==e)return{};var t,n,i=function(e,r){if(null==e)return{};var t,n,i={},o=Object.keys(e);for(n=0;n<o.length;n++)t=o[n],r.indexOf(t)>=0||(i[t]=e[t]);return i}(e,r);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)t=o[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var d=n.createContext({}),c=function(e){var r=n.useContext(d),t=r;return e&&(t="function"==typeof e?e(r):a(a({},r),e)),t},l=function(e){var r=c(e.components);return n.createElement(d.Provider,{value:r},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},m=n.forwardRef((function(e,r){var t=e.components,i=e.mdxType,o=e.originalType,d=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=c(t),m=i,f=u["".concat(d,".").concat(m)]||u[m]||p[m]||o;return t?n.createElement(f,a(a({ref:r},l),{},{components:t})):n.createElement(f,a({ref:r},l))}));function f(e,r){var t=arguments,i=r&&r.mdxType;if("string"==typeof e||i){var o=t.length,a=new Array(o);a[0]=m;var s={};for(var d in r)hasOwnProperty.call(r,d)&&(s[d]=r[d]);s.originalType=e,s[u]="string"==typeof e?e:i,a[1]=s;for(var c=2;c<o;c++)a[c]=t[c];return n.createElement.apply(null,a)}return n.createElement.apply(null,t)}m.displayName="MDXCreateElement"},2045:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>d,contentTitle:()=>a,default:()=>p,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var n=t(7462),i=(t(7294),t(3905));const o={sidebar_position:2},a="Reward distribution",s={unversionedId:"features/reward-distribution",id:"version-v2.4.0-lsm/features/reward-distribution",title:"Reward distribution",description:"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.",source:"@site/versioned_docs/version-v2.4.0-lsm/features/reward-distribution.md",sourceDirName:"features",slug:"/features/reward-distribution",permalink:"/interchain-security/legacy/v2.4.0-lsm/features/reward-distribution",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/legacy/v2.4.0-lsm/features/key-assignment"},next:{title:"ICS Provider Proposals",permalink:"/interchain-security/legacy/v2.4.0-lsm/features/proposals"}},d={},c=[{value:"Parameters",id:"parameters",level:2},{value:"<code>consumer_redistribution_fraction</code>",id:"consumer_redistribution_fraction",level:3},{value:"<code>blocks_per_distribution_transmission</code>",id:"blocks_per_distribution_transmission",level:3},{value:"<code>transfer_timeout_period</code>",id:"transfer_timeout_period",level:3},{value:"<code>distribution_transmission_channel</code>",id:"distribution_transmission_channel",level:3},{value:"<code>provider_fee_pool_addr_str</code>",id:"provider_fee_pool_addr_str",level:3}],l={toc:c},u="wrapper";function p(e){let{components:r,...t}=e;return(0,i.kt)(u,(0,n.Z)({},l,t,{components:r,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"reward-distribution"},"Reward distribution"),(0,i.kt)("p",null,"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.\nIn replicated security block rewards and fees are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel that gets created during consumer chain initialization."),(0,i.kt)("p",null,"Reward distribution on the provider is handled by the distribution module - validators and delegators receive a fraction of the consumer chain tokens as staking rewards.\nThe distributed reward tokens are IBC tokens and therefore cannot be staked on the provider chain."),(0,i.kt)("p",null,"Sending and distributing rewards from consumer chains to provider chain is handled by the ",(0,i.kt)("inlineCode",{parentName:"p"},"Reward Distribution")," sub-protocol."),(0,i.kt)("h2",{id:"parameters"},"Parameters"),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"The following chain parameters dictate consumer chain distribution amount and frequency.\nThey are set at consumer genesis and ",(0,i.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction"),"\n",(0,i.kt)("inlineCode",{parentName:"p"},"transfer_timeout_period")," must be provided in every ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerChainAddition")," proposal.")),(0,i.kt)("h3",{id:"consumer_redistribution_fraction"},(0,i.kt)("inlineCode",{parentName:"h3"},"consumer_redistribution_fraction")),(0,i.kt)("p",null,'The fraction of tokens sent from consumer to provider during distribution events. The fraction is a string representing a decimal number. For example "0.75" would represent 75%.'),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"Example:"),(0,i.kt)("p",{parentName:"admonition"},"With ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction")," set to ",(0,i.kt)("inlineCode",{parentName:"p"},"0.75")," the consumer chain would send 75% of its block rewards and accumulated fees to the consumer chain and the remaining 25% to the provider chain every ",(0,i.kt)("inlineCode",{parentName:"p"},"n")," blocks where ",(0,i.kt)("inlineCode",{parentName:"p"},"n == blocks_per_distribution_transmission"),".")),(0,i.kt)("h3",{id:"blocks_per_distribution_transmission"},(0,i.kt)("inlineCode",{parentName:"h3"},"blocks_per_distribution_transmission")),(0,i.kt)("p",null,"The number of blocks between IBC token transfers from the consumer chain to the provider chain."),(0,i.kt)("h3",{id:"transfer_timeout_period"},(0,i.kt)("inlineCode",{parentName:"h3"},"transfer_timeout_period")),(0,i.kt)("p",null,"Timeout period for consumer chain reward distribution IBC packets."),(0,i.kt)("h3",{id:"distribution_transmission_channel"},(0,i.kt)("inlineCode",{parentName:"h3"},"distribution_transmission_channel")),(0,i.kt)("p",null,"Provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."),(0,i.kt)("h3",{id:"provider_fee_pool_addr_str"},(0,i.kt)("inlineCode",{parentName:"h3"},"provider_fee_pool_addr_str")),(0,i.kt)("p",null,"Provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/d67a6454.f96dac3e.js b/legacy/assets/js/d67a6454.f96dac3e.js new file mode 100644 index 0000000000..ef57eaec0b --- /dev/null +++ b/legacy/assets/js/d67a6454.f96dac3e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4738],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>m});var i=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,i)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?r(Object(a),!0).forEach((function(t){n(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):r(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function l(e,t){if(null==e)return{};var a,i,n=function(e,t){if(null==e)return{};var a,i,n={},r=Object.keys(e);for(i=0;i<r.length;i++)a=r[i],t.indexOf(a)>=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)a=r[i],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var s=i.createContext({}),h=function(e){var t=i.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},d=function(e){var t=h(e.components);return i.createElement(s.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},u=i.forwardRef((function(e,t){var a=e.components,n=e.mdxType,r=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=h(a),u=n,m=c["".concat(s,".").concat(u)]||c[u]||p[u]||r;return a?i.createElement(m,o(o({ref:t},d),{},{components:a})):i.createElement(m,o({ref:t},d))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=a.length,o=new Array(r);o[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:n,o[1]=l;for(var h=2;h<r;h++)o[h]=a[h];return i.createElement.apply(null,o)}return i.createElement.apply(null,a)}u.displayName="MDXCreateElement"},5266:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>p,frontMatter:()=>r,metadata:()=>l,toc:()=>h});var i=a(7462),n=(a(7294),a(3905));const r={sidebar_position:3,title:"Jail Throttling"},o="ADR 002: Jail Throttling",l={unversionedId:"adrs/adr-002-throttle",id:"version-v2.0.0/adrs/adr-002-throttle",title:"Jail Throttling",description:"Changelog",source:"@site/versioned_docs/version-v2.0.0/adrs/adr-002-throttle.md",sourceDirName:"adrs",slug:"/adrs/adr-002-throttle",permalink:"/interchain-security/legacy/v2.0.0/adrs/adr-002-throttle",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Jail Throttling"},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/legacy/v2.0.0/adrs/adr-001-key-assignment"},next:{title:"Equivocation governance proposal",permalink:"/interchain-security/legacy/v2.0.0/adrs/adr-003-equivocation-gov-proposal"}},s={},h=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"State Required - Slash Meter",id:"state-required---slash-meter",level:3},{value:"State Required - Global entry queue",id:"state-required---global-entry-queue",level:3},{value:"State Required - Per-chain data queue",id:"state-required---per-chain-data-queue",level:3},{value:"Reasoning - Multiple queues",id:"reasoning---multiple-queues",level:3},{value:"Protocol Overview - OnRecvSlashPacket",id:"protocol-overview---onrecvslashpacket",level:3},{value:"Protocol Overview - OnRecvVSCMaturedPacket",id:"protocol-overview---onrecvvscmaturedpacket",level:3},{value:"Endblocker Step 1 - Slash Meter Replenishment",id:"endblocker-step-1---slash-meter-replenishment",level:3},{value:"Endblocker Step 2 - HandleLeadingVSCMaturedPackets",id:"endblocker-step-2---handleleadingvscmaturedpackets",level:3},{value:"Endblocker Step 3 - HandleThrottleQueues",id:"endblocker-step-3---handlethrottlequeues",level:3},{value:"System Properties",id:"system-properties",level:3},{value:"Main Throttling Property",id:"main-throttling-property",level:3},{value:"How Unjailing Affects the Main Throttling Property",id:"how-unjailing-affects-the-main-throttling-property",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],d={toc:h},c="wrapper";function p(e){let{components:t,...a}=e;return(0,n.kt)(c,(0,i.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"adr-002-jail-throttling"},"ADR 002: Jail Throttling"),(0,n.kt)("h2",{id:"changelog"},"Changelog"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"2023-01-26: Initial Draft"),(0,n.kt)("li",{parentName:"ul"},"2023-02-07: Property refined, ADR ready to review/merge")),(0,n.kt)("h2",{id:"status"},"Status"),(0,n.kt)("p",null,"Accepted"),(0,n.kt)("h2",{id:"context"},"Context"),(0,n.kt)("p",null,"The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols. In practice, this assumption may not hold. A malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider."),(0,n.kt)("p",null,"Before the throttling feature was implemented, the following attack was possible. Attacker(s) would create provider validators just below the provider's active set. Using a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once. Control of the provider would then pass over to the attackers' validators. This enables the attacker(s) to halt the provider. Or even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC."),(0,n.kt)("h2",{id:"decision"},"Decision"),(0,n.kt)("p",null,"The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack. Ie. this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time."),(0,n.kt)("h3",{id:"state-required---slash-meter"},"State Required - Slash Meter"),(0,n.kt)("p",null,"There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time. This meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params."),(0,n.kt)("h3",{id:"state-required---global-entry-queue"},"State Required - Global entry queue"),(0,n.kt)("p",null,'There exists a single queue which stores "global slash entries". These entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering. This queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.'),(0,n.kt)("h3",{id:"state-required---per-chain-data-queue"},"State Required - Per-chain data queue"),(0,n.kt)("p",null,'For each established consumer, there exists a queue which stores "throttled packet data". Ie. pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering. Order is enforced by IBC sequence number. These "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.'),(0,n.kt)("h3",{id:"reasoning---multiple-queues"},"Reasoning - Multiple queues"),(0,n.kt)("p",null,"For reasoning on why this feature was implemented with multiple queues, see ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"spec"),". Specifically the section on ",(0,n.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order"),". There are other ways to ensure such a property (like a queue of linked lists, etc.), but the implemented protocol seemed to be the most understandable and easiest to implement with a KV store."),(0,n.kt)("h3",{id:"protocol-overview---onrecvslashpacket"},"Protocol Overview - OnRecvSlashPacket"),(0,n.kt)("p",null,"Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"A global slash entry is queued."),(0,n.kt)("li",{parentName:"ol"},"The data of such a packet is added to the per-chain queue.")),(0,n.kt)("h3",{id:"protocol-overview---onrecvvscmaturedpacket"},"Protocol Overview - OnRecvVSCMaturedPacket"),(0,n.kt)("p",null,"Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue."),(0,n.kt)("h3",{id:"endblocker-step-1---slash-meter-replenishment"},"Endblocker Step 1 - Slash Meter Replenishment"),(0,n.kt)("p",null,"Once the slash meter becomes not full, it'll be replenished after ",(0,n.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishPeriod (param)")," by incrementing the meter with its allowance for the replenishment block, where ",(0,n.kt)("inlineCode",{parentName:"p"},"allowance")," = ",(0,n.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction (param)")," * ",(0,n.kt)("inlineCode",{parentName:"p"},"currentTotalVotingPower"),". The slash meter will never exceed its current allowance (fn of the total voting power for the block) in value. Note a few things:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power. In such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods."),(0,n.kt)("li",{parentName:"ol"},"Total voting power of a chain changes over time, especially as validators are jailed. As validators are jailed, total voting power decreases, and so does the jailing allowance. See below for more detailed throttling property discussion."),(0,n.kt)("li",{parentName:"ol"},"The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1. If the ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction (param)")," is set too low, integer rounding will put this minimum value into effect. That is, if ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," * ",(0,n.kt)("inlineCode",{parentName:"li"},"currentTotalVotingPower")," < 1, then the effective allowance would be 1. This min value of allowance ensures that there's some packets handled over time, even if that is a very long time. It's a crude solution to an edge case caused by too small of a replenishment fraction.")),(0,n.kt)("p",null,"The behavior described above is achieved by executing ",(0,n.kt)("inlineCode",{parentName:"p"},"CheckForSlashMeterReplenishment()")," every endblock, BEFORE ",(0,n.kt)("inlineCode",{parentName:"p"},"HandleThrottleQueues()")," is executed."),(0,n.kt)("h3",{id:"endblocker-step-2---handleleadingvscmaturedpackets"},"Endblocker Step 2 - HandleLeadingVSCMaturedPackets"),(0,n.kt)("p",null,'Every block it is possible that VSCMatured packet data was queued before any slash packet data. Since this "leading" VSCMatured packet data does not have to be throttled (see ',(0,n.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order"),"), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes."),(0,n.kt)("h3",{id:"endblocker-step-3---handlethrottlequeues"},"Endblocker Step 3 - HandleThrottleQueues"),(0,n.kt)("p",null,"Every endblocker the following pseudo-code is executed to handle data from the throttle queues."),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-typescript"},"meter := getSlashMeter()\n\n// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist \nwhile meter.IsPositiveOrZero() && entriesExist() {\n // Get next entry in queue\n entry := getNextGlobalSlashEntry()\n // Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet\n valPower := entry.getValPower()\n meter = meter - valPower\n // Using the per-chain queue, handle the single slash packet using its queued data,\n // then handle all trailing VSCMatured packets for this consumer\n handleSlashPacketAndTrailingVSCMaturedPackets(entry)\n // Delete entry in global queue, delete handled data\n entry.Delete()\n deleteThrottledSlashPacketData()\n deleteTrailingVSCMaturedPacketData()\n}\n")),(0,n.kt)("h3",{id:"system-properties"},"System Properties"),(0,n.kt)("p",null,"All CCV system properties should be maintained by implementing this feature, see: ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"CCV spec - Consumer Initiated Slashing"),"."),(0,n.kt)("p",null,"One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than ",(0,n.kt)("inlineCode",{parentName:"p"},"MaxThrottledPackets (param)"),", then the provider binary will panic, and the provider chain will halt. Therefore this param should be set carefully. See ",(0,n.kt)("inlineCode",{parentName:"p"},"SetThrottledPacketDataSize"),". This behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators."),(0,n.kt)("h3",{id:"main-throttling-property"},"Main Throttling Property"),(0,n.kt)("p",null,"Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions."),(0,n.kt)("p",null,"First, we define the following:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},'A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.'),(0,n.kt)("li",{parentName:"ul"},'The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.'),(0,n.kt)("li",{parentName:"ul"},"There is a list of honest validators s.t if they are jailed, ",(0,n.kt)("inlineCode",{parentName:"li"},"X"),"% of the initial validator set will be jailed.")),(0,n.kt)("p",null,"For the following property to hold, these assumptions must be true:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack."),(0,n.kt)("li",{parentName:"ol"},"No validator has more than ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," of total voting power on the provider."),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," is large enough that ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," * ",(0,n.kt)("inlineCode",{parentName:"li"},"currentTotalVotingPower")," > 1. Ie. the replenish fraction is set high enough that we can ignore the effects of rounding."),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishPeriod")," is sufficiently longer than the time it takes to produce a block.")),(0,n.kt)("p",null,(0,n.kt)("em",{parentName:"p"},"Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined.")),(0,n.kt)("p",null,"Property:"),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"The time it takes to jail/tombstone ",(0,n.kt)("inlineCode",{parentName:"p"},"X"),"% of the initial validator set will be greater than or equal to ",(0,n.kt)("inlineCode",{parentName:"p"},"(X * SlashMeterReplenishPeriod / SlashMeterReplenishFraction) - 2 * SlashMeterReplenishPeriod"))),(0,n.kt)("p",null,"Intuition:"),(0,n.kt)("p",null,"Let's use the following notation:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"$C$: Number of replenishment cycles"),(0,n.kt)("li",{parentName:"ul"},"$P$: $\\text{SlashMeterReplenishPeriod}$"),(0,n.kt)("li",{parentName:"ul"},"$F$: $\\text{SlashMeterReplenishFraction}$"),(0,n.kt)("li",{parentName:"ul"},"$V_{\\mathit{max}}$: Max power of a validator as a fraction of total voting power")),(0,n.kt)("p",null,"In $C$ number of replenishment cycles, the fraction of total voting power that can be removed, $a$, is $a \\leq F \\cdot C + V",(0,n.kt)("em",{parentName:"p"},"{\\mathit{max}}$ (where $V"),"{\\mathit{max}}$ is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value)."),(0,n.kt)("p",null,"So, we need at least $C \\geq \\frac{a - V_{\\mathit{max}}}{F}$ cycles to remove $a$ fraction of the total voting power."),(0,n.kt)("p",null,"Since we defined the start of the attack to be the moment when the first slash request arrives, then $F$ fraction of the initial validator set can be jailed immediately. For the remaining $X - F$ fraction of the initial validator set to be jailed, it takes at least $C \\geq \\frac{(X - F) - V",(0,n.kt)("em",{parentName:"p"},"{\\mathit{max}}}{F}$ cycles. Using the assumption that $V"),"{\\mathit{max}} \\leq F$ (assumption 2), we get $C \\geq \\frac{X - 2F}{F}$ cycles."),(0,n.kt)("p",null,"In order to execute $C$ cycles, we need $C \\cdot P$ time."),(0,n.kt)("p",null,"Thus, jailing the remaining $X - F$ fraction of the initial validator set corresponds to $\\frac{P \\cdot (X - 2F)}{F}$ time."),(0,n.kt)("p",null,"In other words, the attack must take at least $\\frac{P \\cdot X}{F} - 2P$ time (in the units of replenish period $P$)."),(0,n.kt)("p",null,"This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests. For example, if ",(0,n.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction")," is set to 0.06, then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub. Note that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power."),(0,n.kt)("p",null,"Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings."),(0,n.kt)("h3",{id:"how-unjailing-affects-the-main-throttling-property"},"How Unjailing Affects the Main Throttling Property"),(0,n.kt)("p",null,"Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained."),(0,n.kt)("p",null,"If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider."),(0,n.kt)("p",null,"In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack."),(0,n.kt)("h2",{id:"consequences"},"Consequences"),(0,n.kt)("h3",{id:"positive"},"Positive"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"The described attack is slowed down in seemingly all cases."),(0,n.kt)("li",{parentName:"ul"},"If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded.")),(0,n.kt)("h3",{id:"negative"},"Negative"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below. However, this is sacrificing liveness in a edge case scenario for the sake of security. As an improvement, ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/713"},"using retries")," would fully prevent this attack vector.")),(0,n.kt)("h3",{id:"neutral"},"Neutral"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Additional state is introduced to the provider chain."),(0,n.kt)("li",{parentName:"ul"},"VSCMatured and slash packet data is not always handled in the same block that it is received.")),(0,n.kt)("h2",{id:"references"},"References"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/404"},"Original issue inspiring throttling feature")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/594"},"Issue on DOS vector")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/685"},"Consideration of another attack vector"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/d73929d1.71420f3f.js b/legacy/assets/js/d73929d1.71420f3f.js new file mode 100644 index 0000000000..8aa2d30a52 --- /dev/null +++ b/legacy/assets/js/d73929d1.71420f3f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8795],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>h});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=s(r),m=a,h=d["".concat(c,".").concat(m)]||d[m]||u[m]||i;return r?n.createElement(h,o(o({ref:t},p),{},{components:r})):n.createElement(h,o({ref:t},p))}));function h(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=m;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[d]="string"==typeof e?e:a,o[1]=l;for(var s=2;s<i;s++)o[s]=r[s];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},5403:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var n=r(7462),a=(r(7294),r(3905));const i={sidebar_position:1,title:"ADRs"},o="Architecture Decision Records (ADR)",l={unversionedId:"adrs/intro",id:"version-v3.1.0/adrs/intro",title:"ADRs",description:"This is a location to record all high-level architecture decisions in the Interchain Security project.",source:"@site/versioned_docs/version-v3.1.0/adrs/intro.md",sourceDirName:"adrs",slug:"/adrs/intro",permalink:"/interchain-security/legacy/v3.1.0/adrs/intro",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:1,frontMatter:{sidebar_position:1,title:"ADRs"},sidebar:"tutorialSidebar",previous:{title:"Frequently Asked Questions",permalink:"/interchain-security/legacy/v3.1.0/faq"},next:{title:"ADR Template",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-prop"}},c={},s=[{value:"Table of Contents",id:"table-of-contents",level:2}],p={toc:s},d="wrapper";function u(e){let{components:t,...r}=e;return(0,a.kt)(d,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"architecture-decision-records-adr"},"Architecture Decision Records (ADR)"),(0,a.kt)("p",null,"This is a location to record all high-level architecture decisions in the Interchain Security project."),(0,a.kt)("p",null,"You can read more about the ADR concept in this ",(0,a.kt)("a",{parentName:"p",href:"https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0#.78xhdix6t"},"blog post"),"."),(0,a.kt)("p",null,"An ADR should provide:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Context on the relevant goals and the current state"),(0,a.kt)("li",{parentName:"ul"},"Proposed changes to achieve the goals"),(0,a.kt)("li",{parentName:"ul"},"Summary of pros and cons"),(0,a.kt)("li",{parentName:"ul"},"References"),(0,a.kt)("li",{parentName:"ul"},"Changelog")),(0,a.kt)("p",null,"Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and\njustification for a change in architecture, or for the architecture of something\nnew. The spec is much more compressed and streamlined summary of everything as\nit is or should be."),(0,a.kt)("p",null,"If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match."),(0,a.kt)("p",null,"Note the context/background should be written in the present tense."),(0,a.kt)("p",null,"To suggest an ADR, please make use of the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.1.0/adrs/adr-template"},"ADR template")," provided."),(0,a.kt)("h2",{id:"table-of-contents"},"Table of Contents"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"ADR ","#"),(0,a.kt)("th",{parentName:"tr",align:null},"Description"),(0,a.kt)("th",{parentName:"tr",align:null},"Status"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.1.0/adrs/adr-001-key-assignment"},"001")),(0,a.kt)("td",{parentName:"tr",align:null},"Consumer chain key assignment"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.1.0/adrs/adr-002-throttle"},"002")),(0,a.kt)("td",{parentName:"tr",align:null},"Jail Throttling"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.1.0/adrs/adr-003-equivocation-gov-proposal"},"003")),(0,a.kt)("td",{parentName:"tr",align:null},"Equivocation governance proposal"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"./adr-004-denom-dos-fixes"},"004")),(0,a.kt)("td",{parentName:"tr",align:null},"Denom DOS fixes"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-prop"},"007")),(0,a.kt)("td",{parentName:"tr",align:null},"Pause validator unbonding during equivocation proposal"),(0,a.kt)("td",{parentName:"tr",align:null},"Proposed")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.1.0/adrs/adr-008-throttle-retries"},"008")),(0,a.kt)("td",{parentName:"tr",align:null},"Throttle with retries"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, In-progress")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("a",{parentName:"td",href:"/interchain-security/legacy/v3.1.0/adrs/adr-009-soft-opt-out"},"009")),(0,a.kt)("td",{parentName:"tr",align:null},"Soft Opt-out"),(0,a.kt)("td",{parentName:"tr",align:null},"Accepted, Implemented")))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/d784d738.43cc64b4.js b/legacy/assets/js/d784d738.43cc64b4.js new file mode 100644 index 0000000000..da2536256c --- /dev/null +++ b/legacy/assets/js/d784d738.43cc64b4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7333],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>d});var o=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function c(e,n){if(null==e)return{};var t,o,r=function(e,n){if(null==e)return{};var t,o,r={},a=Object.keys(e);for(o=0;o<a.length;o++)t=a[o],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o<a.length;o++)t=a[o],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=o.createContext({}),l=function(e){var n=o.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},u=function(e){var n=l(e.components);return o.createElement(s.Provider,{value:n},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},h=o.forwardRef((function(e,n){var t=e.components,r=e.mdxType,a=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=l(t),h=r,d=p["".concat(s,".").concat(h)]||p[h]||m[h]||a;return t?o.createElement(d,i(i({ref:n},u),{},{components:t})):o.createElement(d,i({ref:n},u))}));function d(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var a=t.length,i=new Array(a);i[0]=h;var c={};for(var s in n)hasOwnProperty.call(n,s)&&(c[s]=n[s]);c.originalType=e,c[p]="string"==typeof e?e:r,i[1]=c;for(var l=2;l<a;l++)i[l]=t[l];return o.createElement.apply(null,i)}return o.createElement.apply(null,t)}h.displayName="MDXCreateElement"},9774:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var o=t(7462),r=(t(7294),t(3905));const a={sidebar_position:1},i="Developing an ICS consumer chain",c={unversionedId:"consumer-development/app-integration",id:"consumer-development/app-integration",title:"Developing an ICS consumer chain",description:"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.",source:"@site/docs/consumer-development/app-integration.md",sourceDirName:"consumer-development",slug:"/consumer-development/app-integration",permalink:"/interchain-security/legacy/consumer-development/app-integration",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Consumer Initiated Slashing",permalink:"/interchain-security/legacy/features/slashing"},next:{title:"Consumer Chain Governance",permalink:"/interchain-security/legacy/consumer-development/consumer-chain-governance"}},s={},l=[{value:"Basic consumer chain",id:"basic-consumer-chain",level:2},{value:"Democracy consumer chain",id:"democracy-consumer-chain",level:2},{value:"Standalone chain to consumer chain changeover",id:"standalone-chain-to-consumer-chain-changeover",level:2}],u={toc:l},p="wrapper";function m(e){let{components:n,...t}=e;return(0,r.kt)(p,(0,o.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"developing-an-ics-consumer-chain"},"Developing an ICS consumer chain"),(0,r.kt)("p",null,"When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.\nTo help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications."),(0,r.kt)("h2",{id:"basic-consumer-chain"},"Basic consumer chain"),(0,r.kt)("p",null,"The source code for the example app can be found ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer"},"here"),"."),(0,r.kt)("p",null,"Please note that consumer chains do not implement the staking module - the validator set is replicated from the provider, meaning that the provider and the consumer use the same validator set and their stake on the provider directly determines their stake on the consumer.\nAt present there is no opt-in mechanism available, so all validators of the provider must also validate on the provider chain."),(0,r.kt)("p",null,"Your chain should import the consumer module from ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," and register it in the correct places in your ",(0,r.kt)("inlineCode",{parentName:"p"},"app.go"),".\nThe ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in.\nYou should not need to manage or override any code from the ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module."),(0,r.kt)("h2",{id:"democracy-consumer-chain"},"Democracy consumer chain"),(0,r.kt)("p",null,"The source code for the example app can be found ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy"},"here"),"."),(0,r.kt)("p",null,"This type of consumer chain wraps the basic CosmosSDK ",(0,r.kt)("inlineCode",{parentName:"p"},"x/distribution"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"x/staking")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"x/governance")," modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system."),(0,r.kt)("p",null,"This allows the consumer chain to leverage those modules while also using the ",(0,r.kt)("inlineCode",{parentName:"p"},"x/consumer")," module."),(0,r.kt)("p",null,'With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.'),(0,r.kt)("h2",{id:"standalone-chain-to-consumer-chain-changeover"},"Standalone chain to consumer chain changeover"),(0,r.kt)("p",null,"This feature is being actively worked on. Information will be provided at a later time."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/d88536eb.610c4cdc.js b/legacy/assets/js/d88536eb.610c4cdc.js new file mode 100644 index 0000000000..3f2ab1ea91 --- /dev/null +++ b/legacy/assets/js/d88536eb.610c4cdc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8330],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=l(n),u=i,h=d["".concat(c,".").concat(u)]||d[u]||m[u]||o;return n?a.createElement(h,r(r({ref:t},p),{},{components:n})):a.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=u;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:i,r[1]=s;for(var l=2;l<o;l++)r[l]=n[l];return a.createElement.apply(null,r)}return a.createElement.apply(null,n)}u.displayName="MDXCreateElement"},5732:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>m,frontMatter:()=>o,metadata:()=>s,toc:()=>l});var a=n(7462),i=(n(7294),n(3905));const o={sidebar_position:4,title:"Onboarding Checklist"},r="Consumer Onboarding Checklist",s={unversionedId:"consumer-development/onboarding",id:"version-v2.4.0-lsm/consumer-development/onboarding",title:"Onboarding Checklist",description:"The following checklists will aid in onboarding a new consumer chain to replicated security.",source:"@site/versioned_docs/version-v2.4.0-lsm/consumer-development/onboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/onboarding",permalink:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/onboarding",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Onboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Upgrading Consumer Chains",permalink:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/consumer-chain-upgrade-procedure"},next:{title:"Offboarding Checklist",permalink:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/offboarding"}},c={},l=[{value:"1. Complete testing & integration",id:"1-complete-testing--integration",level:2},{value:"2. Create an Onboarding Repository",id:"2-create-an-onboarding-repository",level:2},{value:"3. Submit a Governance Proposal",id:"3-submit-a-governance-proposal",level:2},{value:"4. Launch",id:"4-launch",level:2}],p={toc:l},d="wrapper";function m(e){let{components:t,...n}=e;return(0,i.kt)(d,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"consumer-onboarding-checklist"},"Consumer Onboarding Checklist"),(0,i.kt)("p",null,"The following checklists will aid in onboarding a new consumer chain to replicated security."),(0,i.kt)("p",null,"Additionally, you can check the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md"},"testnet repo")," for a comprehensive guide on preparing and launching consumer chains."),(0,i.kt)("h2",{id:"1-complete-testing--integration"},"1. Complete testing & integration"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test integration with gaia"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","test your protocol with supported relayer versions (minimum hermes 1.4.1)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","reach out to the ICS team if you are facing issues")),(0,i.kt)("h2",{id:"2-create-an-onboarding-repository"},"2. Create an Onboarding Repository"),(0,i.kt)("p",null,"To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain."),(0,i.kt)("p",null,"This should include (at minimum):"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json witout CCV data (before the propsal passes)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json with CCV data (after spawn time passes)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","information about relevant seed/peer nodes you are running"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","relayer information (compatible versions)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","copy of your governance proposal (as JSON)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","a script showing how to start your chain and connect to peers (optional)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable")),(0,i.kt)("p",null,"Example of such a repository can be found ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/hyphacoop/ics-testnets/tree/main/game-of-chains-2022/sputnik"},"here"),"."),(0,i.kt)("h2",{id:"3-submit-a-governance-proposal"},"3. Submit a Governance Proposal"),(0,i.kt)("p",null,"Before you submit a ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerChainAddition")," proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch.\nIf possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues."),(0,i.kt)("p",null,"Additionally, reach out to the community via the ",(0,i.kt)("a",{parentName:"p",href:"https://forum.cosmos.network/"},"forum")," to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers."),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine your chain's spawn time"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","determine consumer chain parameters to be put in the proposal"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","take note to include a link to your onboarding repository"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","describe the purpose and benefits of running your chain")),(0,i.kt)("p",null,"Example of a consumer chain addition proposal."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},'// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.\n// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.\n// It is recommended that spawn time occurs after the proposal end time.\n{\n // Title of the proposal\n "title": "Add consumer chain",\n // Description of the proposal\n // format the text as a .md file and include the file in your onboarding repository\n "description": ".md description of your chain and all other relevant information",\n // Proposed chain-id of the new consumer chain.\n // Must be unique from all other consumer chain ids of the executing provider chain.\n "chain_id": "newchain-1",\n // Initial height of new consumer chain.\n // For a completely new chain, this will be {0,1}.\n "initial_height" : {\n "revision_height": 0,\n "revision_number": 1,\n },\n // Hash of the consumer chain genesis state without the consumer CCV module genesis params.\n // It is used for off-chain confirmation of genesis.json validity by validators and other parties.\n "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",\n // Hash of the consumer chain binary that should be run by validators on chain initialization.\n // It is used for off-chain confirmation of binary validity by validators and other parties.\n "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",\n // Time on the provider chain at which the consumer chain genesis is finalized and all validators\n // will be responsible for starting their consumer chain validator node.\n "spawn_time": "2023-02-28T20:40:00.000000Z",\n // Unbonding period for the consumer chain.\n // It should should be smaller than that of the provider.\n "unbonding_period": 86400000000000,\n // Timeout period for CCV related IBC packets.\n // Packets are considered timed-out after this interval elapses.\n "ccv_timeout_period": 259200000000000,\n // IBC transfer packets will timeout after this interval elapses.\n "transfer_timeout_period": 1800000000000,\n // The fraction of tokens allocated to the consumer redistribution address during distribution events.\n // The fraction is a string representing a decimal number. For example "0.75" would represent 75%.\n // The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.\n "consumer_redistribution_fraction": "0.75",\n // BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.\n // eg. send rewards to the provider every 1000 blocks\n "blocks_per_distribution_transmission": 1000,\n // The number of historical info entries to persist in store.\n // This param is a part of the cosmos sdk staking module. In the case of\n // a ccv enabled consumer chain, the ccv module acts as the staking module.\n "historical_entries": 10000,\n // The ID of a token transfer channel used for the Reward Distribution\n // sub-protocol. If DistributionTransmissionChannel == "", a new transfer\n // channel is created on top of the same connection as the CCV channel.\n // Note that transfer_channel_id is the ID of the channel end on the consumer chain.\n // it is most relevant for chains performing a sovereign to consumer changeover\n // in order to maintan the existing ibc transfer channel\n "distribution_transmission_channel": "channel-123"\n}\n')),(0,i.kt)("h2",{id:"4-launch"},"4. Launch"),(0,i.kt)("p",null,"The consumer chain starts after at least 66.67% of all provider's voting power comes online. The consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","provide a repo with onboarding instructions for validators (it should already be listed in the proposal)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","genesis.json with ccv data populated (MUST contain the initial validator set)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","have a block explorer in place to track chain activity & health")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/d925e878.cf4495d8.js b/legacy/assets/js/d925e878.cf4495d8.js new file mode 100644 index 0000000000..55162eabbf --- /dev/null +++ b/legacy/assets/js/d925e878.cf4495d8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6550],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(n),d=o,f=u["".concat(c,".").concat(d)]||u[d]||m[d]||i;return n?r.createElement(f,a(a({ref:t},p),{},{components:n})):r.createElement(f,a({ref:t},p))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:o,a[1]=s;for(var l=2;l<i;l++)a[l]=n[l];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},1558:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>m,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var r=n(7462),o=(n(7294),n(3905));const i={sidebar_position:4,title:"Offboarding Checklist"},a="Consumer Offboarding",s={unversionedId:"consumer-development/offboarding",id:"version-v3.3.0/consumer-development/offboarding",title:"Offboarding Checklist",description:"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).",source:"@site/versioned_docs/version-v3.3.0/consumer-development/offboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/offboarding",permalink:"/interchain-security/legacy/v3.3.0/consumer-development/offboarding",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Offboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Onboarding Checklist",permalink:"/interchain-security/legacy/v3.3.0/consumer-development/onboarding"},next:{title:"Changeover Procedure",permalink:"/interchain-security/legacy/v3.3.0/consumer-development/changeover-procedure"}},c={},l=[],p={toc:l},u="wrapper";function m(e){let{components:t,...n}=e;return(0,o.kt)(u,(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-offboarding"},"Consumer Offboarding"),(0,o.kt)("p",null,"To offboard a consumer chain simply submit a ",(0,o.kt)("inlineCode",{parentName:"p"},"ConsumerRemovalProposal")," governance proposal listing a ",(0,o.kt)("inlineCode",{parentName:"p"},"stop_time"),". After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates)."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.\n// If it passes, all the consumer chain\'s state is removed from the provider chain. The outstanding unbonding\n// operation funds are released.\n{\n // the title of the proposal\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n}\n')),(0,o.kt)("p",null,"More information will be listed in a future version of this document."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/d9aa5843.661bb45b.js b/legacy/assets/js/d9aa5843.661bb45b.js new file mode 100644 index 0000000000..f4c5136de8 --- /dev/null +++ b/legacy/assets/js/d9aa5843.661bb45b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2715],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>m});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),h=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=h(e.components);return r.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),d=h(n),p=a,m=d["".concat(c,".").concat(p)]||d[p]||u[p]||o;return n?r.createElement(m,i(i({ref:t},l),{},{components:n})):r.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=p;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:a,i[1]=s;for(var h=2;h<o;h++)i[h]=n[h];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}p.displayName="MDXCreateElement"},4541:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>h});var r=n(7462),a=(n(7294),n(3905));const o={sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},i=void 0,s={unversionedId:"frequently-asked-questions",id:"version-v3.3.0/frequently-asked-questions",title:"Frequently Asked Questions",description:"What is the meaning of Validator Set Replication?",source:"@site/versioned_docs/version-v3.3.0/frequently-asked-questions.md",sourceDirName:".",slug:"/faq",permalink:"/interchain-security/legacy/v3.3.0/faq",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:5,frontMatter:{sidebar_position:5,title:"Frequently Asked Questions",slug:"/faq"},sidebar:"tutorialSidebar",previous:{title:"Joining Stride",permalink:"/interchain-security/legacy/v3.3.0/validators/joining-stride"},next:{title:"ADRs",permalink:"/interchain-security/legacy/v3.3.0/adrs/intro"}},c={},h=[{value:"What is the meaning of Validator Set Replication?",id:"what-is-the-meaning-of-validator-set-replication",level:2},{value:"What is a consumer chain?",id:"what-is-a-consumer-chain",level:2},{value:"What happens to consumer if provider is down?",id:"what-happens-to-consumer-if-provider-is-down",level:2},{value:"What happens to provider if consumer is down?",id:"what-happens-to-provider-if-consumer-is-down",level:2},{value:"Can I run the provider and consumer chains on the same machine?",id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine",level:2},{value:"Can the consumer chain have its own token?",id:"can-the-consumer-chain-have-its-own-token",level:2},{value:"How are Tx fees paid on consumer?",id:"how-are-tx-fees-paid-on-consumer",level:2},{value:"Are there any restrictions the consumer chains need to abide by?",id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by",level:2},{value:"What's in it for the validators and stakers?",id:"whats-in-it-for-the-validators-and-stakers",level:2},{value:"Can the consumer chain have its own governance?",id:"can-the-consumer-chain-have-its-own-governance",level:2},{value:"Can validators opt-out of replicated security?",id:"can-validators-opt-out-of-replicated-security",level:2},{value:"How does Equivocation Governance Slashing work?",id:"how-does-equivocation-governance-slashing-work",level:2},{value:"Can Consumer Chains perform Software Upgrades?",id:"can-consumer-chains-perform-software-upgrades",level:2},{value:"How can I connect to the testnets?",id:"how-can-i-connect-to-the-testnets",level:2},{value:"How do I start using ICS?",id:"how-do-i-start-using-ics",level:2},{value:"Which relayers are supported?",id:"which-relayers-are-supported",level:2},{value:"How does key delegation work in ICS?",id:"how-does-key-delegation-work-in-ics",level:2}],l={toc:h},d="wrapper";function u(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"what-is-the-meaning-of-validator-set-replication"},"What is the meaning of Validator Set Replication?"),(0,a.kt)("p",null,"VSR simply means that the same validator set is used to secure both the provider and consumer chains. VSR is ensured through ICS protocol which keeps consumers up to date with the validator set of the provider."),(0,a.kt)("h2",{id:"what-is-a-consumer-chain"},"What is a consumer chain?"),(0,a.kt)("p",null,"Consumer chain is blockchain operated by the same validator operators as the provider chain. The ICS protocol ensures the validator set replication properties (informs consumer chain about the current state of the validator set on the provider)"),(0,a.kt)("p",null,"Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements."),(0,a.kt)("h2",{id:"what-happens-to-consumer-if-provider-is-down"},"What happens to consumer if provider is down?"),(0,a.kt)("p",null,"In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set."),(0,a.kt)("p",null,"The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness."),(0,a.kt)("p",null,"However, if the ",(0,a.kt)("inlineCode",{parentName:"p"},"trusting_period")," (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain.\nThis means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about."),(0,a.kt)("p",null,'Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point.\nAt the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.'),(0,a.kt)("h2",{id:"what-happens-to-provider-if-consumer-is-down"},"What happens to provider if consumer is down?"),(0,a.kt)("p",null,"Consumer chains do not impact the provider chain.\nThe ICS protocol is concerned only with validator set replication and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events)."),(0,a.kt)("h2",{id:"can-i-run-the-provider-and-consumer-chains-on-the-same-machine"},"Can I run the provider and consumer chains on the same machine?"),(0,a.kt)("p",null,"Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation."),(0,a.kt)("h2",{id:"can-the-consumer-chain-have-its-own-token"},"Can the consumer chain have its own token?"),(0,a.kt)("p",null,"As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees."),(0,a.kt)("h2",{id:"how-are-tx-fees-paid-on-consumer"},"How are Tx fees paid on consumer?"),(0,a.kt)("p",null,"The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations."),(0,a.kt)("h2",{id:"are-there-any-restrictions-the-consumer-chains-need-to-abide-by"},"Are there any restrictions the consumer chains need to abide by?"),(0,a.kt)("p",null,"No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way.\nThe only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain."),(0,a.kt)("h2",{id:"whats-in-it-for-the-validators-and-stakers"},"What's in it for the validators and stakers?"),(0,a.kt)("p",null,"The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by ",(0,a.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction"),". The rewards are distributed (sent to the provider) every ",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission"),"."),(0,a.kt)("admonition",{type:"note"},(0,a.kt)("p",{parentName:"admonition"}," ",(0,a.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission")," are parameters defined in the ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," used to create the consumer chain. These parameters can be changed via consumer chain governance.")),(0,a.kt)("h2",{id:"can-the-consumer-chain-have-its-own-governance"},"Can the consumer chain have its own governance?"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Yes.")),(0,a.kt)("p",null,'In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.'),(0,a.kt)("p",null,"Validators can also be representatives but representatives are not required to run validator nodes."),(0,a.kt)("p",null,"This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance."),(0,a.kt)("h2",{id:"can-validators-opt-out-of-replicated-security"},"Can validators opt-out of replicated security?"),(0,a.kt)("p",null,"At present, the validators cannot opt-out of validating consumer chains."),(0,a.kt)("p",null,"There are multiple opt-out mechanisms under active research."),(0,a.kt)("h2",{id:"how-does-equivocation-governance-slashing-work"},"How does Equivocation Governance Slashing work?"),(0,a.kt)("p",null,"To avoid potential attacks directed at provider chain validators, a new mechanism was introduced:"),(0,a.kt)("p",null,"When a validator double-signs on the consumer chain, a special type of slash packet is relayed to the provider chain. The provider will store information about the double signing validator and allow a governance proposal to be submitted.\nIf the double-signing proposal passes, the offending validator will be slashed on the provider chain and tombstoned. Tombstoning will permanently exclude the validator from the active set of the provider."),(0,a.kt)("admonition",{type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"An equivocation proposal cannot be submitted for a validator that did not double sign on any of the consumer chains.")),(0,a.kt)("h2",{id:"can-consumer-chains-perform-software-upgrades"},"Can Consumer Chains perform Software Upgrades?"),(0,a.kt)("p",null,"Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM)."),(0,a.kt)("p",null,"Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module."),(0,a.kt)("h2",{id:"how-can-i-connect-to-the-testnets"},"How can I connect to the testnets?"),(0,a.kt)("p",null,"Check out the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/validators/joining-testnet"},"Joining Replicated Security testnet")," section."),(0,a.kt)("h2",{id:"how-do-i-start-using-ics"},"How do I start using ICS?"),(0,a.kt)("p",null,"To become a consumer chain use this ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/consumer-development/onboarding"},"checklist")," and check the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/consumer-development/app-integration"},"App integration section")),(0,a.kt)("h2",{id:"which-relayers-are-supported"},"Which relayers are supported?"),(0,a.kt)("p",null,"Currently supported versions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Hermes 1.4.1"),(0,a.kt)("li",{parentName:"ul"},"Support for the CCV module was added to the Go ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/relayer"},"relayer")," in v2.2.0 but v2.4.0 has significant performance fixes which makes it the earliest suggested version to use.")),(0,a.kt)("h2",{id:"how-does-key-delegation-work-in-ics"},"How does key delegation work in ICS?"),(0,a.kt)("p",null,"You can check the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/features/key-assignment"},"Key Assignment Guide")," for specific instructions."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/db091dad.0a75cee6.js b/legacy/assets/js/db091dad.0a75cee6.js new file mode 100644 index 0000000000..0a71f4302e --- /dev/null +++ b/legacy/assets/js/db091dad.0a75cee6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4360],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),m=c(n),d=o,f=m["".concat(l,".").concat(d)]||m[d]||u[d]||i;return n?r.createElement(f,a(a({ref:t},p),{},{components:n})):r.createElement(f,a({ref:t},p))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[m]="string"==typeof e?e:o,a[1]=s;for(var c=2;c<i;c++)a[c]=n[c];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},624:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var r=n(7462),o=(n(7294),n(3905));const i={sidebar_position:5,title:"Offboarding Checklist"},a="Consumer Offboarding",s={unversionedId:"consumer-development/offboarding",id:"version-v2.0.0/consumer-development/offboarding",title:"Offboarding Checklist",description:"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).",source:"@site/versioned_docs/version-v2.0.0/consumer-development/offboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/offboarding",permalink:"/interchain-security/legacy/v2.0.0/consumer-development/offboarding",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:5,frontMatter:{sidebar_position:5,title:"Offboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Onboarding Checklist",permalink:"/interchain-security/legacy/v2.0.0/consumer-development/onboarding"},next:{title:"Overview",permalink:"/interchain-security/legacy/v2.0.0/validators/overview"}},l={},c=[],p={toc:c},m="wrapper";function u(e){let{components:t,...n}=e;return(0,o.kt)(m,(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-offboarding"},"Consumer Offboarding"),(0,o.kt)("p",null,"To offboard a consumer chain simply submit a ",(0,o.kt)("inlineCode",{parentName:"p"},"ConsumerRemovalProposal")," governance proposal listing a ",(0,o.kt)("inlineCode",{parentName:"p"},"stop_time"),". After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates)."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.\n// If it passes, all the consumer chain\'s state is removed from the provider chain. The outstanding unbonding\n// operation funds are released.\n{\n // the title of the proposal\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n}\n')),(0,o.kt)("p",null,"More information will be listed in a future version of this document."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/dc875b45.7203e3b3.js b/legacy/assets/js/dc875b45.7203e3b3.js new file mode 100644 index 0000000000..013e7e5749 --- /dev/null +++ b/legacy/assets/js/dc875b45.7203e3b3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6894],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>m});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),d=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},h="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),h=d(n),u=i,m=h["".concat(s,".").concat(u)]||h[u]||p[u]||r;return n?a.createElement(m,o(o({ref:t},c),{},{components:n})):a.createElement(m,o({ref:t},c))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[h]="string"==typeof e?e:i,o[1]=l;for(var d=2;d<r;d++)o[d]=n[d];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}u.displayName="MDXCreateElement"},1350:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>p,frontMatter:()=>r,metadata:()=>l,toc:()=>d});var a=n(7462),i=(n(7294),n(3905));const r={sidebar_position:7,title:"Throttle with retries"},o=void 0,l={unversionedId:"adrs/adr-008-throttle-retries",id:"version-v3.3.0/adrs/adr-008-throttle-retries",title:"Throttle with retries",description:"ADR 008: Throttle with retries",source:"@site/versioned_docs/version-v3.3.0/adrs/adr-008-throttle-retries.md",sourceDirName:"adrs",slug:"/adrs/adr-008-throttle-retries",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-008-throttle-retries",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:7,frontMatter:{sidebar_position:7,title:"Throttle with retries"},sidebar:"tutorialSidebar",previous:{title:"Cryptographic verification of equivocation evidence",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-005-cryptographic-equivocation-verification"},next:{title:"Soft Opt-Out",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-009-soft-opt-out"}},s={},d=[{value:"ADR 008: Throttle with retries",id:"adr-008-throttle-with-retries",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consumer changes",id:"consumer-changes",level:3},{value:"Consumer pending packets storage optimization",id:"consumer-pending-packets-storage-optimization",level:4},{value:"Provider changes",id:"provider-changes",level:3},{value:"Handling <code>VSCMaturedPackets</code> immediately",id:"handling-vscmaturedpackets-immediately",level:4},{value:"Why the provider can handle VSCMatured packets immediately",id:"why-the-provider-can-handle-vscmatured-packets-immediately",level:4},{value:"Splitting of PRs and Upgrade Order",id:"splitting-of-prs-and-upgrade-order",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],c={toc:d},h="wrapper";function p(e){let{components:t,...n}=e;return(0,i.kt)(h,(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h2",{id:"adr-008-throttle-with-retries"},"ADR 008: Throttle with retries"),(0,i.kt)("h2",{id:"changelog"},"Changelog"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"6/9/23: Initial draft"),(0,i.kt)("li",{parentName:"ul"},"6/22/23: added note on consumer pending packets storage optimization"),(0,i.kt)("li",{parentName:"ul"},"7/14/23: Added note on upgrade order")),(0,i.kt)("h2",{id:"status"},"Status"),(0,i.kt)("p",null,"Accepted"),(0,i.kt)("h2",{id:"context"},"Context"),(0,i.kt)("p",null,"For context on why the throttling mechanism exists, see ",(0,i.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/adrs/adr-002-throttle"},"ADR 002"),"."),(0,i.kt)("p",null,"Note the terms slash throttling and jail throttling are synonymous, since in replicated security a ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPacket")," simply jails a validator for downtime infractions. "),(0,i.kt)("p",null,"Currently the throttling mechanism is designed so that provider logic (slash meter, etc.) dictates how many ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," can be handled over time.\nThrottled ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," are persisted on the provider, leading to multiple possible issues. Namely:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"If ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashPackets")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"VSCMaturedPackets")," are actually throttled/queued on the provider, state can grow and potentially lead to a DoS attack.\nWe have short term solutions around this, but overall they come with their own weaknesses.\nSee ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/594"},"#594"),"."),(0,i.kt)("li",{parentName:"ul"},"If a jailing attack described in ",(0,i.kt)("a",{parentName:"li",href:"/interchain-security/legacy/v3.3.0/adrs/adr-002-throttle"},"ADR 002")," were actually to be carried out with the current throttling design, we'd likely have to halt the provider, and perform an emergency upgrade and/or migration to clear the queues of ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashPackets")," that were deemed to be malicious.\nAlternatively, validators would just have to ",(0,i.kt)("em",{parentName:"li"},"tough it out")," and wait for the queues to clear, during which all/most validators would be jailed.\nRight after being jailed, validators would have to unjail themselves promptly to ensure safety.\nThe coordination required to maintain safety in such a scenario is not ideal.")),(0,i.kt)("p",null,"As as solution, we can improve the throttling mechanism to instead queue/persist relevant data on each consumer, and have consumers retry slash requests as needed."),(0,i.kt)("h2",{id:"decision"},"Decision"),(0,i.kt)("h3",{id:"consumer-changes"},"Consumer changes"),(0,i.kt)("p",null,"Note the consumer already queues up both ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets")," via ",(0,i.kt)("inlineCode",{parentName:"p"},"AppendPendingPacket"),".\nThose packets are dequeued in every ",(0,i.kt)("inlineCode",{parentName:"p"},"EndBlock")," in ",(0,i.kt)("inlineCode",{parentName:"p"},"SendPackets")," and sent to the provider."),(0,i.kt)("p",null,"Instead, we will now introduce the following logic on ",(0,i.kt)("inlineCode",{parentName:"p"},"EndBlock"),":"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Slash packets will always be sent to the provider once they're at the head of the queue.\nHowever, once sent, the consumer will not send any subsequent ",(0,i.kt)("inlineCode",{parentName:"li"},"VSCMaturedPackets")," from the queue until the provider responds with an acknowledgement that the sent ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashPacket")," has been handled, i.e., validator was jailed.\nThat is, ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashPackets")," block the sending of subsequent ",(0,i.kt)("inlineCode",{parentName:"li"},"VSCMaturedPackets")," in the consumer queue."),(0,i.kt)("li",{parentName:"ul"},"If two ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashPackets")," are at the head of the queue, the consumer will send the first ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashPacket"),", and then wait for a success acknowledgement from the provider before sending the second ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashPacket"),".\nThis seems like it'd simplify implementation."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"VSCMaturedPackets")," at the head of the queue (i.e., NOT following a ",(0,i.kt)("inlineCode",{parentName:"li"},"SlashPacket"),") can be sent immediately, and do not block any other packets in the queue, since the provider always handles them immediately.")),(0,i.kt)("p",null,"To prevent the provider from having to keep track of what ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," have been rejected, the consumer will have to retry the sending of ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," over some period of time.\nThis can be achieved with an on-chain consumer param, i.e., ",(0,i.kt)("inlineCode",{parentName:"p"},"RetryDelayPeriod"),".\nTo reduce the amount of redundant re-sends, we recommend setting ",(0,i.kt)("inlineCode",{parentName:"p"},"RetryDelayPeriod ~ SlashMeterReplenishmentPeriod"),", i.e., waiting for the provider slash meter to be replenished before resending the rejected ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPacket"),"."),(0,i.kt)("p",null,"Note to prevent weird edge case behavior, a retry would not be attempted until either a success or failure acknowledgement has been received from the provider."),(0,i.kt)("p",null,"With the behavior described, we maintain very similar behavior to the previous throttling mechanism regarding the timing that ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets")," are handled on the provider.\nObviously the queueing and blocking logic is moved, and the two chains would have to send more messages between one another (only in the case the throttling mechanism is triggered)."),(0,i.kt)("p",null,"In the normal case, when no or a few ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," are being sent, the ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets")," will not be delayed, and hence unbonding will not be delayed."),(0,i.kt)("p",null,"For the implementation of this design, see ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/fec3eccad59416cbdb6844e279f59e3f81242888/x/ccv/consumer/keeper/throttle_retry.go"},"throttle_retry.go"),"."),(0,i.kt)("h4",{id:"consumer-pending-packets-storage-optimization"},"Consumer pending packets storage optimization"),(0,i.kt)("p",null,"In addition to the mentioned consumer changes, an optimization will need to be made to the consumer's pending packets storage to properly implement the feature from this ADR."),(0,i.kt)("p",null,'The consumer ccv module previously queued "pending packets" to be sent in each ',(0,i.kt)("inlineCode",{parentName:"p"},"EndBlock")," in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/3bc4e7135066d848aac60b0787364c07157fd36d/x/ccv/consumer/keeper/relay.go#L178"},"SendPackets"),".\nThese packets are queued in state with a protobuf list of ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerPacketData"),".\nFor a single append operation, the entire list is deserialized, then a packet is appended to that list, and the list is serialized again.\nSee older version of ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/05c2dae7c6372b1252b9e97215d07c6aa7618f33/x/ccv/consumer/keeper/keeper.go#L606"},"AppendPendingPacket"),".\nThat is, a single append operation has O(N) complexity, where N is the size of the list."),(0,i.kt)("p",null,"This poor append performance isn't a problem when the pending packets list is small.\nBut with this ADR being implemented, the pending packets list could potentially grow to the order of thousands of entries when ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," need to be resent."),(0,i.kt)("p",null,"We can improve the append time for this queue by converting it from a protobuf-esq list, to a queue implemented with sdk-esq code.\nThe idea is to persist an uint64 index that will be incremented each time you queue up a packet.\nYou can think of this as storing the tail of the queue.\nThen, packet data will be keyed by that index, making the data naturally ordered byte-wise for sdk's iterator.\nThe index will also be stored in the packet data value bytes, so that the index can later be used to delete certain packets from the queue."),(0,i.kt)("p",null,"Two things are achieved with this approach:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"More efficient packet append/enqueue times"),(0,i.kt)("li",{parentName:"ul"},"The ability to delete select packets from the queue (previously all packets were deleted at once)")),(0,i.kt)("h3",{id:"provider-changes"},"Provider changes"),(0,i.kt)("p",null,"The main change needed for the provider is the removal of queuing logic for ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets")," upon being received."),(0,i.kt)("p",null,"Instead, the provider will consult the slash meter to determine if a ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPacket")," can be handled immediately.\nIf not, the provider will return an acknowledgement message to the consumer communicating that the ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPacket")," could not be handled, and needs to be sent again in the future (retried)."),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets")," will always be handled immediately upon being received by the provider."),(0,i.kt)("p",null,"Note ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"spec"),". Specifically the section on ",(0,i.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order"),". Previously the onus was on the provider to maintain this property via queuing packets and handling them FIFO."),(0,i.kt)("p",null,"Now this property will be maintained by the consumer sending packets in the correct order, and blocking the sending of ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets")," as needed. Then, the ordered IBC channel will ensure that ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPackets")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets")," are received in the correct order on the provider."),(0,i.kt)("p",null,"The provider's main responsibility regarding throttling will now be to determine if a received ",(0,i.kt)("inlineCode",{parentName:"p"},"SlashPacket")," can be handled via slash meter etc., and appropriately acknowledge to the sending consumer."),(0,i.kt)("h4",{id:"handling-vscmaturedpackets-immediately"},"Handling ",(0,i.kt)("inlineCode",{parentName:"h4"},"VSCMaturedPackets")," immediately"),(0,i.kt)("h4",{id:"why-the-provider-can-handle-vscmatured-packets-immediately"},"Why the provider can handle VSCMatured packets immediately"),(0,i.kt)("p",null,"A ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPacket")," communicates to the provider that sufficient time passed on the consumer since the corresponding ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCPacket")," has been applied (on the consumer) such that infractions committed on the consumer could have been submitted."),(0,i.kt)("p",null,"If the consumer is following the queuing/blocking protocol described, then no bad behavior occurs and the ",(0,i.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order")," property is maintained."),(0,i.kt)("p",null,"If a consumer sends ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets")," too leniently -- the consumer is malicious and sends duplicate ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets"),", or sends the packets sooner than the CCV protocol specifies -- then the provider needs to handle ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets")," immediately to prevent DOS, state bloat, or other issues.\nThe only possible negative outcome is that the malicious consumer may not be able to jail a validator who should have been jailed.\nThe malicious behavior only creates a negative outcome for the consumer chain that is being malicious."),(0,i.kt)("p",null,"If a consumer blocks the sending of ",(0,i.kt)("inlineCode",{parentName:"p"},"VSCMaturedPackets"),", then unbonding operations on the provider will be delayed, but only until the VSC timeout period has elapsed.\nAt that time, the consumer is removed.\nAgain the malicious behavior only creates a negative outcome for the consumer chain that is being malicious."),(0,i.kt)("h3",{id:"splitting-of-prs-and-upgrade-order"},"Splitting of PRs and Upgrade Order"),(0,i.kt)("p",null,"This feature will implement consumer changes in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1024"},"#1024"),". "),(0,i.kt)("p",null,"\u2757",(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("em",{parentName:"strong"},"These changes should be deployed to production for all consumers before the provider changes are deployed to production."))," "),(0,i.kt)("p",null,"In other words, the consumer changes in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1024"},"#1024"),' are compatible with the current ("v1") provider implementation of throttling that\'s running on the Cosmos Hub as of July 2023.'),(0,i.kt)("p",null,"Once all consumers have deployed the changes in #1024, the provider changes from ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1321"},"#1321")," can be deployed to production, fully enabling v2 throttling."),(0,i.kt)("h2",{id:"consequences"},"Consequences"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Consumers will now have to manage their own queues, and retry logic."),(0,i.kt)("li",{parentName:"ul"},"Consumers still aren't trustless, but the provider is now less susceptible to mismanaged or malicious consumers."),(0,i.kt)("li",{parentName:"ul"},'Recovering from the "jailing attack" is more elegant.'),(0,i.kt)("li",{parentName:"ul"},"Some issues like ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/1001"},"#1001")," will now be handled implicitly by the improved throttling mechanism."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"SlashPackets")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"VSCMaturedPackets")," can be handled immediately once received by the provider if the slash meter allows."),(0,i.kt)("li",{parentName:"ul"},"In general, we reduce the amount of computation that happens in the provider ",(0,i.kt)("inlineCode",{parentName:"li"},"EndBlock"),".")),(0,i.kt)("h3",{id:"positive"},"Positive"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},'We no longer have to reason about a "global queue" and a "chain specific queue", and keeping those all in-sync.\nNow ',(0,i.kt)("inlineCode",{parentName:"li"},"SlashPackets")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"VSCMaturedPackets")," queuing is handled on each consumer individually."),(0,i.kt)("li",{parentName:"ul"},"Due to the above, the throttling protocol becomes less complex overall."),(0,i.kt)("li",{parentName:"ul"},"We no longer have to worry about throttle related DoS attack on the provider, since no queuing exists on the provider.")),(0,i.kt)("h3",{id:"negative"},"Negative"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Increased number of IBC packets being relayed anytime throttling logic is triggered."),(0,i.kt)("li",{parentName:"ul"},"Consumer complexity increases, since consumers now have manage queuing themselves, and implement packet retry logic.")),(0,i.kt)("h3",{id:"neutral"},"Neutral"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Core throttling logic on the provider remains unchanged, i.e., slash meter, replenishment cycles, etc.")),(0,i.kt)("h2",{id:"references"},"References"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/713"},"EPIC")," tracking the changes proposed by this ADR"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/interchain-security/legacy/v3.3.0/adrs/adr-002-throttle"},"ADR 002: Jail Throttling")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/594"},"#594"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/dc9efaba.43a93fd3.js b/legacy/assets/js/dc9efaba.43a93fd3.js new file mode 100644 index 0000000000..180e61d281 --- /dev/null +++ b/legacy/assets/js/dc9efaba.43a93fd3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1324],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},p=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(r),d=o,f=u["".concat(c,".").concat(d)]||u[d]||m[d]||i;return r?n.createElement(f,a(a({ref:t},p),{},{components:r})):n.createElement(f,a({ref:t},p))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=d;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:o,a[1]=s;for(var l=2;l<i;l++)a[l]=r[l];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}d.displayName="MDXCreateElement"},5224:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>m,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const i={sidebar_position:4,title:"Offboarding Checklist"},a="Consumer Offboarding",s={unversionedId:"consumer-development/offboarding",id:"consumer-development/offboarding",title:"Offboarding Checklist",description:"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).",source:"@site/docs/consumer-development/offboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/offboarding",permalink:"/interchain-security/legacy/consumer-development/offboarding",draft:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Offboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Onboarding Checklist",permalink:"/interchain-security/legacy/consumer-development/onboarding"},next:{title:"Changeover Procedure",permalink:"/interchain-security/legacy/consumer-development/changeover-procedure"}},c={},l=[],p={toc:l},u="wrapper";function m(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-offboarding"},"Consumer Offboarding"),(0,o.kt)("p",null,"To offboard a consumer chain simply submit a ",(0,o.kt)("inlineCode",{parentName:"p"},"ConsumerRemovalProposal")," governance proposal listing a ",(0,o.kt)("inlineCode",{parentName:"p"},"stop_time"),". After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates)."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.\n// If it passes, all the consumer chain\'s state is removed from the provider chain. The outstanding unbonding\n// operation funds are released.\n{\n // the title of the proposal\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n}\n')),(0,o.kt)("p",null,"More information will be listed in a future version of this document."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/dca56be7.8e46da4b.js b/legacy/assets/js/dca56be7.8e46da4b.js new file mode 100644 index 0000000000..b967a27968 --- /dev/null +++ b/legacy/assets/js/dca56be7.8e46da4b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3612],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>m});var i=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?r(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):r(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,i,a=function(e,n){if(null==e)return{};var t,i,a={},r=Object.keys(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=i.createContext({}),c=function(e){var n=i.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},p=function(e){var n=c(e.components);return i.createElement(l.Provider,{value:n},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},u=i.forwardRef((function(e,n){var t=e.components,a=e.mdxType,r=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(t),u=a,m=d["".concat(l,".").concat(u)]||d[u]||h[u]||r;return t?i.createElement(m,o(o({ref:n},p),{},{components:t})):i.createElement(m,o({ref:n},p))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var r=t.length,o=new Array(r);o[0]=u;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:a,o[1]=s;for(var c=2;c<r;c++)o[c]=t[c];return i.createElement.apply(null,o)}return i.createElement.apply(null,t)}u.displayName="MDXCreateElement"},5109:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>c});var i=t(7462),a=(t(7294),t(3905));const r={sidebar_position:1},o="Overview",s={unversionedId:"validators/overview",id:"version-v3.3.1-lsm/validators/overview",title:"Overview",description:"We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.",source:"@site/versioned_docs/version-v3.3.1-lsm/validators/overview.md",sourceDirName:"validators",slug:"/validators/overview",permalink:"/interchain-security/legacy/validators/overview",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Consumer Genesis Transformation",permalink:"/interchain-security/legacy/consumer-development/consumer-genesis-transformation"},next:{title:"Joining Replicated Security testnet",permalink:"/interchain-security/legacy/validators/joining-testnet"}},l={},c=[{value:"Startup sequence overview",id:"startup-sequence-overview",level:2},{value:"1. Consumer Chain init + 2. Genesis generation",id:"1-consumer-chain-init--2-genesis-generation",level:3},{value:"3. Submit Proposal",id:"3-submit-proposal",level:3},{value:"4. CCV Genesis state generation",id:"4-ccv-genesis-state-generation",level:3},{value:"5. Updating the genesis file",id:"5-updating-the-genesis-file",level:3},{value:"6. Chain start",id:"6-chain-start",level:3},{value:"7. Creating IBC connections",id:"7-creating-ibc-connections",level:3},{value:"Downtime Infractions",id:"downtime-infractions",level:2},{value:"Double-signing Infractions",id:"double-signing-infractions",level:2},{value:"Key assignment",id:"key-assignment",level:2},{value:"References:",id:"references",level:2}],p={toc:c},d="wrapper";function h(e){let{components:n,...r}=e;return(0,a.kt)(d,(0,i.Z)({},p,r,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"overview"},"Overview"),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"We advise that you join the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security"},"Replicated Security testnet")," to gain hands-on experience with running consumer chains.")),(0,a.kt)("p",null,"At present, replicated security requires all validators of the provider chain (ie. Cosmos Hub) to run validator nodes for all governance-approved consumer chains."),(0,a.kt)("p",null,"Once a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," passes, validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains."),(0,a.kt)("p",null,"Provider chain and consumer chains represent standalone chains that only share the validator set ie. the same validator operators are tasked with running all chains."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 180 validators for Cosmos Hub).")),(0,a.kt)("h2",{id:"startup-sequence-overview"},"Startup sequence overview"),(0,a.kt)("p",null,"Consumer chains cannot start and be secured by the validator set of the provider unless a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," is passed.\nEach proposal contains defines a ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider."),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"Validators are required to run consumer chain binaries only after ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," has passed.")),(0,a.kt)("p",null,"Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains."),(0,a.kt)("p",null,"The image below illustrates the startup sequence\n",(0,a.kt)("img",{alt:"startup",src:t(7728).Z,width:"942",height:"632"})),(0,a.kt)("h3",{id:"1-consumer-chain-init--2-genesis-generation"},"1. Consumer Chain init + 2. Genesis generation"),(0,a.kt)("p",null,"Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")),(0,a.kt)("h3",{id:"3-submit-proposal"},"3. Submit Proposal"),(0,a.kt)("p",null,"Consumer chain team (or their advocates) submits a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal"),".\nThe most important parameters for validators are:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"spawn_time")," - the time after which the consumer chain must be started"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"genesis_hash")," - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and ",(0,a.kt)("inlineCode",{parentName:"li"},"spawn_time")," is reached"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"binary_hash")," - hash of the consumer chain binary used to validate the software builds")),(0,a.kt)("h3",{id:"4-ccv-genesis-state-generation"},"4. CCV Genesis state generation"),(0,a.kt)("p",null,"After reaching ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json"),". The CCV validator set consists of the validator set on the provider at ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time"),"."),(0,a.kt)("p",null,"The state can be queried on the provider chain (in this case the Cosmos Hub):"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json\n")),(0,a.kt)("p",null,"This is used by the launch coordinator to create the final ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," that will be distributed to validators in step 5."),(0,a.kt)("h3",{id:"5-updating-the-genesis-file"},"5. Updating the genesis file"),(0,a.kt)("p",null,"Upon reaching the ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," the initial validator set state will become available on the provider chain. The initial validator set is included in the ",(0,a.kt)("strong",{parentName:"p"},"final genesis.json")," of the consumer chain."),(0,a.kt)("h3",{id:"6-chain-start"},"6. Chain start"),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences.")),(0,a.kt)("p",null,"The new ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," to start their consumer chain node."),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"Please pay attention to any onboarding repositories provided by the consumer chain teams.\nRecommendations are available in ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/onboarding"},"Consumer Onboarding Checklist"),".\nAnother comprehensive guide is available in the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md"},"Replicated Security testnet repo"),".")),(0,a.kt)("h3",{id:"7-creating-ibc-connections"},"7. Creating IBC connections"),(0,a.kt)("p",null,"Finally, to fully establish replicated security an IBC relayer is used to establish connections and create the required channels."),(0,a.kt)("admonition",{type:"warning"},(0,a.kt)("p",{parentName:"admonition"},"The relayer can establish the connection only after the consumer chain starts producing blocks.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> \nhermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1\nhermes start\n")),(0,a.kt)("h2",{id:"downtime-infractions"},"Downtime Infractions"),(0,a.kt)("p",null,"At present, the consumer chain can report evidence about downtime infractions to the provider chain. The ",(0,a.kt)("inlineCode",{parentName:"p"},"min_signed_per_window")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"signed_blocks_window")," can be different on each consumer chain and are subject to changes via consumer chain governance."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains."),(0,a.kt)("p",{parentName:"admonition"},"To unjail, the validator must wait for the jailing period to elapse on the provider chain and ",(0,a.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html#unjail-validator"},"submit an unjail transaction")," on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains."),(0,a.kt)("p",{parentName:"admonition"},"More information is available in ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/features/slashing#downtime-infractions"},"Downtime Slashing documentation"))),(0,a.kt)("h2",{id:"double-signing-infractions"},"Double-signing Infractions"),(0,a.kt)("p",null,"To learn more about equivocation handling in replicated security check out the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/features/slashing"},"Slashing")," documentation section."),(0,a.kt)("h2",{id:"key-assignment"},"Key assignment"),(0,a.kt)("p",null,"Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use."),(0,a.kt)("p",null,"For more information check our the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/features/key-assignment"},"Key assignment overview and guide")),(0,a.kt)("h2",{id:"references"},"References:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-faq.html"},"Cosmos Hub Validators FAQ")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-setup.html"},"Cosmos Hub Running a validator")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md#chain-launch"},"Startup Sequence")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-setup.html#unjail-validator"},"Submit Unjailing Transaction"))))}h.isMDXComponent=!0},7728:(e,n,t)=>{t.d(n,{Z:()=>i});const i=t.p+"assets/images/hypha-consumer-start-process-2141109f76c584706dd994d7965fd692.svg"}}]); \ No newline at end of file diff --git a/legacy/assets/js/dca8d7c6.b9f5d0fc.js b/legacy/assets/js/dca8d7c6.b9f5d0fc.js new file mode 100644 index 0000000000..33b3261c08 --- /dev/null +++ b/legacy/assets/js/dca8d7c6.b9f5d0fc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[947],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>m});var i=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,i)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?r(Object(a),!0).forEach((function(t){n(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):r(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function l(e,t){if(null==e)return{};var a,i,n=function(e,t){if(null==e)return{};var a,i,n={},r=Object.keys(e);for(i=0;i<r.length;i++)a=r[i],t.indexOf(a)>=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)a=r[i],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var s=i.createContext({}),h=function(e){var t=i.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},d=function(e){var t=h(e.components);return i.createElement(s.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},u=i.forwardRef((function(e,t){var a=e.components,n=e.mdxType,r=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=h(a),u=n,m=c["".concat(s,".").concat(u)]||c[u]||p[u]||r;return a?i.createElement(m,o(o({ref:t},d),{},{components:a})):i.createElement(m,o({ref:t},d))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=a.length,o=new Array(r);o[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:n,o[1]=l;for(var h=2;h<r;h++)o[h]=a[h];return i.createElement.apply(null,o)}return i.createElement.apply(null,a)}u.displayName="MDXCreateElement"},8795:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>p,frontMatter:()=>r,metadata:()=>l,toc:()=>h});var i=a(7462),n=(a(7294),a(3905));const r={sidebar_position:3,title:"Jail Throttling"},o="ADR 002: Jail Throttling",l={unversionedId:"adrs/adr-002-throttle",id:"version-v2.4.0-lsm/adrs/adr-002-throttle",title:"Jail Throttling",description:"Changelog",source:"@site/versioned_docs/version-v2.4.0-lsm/adrs/adr-002-throttle.md",sourceDirName:"adrs",slug:"/adrs/adr-002-throttle",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-002-throttle",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Jail Throttling"},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-001-key-assignment"},next:{title:"Equivocation governance proposal",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposal"}},s={},h=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"State Required - Slash Meter",id:"state-required---slash-meter",level:3},{value:"State Required - Global entry queue",id:"state-required---global-entry-queue",level:3},{value:"State Required - Per-chain data queue",id:"state-required---per-chain-data-queue",level:3},{value:"Reasoning - Multiple queues",id:"reasoning---multiple-queues",level:3},{value:"Protocol Overview - OnRecvSlashPacket",id:"protocol-overview---onrecvslashpacket",level:3},{value:"Protocol Overview - OnRecvVSCMaturedPacket",id:"protocol-overview---onrecvvscmaturedpacket",level:3},{value:"Endblocker Step 1 - Slash Meter Replenishment",id:"endblocker-step-1---slash-meter-replenishment",level:3},{value:"Endblocker Step 2 - HandleLeadingVSCMaturedPackets",id:"endblocker-step-2---handleleadingvscmaturedpackets",level:3},{value:"Endblocker Step 3 - HandleThrottleQueues",id:"endblocker-step-3---handlethrottlequeues",level:3},{value:"System Properties",id:"system-properties",level:3},{value:"Main Throttling Property",id:"main-throttling-property",level:3},{value:"How Unjailing Affects the Main Throttling Property",id:"how-unjailing-affects-the-main-throttling-property",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],d={toc:h},c="wrapper";function p(e){let{components:t,...a}=e;return(0,n.kt)(c,(0,i.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"adr-002-jail-throttling"},"ADR 002: Jail Throttling"),(0,n.kt)("h2",{id:"changelog"},"Changelog"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"2023-01-26: Initial Draft"),(0,n.kt)("li",{parentName:"ul"},"2023-02-07: Property refined, ADR ready to review/merge")),(0,n.kt)("h2",{id:"status"},"Status"),(0,n.kt)("p",null,"Accepted"),(0,n.kt)("h2",{id:"context"},"Context"),(0,n.kt)("p",null,"The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols. In practice, this assumption may not hold. A malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider."),(0,n.kt)("p",null,"Before the throttling feature was implemented, the following attack was possible. Attacker(s) would create provider validators just below the provider's active set. Using a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once. Control of the provider would then pass over to the attackers' validators. This enables the attacker(s) to halt the provider. Or even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC."),(0,n.kt)("h2",{id:"decision"},"Decision"),(0,n.kt)("p",null,"The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack. Ie. this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time."),(0,n.kt)("h3",{id:"state-required---slash-meter"},"State Required - Slash Meter"),(0,n.kt)("p",null,"There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time. This meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params."),(0,n.kt)("h3",{id:"state-required---global-entry-queue"},"State Required - Global entry queue"),(0,n.kt)("p",null,'There exists a single queue which stores "global slash entries". These entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering. This queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.'),(0,n.kt)("h3",{id:"state-required---per-chain-data-queue"},"State Required - Per-chain data queue"),(0,n.kt)("p",null,'For each established consumer, there exists a queue which stores "throttled packet data". Ie. pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering. Order is enforced by IBC sequence number. These "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.'),(0,n.kt)("h3",{id:"reasoning---multiple-queues"},"Reasoning - Multiple queues"),(0,n.kt)("p",null,"For reasoning on why this feature was implemented with multiple queues, see ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"spec"),". Specifically the section on ",(0,n.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order"),". There are other ways to ensure such a property (like a queue of linked lists, etc.), but the implemented protocol seemed to be the most understandable and easiest to implement with a KV store."),(0,n.kt)("h3",{id:"protocol-overview---onrecvslashpacket"},"Protocol Overview - OnRecvSlashPacket"),(0,n.kt)("p",null,"Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"A global slash entry is queued."),(0,n.kt)("li",{parentName:"ol"},"The data of such a packet is added to the per-chain queue.")),(0,n.kt)("h3",{id:"protocol-overview---onrecvvscmaturedpacket"},"Protocol Overview - OnRecvVSCMaturedPacket"),(0,n.kt)("p",null,"Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue."),(0,n.kt)("h3",{id:"endblocker-step-1---slash-meter-replenishment"},"Endblocker Step 1 - Slash Meter Replenishment"),(0,n.kt)("p",null,"Once the slash meter becomes not full, it'll be replenished after ",(0,n.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishPeriod (param)")," by incrementing the meter with its allowance for the replenishment block, where ",(0,n.kt)("inlineCode",{parentName:"p"},"allowance")," = ",(0,n.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction (param)")," * ",(0,n.kt)("inlineCode",{parentName:"p"},"currentTotalVotingPower"),". The slash meter will never exceed its current allowance (fn of the total voting power for the block) in value. Note a few things:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power. In such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods."),(0,n.kt)("li",{parentName:"ol"},"Total voting power of a chain changes over time, especially as validators are jailed. As validators are jailed, total voting power decreases, and so does the jailing allowance. See below for more detailed throttling property discussion."),(0,n.kt)("li",{parentName:"ol"},"The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1. If the ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction (param)")," is set too low, integer rounding will put this minimum value into effect. That is, if ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," * ",(0,n.kt)("inlineCode",{parentName:"li"},"currentTotalVotingPower")," < 1, then the effective allowance would be 1. This min value of allowance ensures that there's some packets handled over time, even if that is a very long time. It's a crude solution to an edge case caused by too small of a replenishment fraction.")),(0,n.kt)("p",null,"The behavior described above is achieved by executing ",(0,n.kt)("inlineCode",{parentName:"p"},"CheckForSlashMeterReplenishment()")," every endblock, BEFORE ",(0,n.kt)("inlineCode",{parentName:"p"},"HandleThrottleQueues()")," is executed."),(0,n.kt)("h3",{id:"endblocker-step-2---handleleadingvscmaturedpackets"},"Endblocker Step 2 - HandleLeadingVSCMaturedPackets"),(0,n.kt)("p",null,'Every block it is possible that VSCMatured packet data was queued before any slash packet data. Since this "leading" VSCMatured packet data does not have to be throttled (see ',(0,n.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order"),"), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes."),(0,n.kt)("h3",{id:"endblocker-step-3---handlethrottlequeues"},"Endblocker Step 3 - HandleThrottleQueues"),(0,n.kt)("p",null,"Every endblocker the following pseudo-code is executed to handle data from the throttle queues."),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-typescript"},"meter := getSlashMeter()\n\n// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist \nwhile meter.IsPositiveOrZero() && entriesExist() {\n // Get next entry in queue\n entry := getNextGlobalSlashEntry()\n // Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet\n valPower := entry.getValPower()\n meter = meter - valPower\n // Using the per-chain queue, handle the single slash packet using its queued data,\n // then handle all trailing VSCMatured packets for this consumer\n handleSlashPacketAndTrailingVSCMaturedPackets(entry)\n // Delete entry in global queue, delete handled data\n entry.Delete()\n deleteThrottledSlashPacketData()\n deleteTrailingVSCMaturedPacketData()\n}\n")),(0,n.kt)("h3",{id:"system-properties"},"System Properties"),(0,n.kt)("p",null,"All CCV system properties should be maintained by implementing this feature, see: ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"CCV spec - Consumer Initiated Slashing"),"."),(0,n.kt)("p",null,"One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than ",(0,n.kt)("inlineCode",{parentName:"p"},"MaxThrottledPackets (param)"),", then the provider binary will panic, and the provider chain will halt. Therefore this param should be set carefully. See ",(0,n.kt)("inlineCode",{parentName:"p"},"SetThrottledPacketDataSize"),". This behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators."),(0,n.kt)("h3",{id:"main-throttling-property"},"Main Throttling Property"),(0,n.kt)("p",null,"Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions."),(0,n.kt)("p",null,"First, we define the following:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},'A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.'),(0,n.kt)("li",{parentName:"ul"},'The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.'),(0,n.kt)("li",{parentName:"ul"},"There is a list of honest validators s.t if they are jailed, ",(0,n.kt)("inlineCode",{parentName:"li"},"X"),"% of the initial validator set will be jailed.")),(0,n.kt)("p",null,"For the following property to hold, these assumptions must be true:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack."),(0,n.kt)("li",{parentName:"ol"},"No validator has more than ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," of total voting power on the provider."),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," is large enough that ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," * ",(0,n.kt)("inlineCode",{parentName:"li"},"currentTotalVotingPower")," > 1. Ie. the replenish fraction is set high enough that we can ignore the effects of rounding."),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishPeriod")," is sufficiently longer than the time it takes to produce a block.")),(0,n.kt)("p",null,(0,n.kt)("em",{parentName:"p"},"Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined.")),(0,n.kt)("p",null,"Property:"),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"The time it takes to jail/tombstone ",(0,n.kt)("inlineCode",{parentName:"p"},"X"),"% of the initial validator set will be greater than or equal to ",(0,n.kt)("inlineCode",{parentName:"p"},"(X * SlashMeterReplenishPeriod / SlashMeterReplenishFraction) - 2 * SlashMeterReplenishPeriod"))),(0,n.kt)("p",null,"Intuition:"),(0,n.kt)("p",null,"Let's use the following notation:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"$C$: Number of replenishment cycles"),(0,n.kt)("li",{parentName:"ul"},"$P$: $\\text{SlashMeterReplenishPeriod}$"),(0,n.kt)("li",{parentName:"ul"},"$F$: $\\text{SlashMeterReplenishFraction}$"),(0,n.kt)("li",{parentName:"ul"},"$V_{\\mathit{max}}$: Max power of a validator as a fraction of total voting power")),(0,n.kt)("p",null,"In $C$ number of replenishment cycles, the fraction of total voting power that can be removed, $a$, is $a \\leq F \\cdot C + V",(0,n.kt)("em",{parentName:"p"},"{\\mathit{max}}$ (where $V"),"{\\mathit{max}}$ is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value)."),(0,n.kt)("p",null,"So, we need at least $C \\geq \\frac{a - V_{\\mathit{max}}}{F}$ cycles to remove $a$ fraction of the total voting power."),(0,n.kt)("p",null,"Since we defined the start of the attack to be the moment when the first slash request arrives, then $F$ fraction of the initial validator set can be jailed immediately. For the remaining $X - F$ fraction of the initial validator set to be jailed, it takes at least $C \\geq \\frac{(X - F) - V",(0,n.kt)("em",{parentName:"p"},"{\\mathit{max}}}{F}$ cycles. Using the assumption that $V"),"{\\mathit{max}} \\leq F$ (assumption 2), we get $C \\geq \\frac{X - 2F}{F}$ cycles."),(0,n.kt)("p",null,"In order to execute $C$ cycles, we need $C \\cdot P$ time."),(0,n.kt)("p",null,"Thus, jailing the remaining $X - F$ fraction of the initial validator set corresponds to $\\frac{P \\cdot (X - 2F)}{F}$ time."),(0,n.kt)("p",null,"In other words, the attack must take at least $\\frac{P \\cdot X}{F} - 2P$ time (in the units of replenish period $P$)."),(0,n.kt)("p",null,"This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests. For example, if ",(0,n.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction")," is set to 0.06, then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub. Note that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power."),(0,n.kt)("p",null,"Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings."),(0,n.kt)("h3",{id:"how-unjailing-affects-the-main-throttling-property"},"How Unjailing Affects the Main Throttling Property"),(0,n.kt)("p",null,"Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained."),(0,n.kt)("p",null,"If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider."),(0,n.kt)("p",null,"In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack."),(0,n.kt)("h2",{id:"consequences"},"Consequences"),(0,n.kt)("h3",{id:"positive"},"Positive"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"The described attack is slowed down in seemingly all cases."),(0,n.kt)("li",{parentName:"ul"},"If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded.")),(0,n.kt)("h3",{id:"negative"},"Negative"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below. However, this is sacrificing liveness in a edge case scenario for the sake of security. As an improvement, ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/713"},"using retries")," would fully prevent this attack vector.")),(0,n.kt)("h3",{id:"neutral"},"Neutral"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Additional state is introduced to the provider chain."),(0,n.kt)("li",{parentName:"ul"},"VSCMatured and slash packet data is not always handled in the same block that it is received.")),(0,n.kt)("h2",{id:"references"},"References"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/404"},"Original issue inspiring throttling feature")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/594"},"Issue on DOS vector")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/685"},"Consideration of another attack vector"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/dd2dc399.3809744d.js b/legacy/assets/js/dd2dc399.3809744d.js new file mode 100644 index 0000000000..75f3edd9c4 --- /dev/null +++ b/legacy/assets/js/dd2dc399.3809744d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8973],{3905:(e,t,i)=>{i.d(t,{Zo:()=>h,kt:()=>g});var n=i(7294);function a(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}function o(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function r(e){for(var t=1;t<arguments.length;t++){var i=null!=arguments[t]?arguments[t]:{};t%2?o(Object(i),!0).forEach((function(t){a(e,t,i[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(i)):o(Object(i)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(i,t))}))}return e}function s(e,t){if(null==e)return{};var i,n,a=function(e,t){if(null==e)return{};var i,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)i=o[n],t.indexOf(i)>=0||(a[i]=e[i]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)i=o[n],t.indexOf(i)>=0||Object.prototype.propertyIsEnumerable.call(e,i)&&(a[i]=e[i])}return a}var l=n.createContext({}),c=function(e){var t=n.useContext(l),i=t;return e&&(i="function"==typeof e?e(t):r(r({},t),e)),i},h=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var i=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,h=s(e,["components","mdxType","originalType","parentName"]),d=c(i),p=a,g=d["".concat(l,".").concat(p)]||d[p]||u[p]||o;return i?n.createElement(g,r(r({ref:t},h),{},{components:i})):n.createElement(g,r({ref:t},h))}));function g(e,t){var i=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=i.length,r=new Array(o);r[0]=p;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:a,r[1]=s;for(var c=2;c<o;c++)r[c]=i[c];return n.createElement.apply(null,r)}return n.createElement.apply(null,i)}p.displayName="MDXCreateElement"},9683:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var n=i(7462),a=(i(7294),i(3905));const o={sidebar_position:4,title:"Cryptographic verification of equivocation evidence"},r="ADR 005: Cryptographic verification of equivocation evidence",s={unversionedId:"adrs/adr-005-cryptographic-equivocation-verification",id:"version-v3.2.0/adrs/adr-005-cryptographic-equivocation-verification",title:"Cryptographic verification of equivocation evidence",description:"Changelog",source:"@site/versioned_docs/version-v3.2.0/adrs/adr-005-cryptographic-equivocation-verification.md",sourceDirName:"adrs",slug:"/adrs/adr-005-cryptographic-equivocation-verification",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-005-cryptographic-equivocation-verification",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Cryptographic verification of equivocation evidence"},sidebar:"tutorialSidebar",previous:{title:"Equivocation governance proposal",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-003-equivocation-gov-proposal"},next:{title:"Throttle with retries",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-008-throttle-retries"}},l={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Light Client Attack",id:"light-client-attack",level:3},{value:"Decision",id:"decision",level:2},{value:"Current limitations:",id:"current-limitations",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}],h={toc:c},d="wrapper";function u(e){let{components:t,...i}=e;return(0,a.kt)(d,(0,n.Z)({},h,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-005-cryptographic-verification-of-equivocation-evidence"},"ADR 005: Cryptographic verification of equivocation evidence"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"5/1/2023: First draft"),(0,a.kt)("li",{parentName:"ul"},"7/23/23: Add light client attacks handling")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"Currently, we use a governance proposal to slash validators for equivocation (double signing and light client attacks).\nEvery proposal needs to go through a (two weeks) voting period before it can be approved.\nGiven a three-week unbonding period, this means that an equivocation proposal needs to be submitted within one week since the infraction occurred."),(0,a.kt)("p",null,"This ADR proposes a system to slash validators automatically for equivocation, immediately upon the provider chain's receipt of the evidence. Another thing to note is that we intend to introduce this system in stages, since even the partial ability to slash and/or tombstone is a strict improvement in security.\nFor the first stage of this work, we will only handle light client attacks."),(0,a.kt)("h3",{id:"light-client-attack"},"Light Client Attack"),(0,a.kt)("p",null,"In a nutshell, the light client is a process that solely verifies a specific state machine's\nconsensus without executing the transactions. The light clients get new headers by querying\nmultiple nodes, called primary and witness nodes. "),(0,a.kt)("p",null,"Light clients download new headers committed on chain from a primary. Headers can be verified in two ways: sequentially,\nwhere the block height of headers is serial, or using skipping. This second verification method allows light clients to download headers\nwith nonconsecutive block height, where some intermediate headers are skipped (see ",(0,a.kt)("a",{parentName:"p",href:"https://arxiv.org/pdf/2010.07031.pdf"},"Tendermint Light Client, Figure 1 and Figure 3"),").\nAdditionally, light clients are cross-checking new headers obtained from a primary with witnesses to ensure all nodes share the same state."),(0,a.kt)("p",null,"A light client attack occurs when a Byzantine validator sends invalid headers to a light client.\nAs the light client doesn't execute transactions, it can be deceived into trusting corrupted application state transitions.\nFor instance, if a light client receives header ",(0,a.kt)("inlineCode",{parentName:"p"},"A")," from the primary and header ",(0,a.kt)("inlineCode",{parentName:"p"},"B")," from a witness for the same block height ",(0,a.kt)("inlineCode",{parentName:"p"},"H"),",\nand both headers are successfully verified, it indicates a light client attack.\nNote that in this case, either the primary or the witness or both are malicious."),(0,a.kt)("p",null,"The types of light client attacks are defined by analyzing the differences between the conflicting headers.\nThere are three types of light client attacks: lunatic attack, equivocation attack, and amnesia attack.\nFor details, see the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/main/spec/light-client/attacks/notes-on-evidence-handling.md#evidence-handling"},"CometBFT specification"),"."),(0,a.kt)("p",null,"When a light client agent detects two conflicting headers, it will initially verify their traces (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/2af25aea6cfe6ac4ddac40ceddfb8c8eee17d0e6/light/detector.go#L28"},"cometBFT detector"),") using its primary and witness nodes.\nIf these headers pass successful verification, the Byzantine validators will be identified based on the header's commit signatures\nand the type of light client attack. The agent will then transmit this information to its nodes using a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/feed0ddf564e113a840c4678505601256b93a8bc/docs/architecture/adr-047-handling-evidence-from-light-client.md"},(0,a.kt)("inlineCode",{parentName:"a"},"LightClientAttackEvidence"))," to be eventually voted on and added to a block.\nNote that from a light client agent perspective, it is not possible to establish whether a primary or a witness node, or both, are malicious.\nTherefore, it will create and send two ",(0,a.kt)("inlineCode",{parentName:"p"},"LightClientAttackEvidence"),": one against the primary (sent to the witness), and one against the witness (sent to the primary).\nBoth nodes will then verify it before broadcasting it and adding it to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/2af25aea6cfe6ac4ddac40ceddfb8c8eee17d0e6/evidence/pool.go#L28"},"evidence pool"),".\nIf a ",(0,a.kt)("inlineCode",{parentName:"p"},"LightClientAttackEvidence")," is finally committed to a block, the chain's evidence module will execute it, resulting in the jailing and the slashing of the validators responsible for the light client attack."),(0,a.kt)("p",null,"Light clients are a core component of IBC. In the event of a light client attack, IBC relayers notify the affected chains by submitting an ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/2b7c969066fbcb18f90c7f5bd256439ca12535c7/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79"},"IBC misbehavior message"),".\nA misbehavior message includes the conflicting headers that constitute a ",(0,a.kt)("inlineCode",{parentName:"p"},"LightClientAttackEvidence"),". Upon receiving such a message,\na chain will first verify whether these headers would have convinced its light client. This verification is achieved by checking\nthe header states against the light client consensus states (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/2b7c969066fbcb18f90c7f5bd256439ca12535c7/modules/light-clients/07-tendermint/types/misbehaviour_handle.go#L101"},"IBC misbehaviour handler"),'). If the misbehaviour is successfully verified, the chain will then "freeze" the\nlight client, halting any further trust in or updating of its states.'),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"In the first iteration of the feature, we will introduce a new endpoint: ",(0,a.kt)("inlineCode",{parentName:"p"},"HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour)"),".\nThe main idea is to leverage the current IBC misbehaviour handling and update it to solely jail and slash the validators that\nperformed a light client attack. This update will be made under the assumption that the chain connected via this light client\nshare the same validator set, as it is the case with Replicated Security. "),(0,a.kt)("p",null,"This endpoint will reuse the IBC client libraries to verify that the misbehaviour headers would have fooled the light client.\nAdditionally, it\u2019s crucial that the endpoint logic result in the slashing and jailing of validators under the same conditions\nas a light client agent detector. Therefore, the endpoint will ensure that the two conditions are met:\nthe headers in the misbehaviour message have the same block height, and\nthe light client isn\u2019t expired."),(0,a.kt)("p",null,"After having successfully verified a misbehaviour, the endpoint will execute the jailing and slashing of the malicious validators similarly as in the evidence module. "),(0,a.kt)("h3",{id:"current-limitations"},"Current limitations:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"This only handles light client attacks, not double signing. In the future, we will add the code to also verify double signing.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"We cannot derive an infraction height from the evidence, so it is only possible to tombstone validators, not actually slash them.\nTo explain the technical reasons behind this limitation, let's recap the initial consumer initiated slashing logic.\nIn a nutshell, consumer heights are mapped to provider heights through VSCPackets, namely through the so called vscIDs.\nWhen an infraction occurs on the consumer, a SlashPacket containing the vscID obtained from mapping the consumer infraction height\nis sent to the provider. Upon receiving the packet, the provider maps the consumer infraction height to a local infraction height,\nwhich is used to slash the misbehaving validator. In the context of untrusted consumer chains, all their states, including vscIDs,\ncould be corrupted and therefore cannot be used for slashing purposes.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},'Currently, the endpoint can only handle "equivocation" light client attacks. This is because the "lunatic" attacks require the endpoint to possess the ability to dissociate which header is conflicted or trusted upon receiving a misbehavior message. Without this information, it\'s not possible to define the Byzantine validators from the conflicting headers (see ',(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/826#discussion_r1268668684"},"comment"),")."))),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"After this ADR is applied, it will be possible for the provider chain to tombstone validators who committed a light client attack.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"N/A")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/826"},"ICS misbehaviour handling PR")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://docs.google.com/document/d/1fe1uSJl1ZIYWXoME3Yf4Aodvz7V597Ric875JH-rigM/edit#heading=h.rv4t8i6d6jfn"},"Architectural diagrams"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/ded36896.d40f5dbf.js b/legacy/assets/js/ded36896.d40f5dbf.js new file mode 100644 index 0000000000..540055b586 --- /dev/null +++ b/legacy/assets/js/ded36896.d40f5dbf.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7429],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>g});var i=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function r(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,i,o=function(e,n){if(null==e)return{};var t,i,o={},a=Object.keys(e);for(i=0;i<a.length;i++)t=a[i],n.indexOf(t)>=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i<a.length;i++)t=a[i],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=i.createContext({}),u=function(e){var n=i.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):r(r({},n),e)),t},p=function(e){var n=u(e.components);return i.createElement(l.Provider,{value:n},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},h=i.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=u(t),h=o,g=d["".concat(l,".").concat(h)]||d[h]||c[h]||a;return t?i.createElement(g,r(r({ref:n},p),{},{components:t})):i.createElement(g,r({ref:n},p))}));function g(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,r=new Array(a);r[0]=h;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:o,r[1]=s;for(var u=2;u<a;u++)r[u]=t[u];return i.createElement.apply(null,r)}return i.createElement.apply(null,t)}h.displayName="MDXCreateElement"},9969:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>r,default:()=>c,frontMatter:()=>a,metadata:()=>s,toc:()=>u});var i=t(7462),o=(t(7294),t(3905));const a={sidebar_position:2,title:"ADR Template"},r="ADR 007: Pause validator unbonding during equivocation proposal",s={unversionedId:"adrs/adr-007-pause-unbonding-on-eqv-prop",id:"adrs/adr-007-pause-unbonding-on-eqv-prop",title:"ADR Template",description:"Changelog",source:"@site/docs/adrs/adr-007-pause-unbonding-on-eqv-prop.md",sourceDirName:"adrs",slug:"/adrs/adr-007-pause-unbonding-on-eqv-prop",permalink:"/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop",draft:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"ADR Template"},sidebar:"tutorialSidebar",previous:{title:"ADRs",permalink:"/interchain-security/legacy/adrs/intro"},next:{title:"ADR Template",permalink:"/interchain-security/legacy/adrs/adr-template"}},l={},u=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"How",id:"how",level:3},{value:"When pause",id:"when-pause",level:3},{value:"When unpause",id:"when-unpause",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],p={toc:u},d="wrapper";function c(e){let{components:n,...t}=e;return(0,o.kt)(d,(0,i.Z)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"adr-007-pause-validator-unbonding-during-equivocation-proposal"},"ADR 007: Pause validator unbonding during equivocation proposal"),(0,o.kt)("h2",{id:"changelog"},"Changelog"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"2023-05-16: Initial Draft")),(0,o.kt)("h2",{id:"status"},"Status"),(0,o.kt)("p",null,"Proposed"),(0,o.kt)("h2",{id:"context"},"Context"),(0,o.kt)("p",null,"Currently, if an equivocation slashing proposal is created after more than one\nweek has passed since the equivocation, it is possible that the validator in\nquestion could unbond and get away without being slashed, since the unbonding\nperiod is 3 weeks, and the voting period is 2 weeks. For this reason, it might\nbe good to pause unbondings for validators named in an equivocation slashing\nproposal until the proposal's voting period is over."),(0,o.kt)("h2",{id:"decision"},"Decision"),(0,o.kt)("h3",{id:"how"},"How"),(0,o.kt)("p",null,"Pausing the unbonding period is already possible thanks to the changes in the\n",(0,o.kt)("inlineCode",{parentName:"p"},"staking")," module of the cosmos-sdk:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"stakingKeeper.PutUnbondingOnHold")," pauses an unbonding period"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"stakingKeeper.UnbondingCanComplete")," unpauses an unbonding period")),(0,o.kt)("p",null,"These methods use a reference counter under the hood, that gets incremented\nevery time ",(0,o.kt)("inlineCode",{parentName:"p"},"PutUnbondingOnHold")," is called, and decreased when\n",(0,o.kt)("inlineCode",{parentName:"p"},"UnbondingCanComplete")," is called instead. A specific unbonding is considered\nfully unpaused when its underlying reference counter reaches 0. Therefore, as\nlong as we safeguard consistency - i.e. we make sure we eventually decrement\nthe reference counter for each time we have incremented it - we can safely use\nthis existing mechanism without conflicts with the ",(0,o.kt)("em",{parentName:"p"},"Completion of Unbonding\nOperations")," system."),(0,o.kt)("h3",{id:"when-pause"},"When pause"),(0,o.kt)("p",null,"The unbonding period (if there is any unbonding) should be paused once an\nequivocation proposal enters the voting period. For that, the ",(0,o.kt)("inlineCode",{parentName:"p"},"gov")," module's\nhook ",(0,o.kt)("inlineCode",{parentName:"p"},"AfterProposalDeposit")," can be used. "),(0,o.kt)("p",null,"If the hook is triggered with a an equivocation proposal in voting period, then\nfor each equivocation of the proposal, the unbonding operations of the related\nvalidator that were initiated after the equivocation block time must be paused"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"i.e. the underlying reference counter has to be increased.")),(0,o.kt)("p",null,"Note that even after the voting period has started, a proposal can receive\nadditional deposits. The hook is triggered however at arrival of a deposit, so\na check to verify that the proposal is not already in voting period is\nrequired."),(0,o.kt)("h3",{id:"when-unpause"},"When unpause"),(0,o.kt)("p",null,"We can use a ",(0,o.kt)("inlineCode",{parentName:"p"},"gov")," module's hook also here and it is\n",(0,o.kt)("inlineCode",{parentName:"p"},"AfterProposalVotingPeriodEnded"),"."),(0,o.kt)("p",null,"If the hook is triggered with an equivocation proposal, then for each\nassociated equivocation, the unbonding operations of the related validator that\nwere initiated between the equivocation block time and the start of the\nproposal voting period must be unpaused - i.e. decrease the underlying\nreference counter - regardless of the proposal outcome."),(0,o.kt)("h2",{id:"consequences"},"Consequences"),(0,o.kt)("h3",{id:"positive"},"Positive"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Validators subject to an equivocation proposal cannot finish unbonding\ntheir tokens before the end of the voting period.")),(0,o.kt)("h3",{id:"negative"},"Negative"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"A malicious consumer chain could forge slash packets enabling submission of\nan equivocation proposal on the provider chain, resulting in the freezing of\nvalidator's unbondings for an undeterminated amount of time."),(0,o.kt)("li",{parentName:"ul"},"Misbehavior on a consumer chain can potentially go unpunished, if no one\nsubmits an equivocation proposal in time, or if the proposal doesn't pass.")),(0,o.kt)("h3",{id:"neutral"},"Neutral"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"This feature can't be used for social slashing, because an equivocation\nproposal is only accepted if there's a slash log for the related\nvalidator(s), meaning the consumer chain has reported the equivocation to\nthe provider chain.")),(0,o.kt)("h2",{id:"references"},"References"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/747"},"https://github.com/cosmos/interchain-security/issues/747")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/791"},"https://github.com/cosmos/interchain-security/pull/791"))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/dee569d7.9ec14372.js b/legacy/assets/js/dee569d7.9ec14372.js new file mode 100644 index 0000000000..67ee5d6c4d --- /dev/null +++ b/legacy/assets/js/dee569d7.9ec14372.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1878],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,m=u["".concat(c,".").concat(h)]||u[h]||d[h]||i;return n?a.createElement(m,o(o({ref:t},p),{},{components:n})):a.createElement(m,o({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:r,o[1]=s;for(var l=2;l<i;l++)o[l]=n[l];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},6087:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var a=n(7462),r=(n(7294),n(3905));const i={sidebar_position:2,title:"Joining Replicated Security testnet"},o=void 0,s={unversionedId:"validators/joining-testnet",id:"version-v3.2.0/validators/joining-testnet",title:"Joining Replicated Security testnet",description:"Introduction",source:"@site/versioned_docs/version-v3.2.0/validators/joining-testnet.md",sourceDirName:"validators",slug:"/validators/joining-testnet",permalink:"/interchain-security/legacy/v3.2.0/validators/joining-testnet",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"Joining Replicated Security testnet"},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/legacy/v3.2.0/validators/overview"},next:{title:"Withdrawing consumer chain validator rewards",permalink:"/interchain-security/legacy/v3.2.0/validators/withdraw_rewards"}},c={},l=[{value:"Introduction",id:"introduction",level:2},{value:"Joining the provider chain",id:"joining-the-provider-chain",level:2},{value:"Initialization",id:"initialization",level:2},{value:"Joining consumer chains",id:"joining-consumer-chains",level:2},{value:"Re-using consensus key",id:"re-using-consensus-key",level:2},{value:"Assigning consensus keys",id:"assigning-consensus-keys",level:2}],p={toc:l},u="wrapper";function d(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"This short guide will teach you how to join the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security"},"Replicated Security testnet"),"."),(0,r.kt)("p",null,"The experience gained in the testnet will prepare you for validating interchain secured chains."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set."),(0,r.kt)("p",{parentName:"admonition"},"For general information about running cosmos-sdk based chains check out the ",(0,r.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html"},"validator basics")," and ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/main/run-node/run-node"},"Running a Node section")," of Cosmos SDK docs")),(0,r.kt)("h2",{id:"joining-the-provider-chain"},"Joining the provider chain"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain.")),(0,r.kt)("p",null,"A comprehensive guide is available ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security/provider"},"here"),"."),(0,r.kt)("h2",{id:"initialization"},"Initialization"),(0,r.kt)("p",null,"First, initialize your ",(0,r.kt)("inlineCode",{parentName:"p"},"$NODE_HOME")," using the ",(0,r.kt)("inlineCode",{parentName:"p"},"provider")," chain binary."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"NODE_MONIKER=<your_node>\nCHAIN_ID=provider\nNODE_HOME=<path_to_your_home>\n\ngaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME\n")),(0,r.kt)("p",null,"Add your key to the keyring - more details available ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/main/run-node/keyring"},"here"),"."),(0,r.kt)("p",null,"In this example we will use the ",(0,r.kt)("inlineCode",{parentName:"p"},"test")," keyring-backend. This option is not safe to use in production."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad keys add <key_moniker> --keyring-backend test\n\n# save the address as variable for later use\nMY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)\n")),(0,r.kt)("p",null,"Before issuing any transactions, use the ",(0,r.kt)("inlineCode",{parentName:"p"},"provider")," testnet faucet to add funds to your address."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider\n\n# example output:\n{\n "address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",\n "amount": "10000000uatom",\n "chain": "provider",\n "hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",\n "status": "success"\n}\n')),(0,r.kt)("p",null,"Then, use the account associated with the keyring to issue a ",(0,r.kt)("inlineCode",{parentName:"p"},"create-validator")," transaction which will register your validator on chain."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad tx staking create-validator \\\n --amount=1000000uatom \\\n --pubkey=$(gaiad tendermint show-validator) \\\n --moniker="choose a moniker" \\\n --chain-id=$CHAIN_ID" \\\n --commission-rate="0.10" \\\n --commission-max-rate="0.20" \\\n --commission-max-change-rate="0.01" \\\n --min-self-delegation="1000000" \\\n --gas="auto" \\\n --gas-prices="0.0025uatom" \\\n --from=<key_moniker>\n')),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Check this ",(0,r.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html#edit-validator-description"},"guide")," to edit your validator.")),(0,r.kt)("p",null,"After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use ",(0,r.kt)("inlineCode",{parentName:"p"},"statesync")," to catch up to the rest of the network."),(0,r.kt)("p",null,"You can use this script to modify your ",(0,r.kt)("inlineCode",{parentName:"p"},"config.toml")," with the required statesync parameters."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"# create the statesync script\n$: cd $NODE_HOME\n$: touch statesync.sh\n$ chmod 700 statesync.sh # make executable\n")),(0,r.kt)("p",null,"Paste the following instructions into the ",(0,r.kt)("inlineCode",{parentName:"p"},"statesync.sh"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'#!/bin/bash\n\nSNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"\n\nLATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \\\nBLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \\\nTRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)\n\nsed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\\1true| ; \\\ns|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\\1\\"$SNAP_RPC,$SNAP_RPC\\"| ; \\\ns|^(trust_height[[:space:]]+=[[:space:]]+).*$|\\1$BLOCK_HEIGHT| ; \\\ns|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\\1\\"$TRUST_HASH\\"|" $NODE_HOME/config/config.toml\n')),(0,r.kt)("p",null,"Then, you can execute the script:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"$: ./statesync.sh # setup config.toml for statesync\n")),(0,r.kt)("p",null,"Finally, copy the provider genesis and start your node:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/replicated-security/provider/provider-genesis.json\n$: wget $GENESIS_URL -O genesis.json\n$: genesis.json $NODE_HOME/config/genesis.json\n# start the service\n$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"\n')),(0,r.kt)("p",null,"Additional scripts to setup your nodes are available ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/provider/join-rs-provider.sh"},"here")," and ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/provider/join-rs-provider-cv.sh"},"here"),". The scripts will configure your node and create the required services - the scripts only work in linux environments."),(0,r.kt)("h2",{id:"joining-consumer-chains"},"Joining consumer chains"),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Once you reach the active set on the provider chain, you will be required to validate all available consumer chains."),(0,r.kt)("p",{parentName:"admonition"},"You can use the same consensus key on all consumer chains, or opt to use a different key on each consumer chain.\nCheck out this ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.2.0/features/key-assignment"},"guide")," to learn more about key assignment in replicated security.")),(0,r.kt)("p",null,"To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"When running the provider chain and consumers on the same machine please update the ",(0,r.kt)("inlineCode",{parentName:"p"},"PORT")," numbers for each of them and make sure they do not overlap (otherwise the binaries will not start)."),(0,r.kt)("p",{parentName:"admonition"},"Important ports to re-configure:"),(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--rpc.laddr")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--p2p.laddr")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--api.address")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--grpc.address")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--grpc-web.address")))),(0,r.kt)("h2",{id:"re-using-consensus-key"},"Re-using consensus key"),(0,r.kt)("p",null,"To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the ",(0,r.kt)("inlineCode",{parentName:"p"},"priv_validator_key.json")," into the home directory of your consumer chain (",(0,r.kt)("inlineCode",{parentName:"p"},"<consumer_home>/config/priv_validator_key.json"),")."),(0,r.kt)("p",null,"When you start the chain, the consensus key will be the same on the provider and the consumer chain."),(0,r.kt)("h2",{id:"assigning-consensus-keys"},"Assigning consensus keys"),(0,r.kt)("p",null,"Whenever you initialize a new node, it will be configured with a consensus key you can use."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'# machine running consumer chain\nconsumerd init <node_moniker> --home <home_path> --chain-id consumer-1\n\n# use the output of this command to get the consumer chain consensus key\nconsumerd tendermint show-validator\n# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}\n')),(0,r.kt)("p",null,"Then, let the provider know which key you will be using for the consumer chain:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"# machine running the provider chain\ngaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b sync -y -o json\n")),(0,r.kt)("p",null,"After this step, you are ready to copy the consumer genesis into your nodes's ",(0,r.kt)("inlineCode",{parentName:"p"},"/config")," folder, start your consumer chain node and catch up to the network."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/df2bbb5c.245ed571.js b/legacy/assets/js/df2bbb5c.245ed571.js new file mode 100644 index 0000000000..00efc1b8e1 --- /dev/null +++ b/legacy/assets/js/df2bbb5c.245ed571.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9832],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>m});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),d=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=d(e.components);return a.createElement(l.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=d(n),h=i,m=p["".concat(l,".").concat(h)]||p[h]||u[h]||r;return n?a.createElement(m,o(o({ref:t},c),{},{components:n})):a.createElement(m,o({ref:t},c))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:i,o[1]=s;for(var d=2;d<r;d++)o[d]=n[d];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},8543:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>s,toc:()=>d});var a=n(7462),i=(n(7294),n(3905));const r={sidebar_position:4},o="Validator instructions for Changeover Procedure",s={unversionedId:"validators/changeover-procedure",id:"version-v3.3.0/validators/changeover-procedure",title:"Validator instructions for Changeover Procedure",description:"More details available in Changeover Procedure documentation.",source:"@site/versioned_docs/version-v3.3.0/validators/changeover-procedure.md",sourceDirName:"validators",slug:"/validators/changeover-procedure",permalink:"/interchain-security/legacy/v3.3.0/validators/changeover-procedure",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Withdrawing consumer chain validator rewards",permalink:"/interchain-security/legacy/v3.3.0/validators/withdraw_rewards"},next:{title:"Joining Neutron",permalink:"/interchain-security/legacy/v3.3.0/validators/joining-neutron"}},l={},d=[{value:"Timeline",id:"timeline",level:2},{value:"1. <code>ConsumerAdditionProposal</code> on provider chain",id:"1-consumeradditionproposal-on-provider-chain",level:3},{value:"2. <code>SoftwareUpgradeProposal</code> on the standalone/consumer chain",id:"2-softwareupgradeproposal-on-the-standaloneconsumer-chain",level:3},{value:"3. Assigning a consumer key",id:"3-assigning-a-consumer-key",level:3},{value:"4. Perform the software ugprade on standalone chain",id:"4-perform-the-software-ugprade-on-standalone-chain",level:3},{value:"FAQ",id:"faq",level:2},{value:"Can I reuse the same validator key for the <code>consumer</code> chain that I am already using on the <code>standalone</code> chain? Will I need to perform a <code>AssignConsumerKey</code> tx with this key before spawn time?",id:"can-i-reuse-the-same-validator-key-for-the-consumer-chain-that-i-am-already-using-on-the-standalone-chain-will-i-need-to-perform-a-assignconsumerkey-tx-with-this-key-before-spawn-time",level:3},{value:"Can I continue using the same node that was validating the <code>standalone</code> chain?",id:"can-i-continue-using-the-same-node-that-was-validating-the-standalone-chain",level:3},{value:"Can I set up a new node to validate the <code>standalone/consumer</code> chain after it transitions to replicated security?",id:"can-i-set-up-a-new-node-to-validate-the-standaloneconsumer-chain-after-it-transitions-to-replicated-security",level:3},{value:"What happens to the <code>standalone</code> validator set after it after it transitions to replicated security?",id:"what-happens-to-the-standalone-validator-set-after-it-after-it-transitions-to-replicated-security",level:3},{value:"Credits",id:"credits",level:2}],c={toc:d},p="wrapper";function u(e){let{components:t,...r}=e;return(0,i.kt)(p,(0,a.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"validator-instructions-for-changeover-procedure"},"Validator instructions for Changeover Procedure"),(0,i.kt)("p",null,"More details available in ",(0,i.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/consumer-development/changeover-procedure"},"Changeover Procedure documentation"),"."),(0,i.kt)("p",null,"A major difference betwen launching a new consumer chain vs. onboarding a standalone chain to ICS is that there is no consumer genesis available for the standalone chain. Since a standalone chain already exists, its state must be preserved once it transitions to being a consumer chain."),(0,i.kt)("h2",{id:"timeline"},"Timeline"),(0,i.kt)("p",null,"Upgrading standalone chains can be best visualised using a timeline, such as the one available ",(0,i.kt)("a",{parentName:"p",href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt"},"Excalidraw graphic by Stride"),"."),(0,i.kt)("p",null,"There is some flexibility with regards to how the changeover procedure is executed, so please make sure to follow the guides provided by the team doing the changeover."),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"Standalone to consumer transition timeline",src:n(4191).Z,width:"5307",height:"2157"})),(0,i.kt)("h3",{id:"1-consumeradditionproposal-on-provider-chain"},"1. ",(0,i.kt)("inlineCode",{parentName:"h3"},"ConsumerAdditionProposal")," on provider chain"),(0,i.kt)("p",null,"This step will add the standalone chain to the list of consumer chains secured by the provider.\nThis step dictates the ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time"),". After ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," the CCV state (initial validator set of the provider) will be available to the consumer."),(0,i.kt)("p",null,"To obtain it from the provider use:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad q provider consumer-genesis stride-1 -o json > ccv-state.json\njq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' genesis.json ccv-state.json > ccv.json\n")),(0,i.kt)("h3",{id:"2-softwareupgradeproposal-on-the-standaloneconsumer-chain"},"2. ",(0,i.kt)("inlineCode",{parentName:"h3"},"SoftwareUpgradeProposal")," on the standalone/consumer chain"),(0,i.kt)("p",null,"This upgrade proposal will introduce ICS to the standalone chain, making it a consumer."),(0,i.kt)("h3",{id:"3-assigning-a-consumer-key"},"3. Assigning a consumer key"),(0,i.kt)("p",null,"After ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time"),", make sure to assign a consumer key if you intend to use one."),(0,i.kt)("p",null,"Instructions are available ",(0,i.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/features/key-assignment"},"here")),(0,i.kt)("h3",{id:"4-perform-the-software-ugprade-on-standalone-chain"},"4. Perform the software ugprade on standalone chain"),(0,i.kt)("p",null,"Please use instructions provided by the standalone chain team and make sure to reach out if you are facing issues.\nThe upgrade preparation depends on your setup, so please make sure you prepare ahead of time."),(0,i.kt)("admonition",{type:"danger"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"ccv.json")," from step 1. must be made available on the machine running the standalone/consumer chain at standalone chain ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height"),". This file contains the initial validator set and parameters required for normal ICS operation."),(0,i.kt)("p",{parentName:"admonition"},"Usually, the file is placed in ",(0,i.kt)("inlineCode",{parentName:"p"},"$NODE_HOME/config")," but this is not a strict requirement. The exact details are available in the upgrade code of the standalone/consumer chain.")),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Performing this upgrade will transition the standalone chain to be a consumer chain.")),(0,i.kt)("p",null,'After 3 blocks, the standalone chain will stop using the "old" validator set and begin using the ',(0,i.kt)("inlineCode",{parentName:"p"},"provider")," validator set."),(0,i.kt)("h2",{id:"faq"},"FAQ"),(0,i.kt)("h3",{id:"can-i-reuse-the-same-validator-key-for-the-consumer-chain-that-i-am-already-using-on-the-standalone-chain-will-i-need-to-perform-a-assignconsumerkey-tx-with-this-key-before-spawn-time"},"Can I reuse the same validator key for the ",(0,i.kt)("inlineCode",{parentName:"h3"},"consumer")," chain that I am already using on the ",(0,i.kt)("inlineCode",{parentName:"h3"},"standalone")," chain? Will I need to perform a ",(0,i.kt)("inlineCode",{parentName:"h3"},"AssignConsumerKey")," tx with this key before spawn time?"),(0,i.kt)("p",null,"Validators must either assign a key or use the same key as on the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider"),"."),(0,i.kt)("p",null,"If you are validating both the ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," and the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider"),", you ",(0,i.kt)("strong",{parentName:"p"},"can")," use your current ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," key with some caveats:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"you must submit an ",(0,i.kt)("inlineCode",{parentName:"li"},"AssignConsumerKey")," tx with your current ",(0,i.kt)("inlineCode",{parentName:"li"},"standalone")," validator key"),(0,i.kt)("li",{parentName:"ul"},"it is best to submit ",(0,i.kt)("inlineCode",{parentName:"li"},"AssignConsumerKey")," tx before ",(0,i.kt)("inlineCode",{parentName:"li"},"spawn_time")),(0,i.kt)("li",{parentName:"ul"},"if you do not submit the Tx, it is assumed that you will be re-using your ",(0,i.kt)("inlineCode",{parentName:"li"},"provider")," key to validate the ",(0,i.kt)("inlineCode",{parentName:"li"},"standalone/consumer")," chain")),(0,i.kt)("h3",{id:"can-i-continue-using-the-same-node-that-was-validating-the-standalone-chain"},"Can I continue using the same node that was validating the ",(0,i.kt)("inlineCode",{parentName:"h3"},"standalone")," chain?"),(0,i.kt)("p",null,"Yes."),(0,i.kt)("p",null,"Please assign your consensus key as stated aboce."),(0,i.kt)("h3",{id:"can-i-set-up-a-new-node-to-validate-the-standaloneconsumer-chain-after-it-transitions-to-replicated-security"},"Can I set up a new node to validate the ",(0,i.kt)("inlineCode",{parentName:"h3"},"standalone/consumer")," chain after it transitions to replicated security?"),(0,i.kt)("p",null,"Yes."),(0,i.kt)("p",null,"If you are planning to do this please make sure that the node is synced with ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," network and to submit ",(0,i.kt)("inlineCode",{parentName:"p"},"AssignConsumerKey")," tx before ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time"),"."),(0,i.kt)("h3",{id:"what-happens-to-the-standalone-validator-set-after-it-after-it-transitions-to-replicated-security"},"What happens to the ",(0,i.kt)("inlineCode",{parentName:"h3"},"standalone")," validator set after it after it transitions to replicated security?"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," chain validators will stop being validators after the first 3 blocks are created while using replicated security. The ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," validators will become ",(0,i.kt)("strong",{parentName:"p"},"governors")," and still can receive delegations if the ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer")," chain is using the ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer-democracy")," module."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Governors DO NOT VALIDATE BLOCKS"),"."),(0,i.kt)("p",null,"Instead, they can participate in the governance process and take on other chain-specific roles."),(0,i.kt)("h2",{id:"credits"},"Credits"),(0,i.kt)("p",null,"Thank you Stride team for providing detailed instructions about the changeover procedure."))}u.isMDXComponent=!0},4191:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/ics_changeover_timeline_stride-9bcad1834fef24a0fea7f2c80c9ccd71.png"}}]); \ No newline at end of file diff --git a/legacy/assets/js/df89b832.6fe61836.js b/legacy/assets/js/df89b832.6fe61836.js new file mode 100644 index 0000000000..ccde255ce0 --- /dev/null +++ b/legacy/assets/js/df89b832.6fe61836.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5059],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>h});var r=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function s(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?s(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):s(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function i(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},s=Object.keys(e);for(r=0;r<s.length;r++)t=s[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r<s.length;r++)t=s[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var d=r.createContext({}),l=function(e){var n=r.useContext(d),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=l(e.components);return r.createElement(d.Provider,{value:n},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,s=e.originalType,d=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),c=l(t),m=a,h=c["".concat(d,".").concat(m)]||c[m]||p[m]||s;return t?r.createElement(h,o(o({ref:n},u),{},{components:t})):r.createElement(h,o({ref:n},u))}));function h(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var s=t.length,o=new Array(s);o[0]=m;var i={};for(var d in n)hasOwnProperty.call(n,d)&&(i[d]=n[d]);i.originalType=e,i[c]="string"==typeof e?e:a,o[1]=i;for(var l=2;l<s;l++)o[l]=t[l];return r.createElement.apply(null,o)}return r.createElement.apply(null,t)}m.displayName="MDXCreateElement"},6619:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>p,frontMatter:()=>s,metadata:()=>i,toc:()=>l});var r=t(7462),a=(t(7294),t(3905));const s={sidebar_position:3,title:"Key Assignment"},o="ADR 001: Key Assignment",i={unversionedId:"adrs/adr-001-key-assignment",id:"version-v3.3.0/adrs/adr-001-key-assignment",title:"Key Assignment",description:"Changelog",source:"@site/versioned_docs/version-v3.3.0/adrs/adr-001-key-assignment.md",sourceDirName:"adrs",slug:"/adrs/adr-001-key-assignment",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-001-key-assignment",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Key Assignment"},sidebar:"tutorialSidebar",previous:{title:"ADR Template",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-template"},next:{title:"Jail Throttling",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-002-throttle"}},d={},l=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"State required",id:"state-required",level:3},{value:"Protocol overview",id:"protocol-overview",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],u={toc:l},c="wrapper";function p(e){let{components:n,...t}=e;return(0,a.kt)(c,(0,r.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-001-key-assignment"},"ADR 001: Key Assignment"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"2022-12-01: Initial Draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"It is possible to change the keys at any time by submitting a transaction (i.e., ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey"),")."),(0,a.kt)("h3",{id:"state-required"},"State required"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorConsumerPubKey")," - Stores the validator assigned keys for every consumer chain.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorByConsumerAddr")," - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"KeyAssignmentReplacements")," - Stores the key assignments that need to be replaced in the current block. Needed to apply the key assignments received in a block to the validator updates sent to the consumer chains.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"KeyAssignmentReplacementsBytePrefix | len(chainID) | chainID | providerConsAddress -> abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower},\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ConsumerAddrsToPrune")," - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ",(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorByConsumerAddr"),". ")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses\n")),(0,a.kt)("h3",{id:"protocol-overview"},"Protocol overview"),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey(chainID, providerAddr, consumerKey)")," message:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"// get validator from staking module \nvalidator, found := stakingKeeper.GetValidator(providerAddr)\nif !found {\n return ErrNoValidatorFound\n}\nproviderConsAddr := validator.GetConsAddr()\n\n// make sure consumer key is not in use\nconsumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)\nif _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {\n return ErrInvalidConsumerConsensusPubKey\n}\n\n// check whether the consumer chain is already registered\n// i.e., a client to the consumer was already created\nif _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {\n // get the previous key assigned for this validator on this consumer chain\n oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)\n if found {\n // mark this old consumer key as prunable once the VSCMaturedPacket\n // for the current VSC ID is received\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n vscID := GetValidatorSetUpdateId()\n AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)\n } else {\n // the validator had no key assigned on this consumer chain\n oldConsumerKey := validator.TmConsPublicKey()\n }\n\n // check whether the validator is valid, i.e., its power is positive\n if currentPower := stakingKeeper.GetLastValidatorPower(providerAddr); currentPower > 0 {\n // to enable multiple calls of AssignConsumerKey in the same block by the same validator\n // the key assignment replacement should not be overwritten\n if _, found := GetKeyAssignmentReplacement(chainID, providerConsAddr); !found {\n // store old key and power for modifying the valset update in EndBlock\n oldKeyAssignment := abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower}\n SetKeyAssignmentReplacement(chainID, providerConsAddr, oldKeyAssignment)\n }\n }\n} else {\n // if the consumer chain is not registered, then remove the previous reverse mapping\n if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)\n }\n}\n\n\n// set the mapping from this validator's provider address to the new consumer key\nSetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)\n\n// set the reverse mapping: from this validator's new consensus address \n// on the consumer to its consensus address on the provider\nSetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)\n")),(0,a.kt)("p",null,"When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see ",(0,a.kt)("inlineCode",{parentName:"p"},"MakeConsumerGenesis"),"). "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {\n // ...\n // get initial valset from the staking module\n var updates []abci.ValidatorUpdate{}\n stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {\n validator := stakingKeeper.GetValidator(providerAddr)\n providerKey := validator.TmConsPublicKey()\n updates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})\n return false\n })\n\n // applies the key assignment to the initial validator\n for i, update := range updates {\n providerAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)\n if consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {\n updates[i].PubKey = consumerKey\n }\n }\n gen.InitialValSet = updates\n\n // get a hash of the consumer validator set from the update\n updatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)\n hash := tendermint.NewValidatorSet(updatesAsValSet).Hash()\n\n return gen, hash, nil\n}\n")),(0,a.kt)("p",null,"On ",(0,a.kt)("inlineCode",{parentName:"p"},"EndBlock")," while queueing ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCPacket"),"s to send to registered consumer chains:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func QueueVSCPackets() {\n valUpdateID := GetValidatorSetUpdateId()\n // get the validator updates from the staking module\n valUpdates := stakingKeeper.GetValidatorUpdates()\n\n IterateConsumerChains(func(chainID, clientID string) (stop bool) {\n // apply the key assignment to the validator updates\n valUpdates := ApplyKeyAssignmentToValUpdates(chainID, valUpdates)\n // ..\n })\n // ...\n}\n\nfunc ApplyKeyAssignmentToValUpdates(\n chainID string, \n valUpdates []abci.ValidatorUpdate,\n) (newUpdates []abci.ValidatorUpdate) {\n for _, valUpdate := range valUpdates {\n providerAddr := utils.TMCryptoPublicKeyToConsAddr(valUpdate.PubKey)\n\n // if a key assignment replacement is found, then\n // remove the valupdate with the old consumer key\n // and create two new valupdates\n prevConsumerKey, _, found := GetKeyAssignmentReplacement(chainID, providerAddr)\n if found {\n // set the old consumer key's power to 0\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: prevConsumerKey,\n Power: 0,\n })\n // set the new consumer key's power to the power in the update\n newConsumerKey := GetValidatorConsumerPubKey(chainID, providerAddr)\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: newConsumerKey,\n Power: valUpdate.Power,\n })\n // delete key assignment replacement\n DeleteKeyAssignmentReplacement(chainID, providerAddr)\n } else {\n // there is no key assignment replacement;\n // check if the validator's key is assigned\n consumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr)\n if found {\n // replace the update containing the provider key \n // with an update containing the consumer key\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: consumerKey,\n Power: valUpdate.Power,\n })\n } else {\n // keep the same update\n newUpdates = append(newUpdates, valUpdate)\n }\n }\n }\n\n // iterate over the remaining key assignment replacements\n IterateKeyAssignmentReplacements(chainID, func(\n pAddr sdk.ConsAddress,\n prevCKey tmprotocrypto.PublicKey,\n power int64,\n ) (stop bool) {\n // set the old consumer key's power to 0\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: prevCKey,\n Power: 0,\n })\n // set the new consumer key's power to the power in key assignment replacement\n newConsumerKey := GetValidatorConsumerPubKey(chainID, pAddr)\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: newConsumerKey,\n Power: power,\n })\n return false\n })\n\n // remove all the key assignment replacements\n \n return newUpdates\n}\n")),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"SlashPacket")," from a consumer chain with id ",(0,a.kt)("inlineCode",{parentName:"p"},"chainID")," for a infraction of a validator ",(0,a.kt)("inlineCode",{parentName:"p"},"data.Validator"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {\n // ...\n // the slash packet validator address may be known only on the consumer chain;\n // in this case, it must be mapped back to the consensus address on the provider chain\n consumerAddr := sdk.ConsAddress(data.Validator.Address)\n providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)\n if !found {\n // the validator has the same key on the consumer as on the provider\n providerAddr = consumer\n }\n // ...\n}\n")),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCMatured"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {\n // ...\n // prune previous consumer validator address that are no longer needed\n consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n for _, addr := range consumerAddrs {\n DeleteValidatorByConsumerAddr(chainID, addr)\n }\n DeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n // ...\n}\n")),(0,a.kt)("p",null,"On stopping a consumer chain:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {\n // ...\n // deletes all the state needed for key assignments on this consumer chain\n // ...\n}\n")),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Validators can use different consensus keys on the consumer chains.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"None")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"The consensus state necessary to create a client to the consumer chain must use the hash returned by the ",(0,a.kt)("inlineCode",{parentName:"li"},"MakeConsumerGenesis")," method as the ",(0,a.kt)("inlineCode",{parentName:"li"},"nextValsHash"),"."),(0,a.kt)("li",{parentName:"ul"},"The consumer chain can no longer check the initial validator set against the consensus state on ",(0,a.kt)("inlineCode",{parentName:"li"},"InitGenesis"),".")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/26"},"Key assignment issue"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/e1611597.55aa8324.js b/legacy/assets/js/e1611597.55aa8324.js new file mode 100644 index 0000000000..5c52050584 --- /dev/null +++ b/legacy/assets/js/e1611597.55aa8324.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9300],{3905:(e,r,t)=>{t.d(r,{Zo:()=>l,kt:()=>f});var n=t(7294);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function o(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?i(Object(t),!0).forEach((function(r){a(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function c(e,r){if(null==e)return{};var t,n,a=function(e,r){if(null==e)return{};var t,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=n.createContext({}),u=function(e){var r=n.useContext(s),t=r;return e&&(t="function"==typeof e?e(r):o(o({},r),e)),t},l=function(e){var r=u(e.components);return n.createElement(s.Provider,{value:r},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},p=n.forwardRef((function(e,r){var t=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),d=u(t),p=a,f=d["".concat(s,".").concat(p)]||d[p]||m[p]||i;return t?n.createElement(f,o(o({ref:r},l),{},{components:t})):n.createElement(f,o({ref:r},l))}));function f(e,r){var t=arguments,a=r&&r.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=p;var c={};for(var s in r)hasOwnProperty.call(r,s)&&(c[s]=r[s]);c.originalType=e,c[d]="string"==typeof e?e:a,o[1]=c;for(var u=2;u<i;u++)o[u]=t[u];return n.createElement.apply(null,o)}return n.createElement.apply(null,t)}p.displayName="MDXCreateElement"},2307:(e,r,t)=>{t.d(r,{Z:()=>i});var n=t(7294);const a=function(e){return n.createElement("a",{href:e.href,className:"border shadow rounded-sm border-stone-200 dark:border-stone-800 dark:bg-neutral-900 hover:border-stone-300 hover:shadow-lg dark:hover:border-stone-200 transition-all duration-200 no-underline"},n.createElement("div",{className:"p-6"},n.createElement("h2",{className:""},e.header),n.createElement("p",{className:""},e.summary)))};const i=function(e){return n.createElement("div",{className:"card-section grid grid-cols-1 lg:grid-cols-2 gap-4 no-underline"},e.cards.map(((e,r)=>n.createElement(a,{key:r,href:e.href,header:e.header,summary:e.summary}))))}},8758:(e,r,t)=>{t.d(r,{Z:()=>n});const n=[{href:"/interchain-security/introduction/overview",header:"Basic concepts",summary:"Get started with the basic concepts and ideas."},{href:"/interchain-security/consumer-development/app-integration",header:"Start building",summary:"Click here to start building with Interchain security"},{href:"/interchain-security/features/key-assignment",header:"Feature: Key Assignment",summary:"Learn about the key assignment feature"},{href:"/interchain-security/features/reward-distribution",header:"Feature: Reward Distribution",summary:"Learn about consumer chain rewards distribution"},{href:"/interchain-security/consumer-development/onboarding",header:"Onboarding Checklist",summary:"Checklist to help you integrate Interchain Security, get support and onboard validators"},{href:"/interchain-security/faq",header:"FAQ",summary:"Frequently asked questions about the protocol and its implications"}]},7033:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>l,contentTitle:()=>s,default:()=>f,frontMatter:()=>c,metadata:()=>u,toc:()=>d});var n=t(7462),a=(t(7294),t(3905)),i=t(2307),o=t(8758);const c={sidebar_position:1},s="Interchain Security Docs",u={unversionedId:"index",id:"version-v2.4.0-lsm/index",title:"Interchain Security Docs",description:"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.",source:"@site/versioned_docs/version-v2.4.0-lsm/index.mdx",sourceDirName:".",slug:"/",permalink:"/interchain-security/legacy/v2.4.0-lsm/",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",next:{title:"Overview",permalink:"/interchain-security/legacy/v2.4.0-lsm/introduction/overview"}},l={},d=[],m={toc:d},p="wrapper";function f(e){let{components:r,...t}=e;return(0,a.kt)(p,(0,n.Z)({},m,t,{components:r,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"interchain-security-docs"},"Interchain Security Docs"),(0,a.kt)("p",null,"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains."),(0,a.kt)("p",null,"Here you can find information about replicated security, consumer chain development and instructions for validator onboarding."),(0,a.kt)(i.Z,{cards:o.Z,mdxType:"CardSection"}))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/e181537f.5447d3b6.js b/legacy/assets/js/e181537f.5447d3b6.js new file mode 100644 index 0000000000..9f8e978036 --- /dev/null +++ b/legacy/assets/js/e181537f.5447d3b6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5680],{3905:(e,t,o)=>{o.d(t,{Zo:()=>c,kt:()=>m});var n=o(7294);function a(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function r(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,n)}return o}function i(e){for(var t=1;t<arguments.length;t++){var o=null!=arguments[t]?arguments[t]:{};t%2?r(Object(o),!0).forEach((function(t){a(e,t,o[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(o)):r(Object(o)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(o,t))}))}return e}function l(e,t){if(null==e)return{};var o,n,a=function(e,t){if(null==e)return{};var o,n,a={},r=Object.keys(e);for(n=0;n<r.length;n++)o=r[n],t.indexOf(o)>=0||(a[o]=e[o]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n<r.length;n++)o=r[n],t.indexOf(o)>=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(a[o]=e[o])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),o=t;return e&&(o="function"==typeof e?e(t):i(i({},t),e)),o},c=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var o=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=u(o),h=a,m=d["".concat(s,".").concat(h)]||d[h]||p[h]||r;return o?n.createElement(m,i(i({ref:t},c),{},{components:o})):n.createElement(m,i({ref:t},c))}));function m(e,t){var o=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=o.length,i=new Array(r);i[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,i[1]=l;for(var u=2;u<r;u++)i[u]=o[u];return n.createElement.apply(null,i)}return n.createElement.apply(null,o)}h.displayName="MDXCreateElement"},159:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>p,frontMatter:()=>r,metadata:()=>l,toc:()=>u});var n=o(7462),a=(o(7294),o(3905));const r={sidebar_position:10,title:"Soft Opt-Out"},i=void 0,l={unversionedId:"adrs/adr-009-soft-opt-out",id:"version-v3.3.0/adrs/adr-009-soft-opt-out",title:"Soft Opt-Out",description:"ADR 009: Soft Opt-Out",source:"@site/versioned_docs/version-v3.3.0/adrs/adr-009-soft-opt-out.md",sourceDirName:"adrs",slug:"/adrs/adr-009-soft-opt-out",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-009-soft-opt-out",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:10,frontMatter:{sidebar_position:10,title:"Soft Opt-Out"},sidebar:"tutorialSidebar",previous:{title:"Throttle with retries",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-008-throttle-retries"},next:{title:"Standalone to Consumer Changeover",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-010-standalone-changeover"}},s={},u=[{value:"ADR 009: Soft Opt-Out",id:"adr-009-soft-opt-out",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],c={toc:u},d="wrapper";function p(e){let{components:t,...o}=e;return(0,a.kt)(d,(0,n.Z)({},c,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"adr-009-soft-opt-out"},"ADR 009: Soft Opt-Out"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"6/13/23: Initial draft of ADR. Feature already implemented and in production.")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"Some small validators may not have the resources needed to validate all consumer chains. Therefore a need exists to allow the bottom ",(0,a.kt)("inlineCode",{parentName:"p"},"x%")," of validators to opt-out of validating a consumer chain. Meaning downtime infractions for these validators are dropped without ever reaching the provider."),(0,a.kt)("p",null,"This document specifies a modification to the ccv protocol which allows the bottom x% of the validator set by power to opt out of validating consumer chains without being jailed or otherwise punished for it. The feature is implemented with entirely consumer-side code."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"A consumer param exists, known as ",(0,a.kt)("inlineCode",{parentName:"p"},"SoftOptOutThreshold"),", which is a string decimal in the range of ","[0, 0.2]",", that determines the portion of validators which are allowed to opt out of validating that specific consumer."),(0,a.kt)("p",null,"In every consumer beginblocker, a function is ran which determines the so called ",(0,a.kt)("em",{parentName:"p"},"smallest non opt-out voting power"),". Validators with voting power greater than or equal to this value must validate the consumer chain, while validators below this value may opt out of validating the consumer chain."),(0,a.kt)("p",null,"The smallest non opt-out voting power is recomputed every beginblocker in ",(0,a.kt)("inlineCode",{parentName:"p"},"UpdateSmallestNonOptOutPower()"),". In a nutshell, the method obtains the total voting power of the consumer, iterates through the full valset (ordered power ascending) keeping track of a power sum, and when ",(0,a.kt)("inlineCode",{parentName:"p"},"powerSum / totalPower > SoftOptOutThreshold"),", the ",(0,a.kt)("inlineCode",{parentName:"p"},"SmallestNonOptOutPower")," is found and persisted."),(0,a.kt)("p",null,"Then, whenever the ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash()")," interface is executed on the consumer, if the voting power of the relevant validator being slashed is less than ",(0,a.kt)("inlineCode",{parentName:"p"},"SmallestNonOptOutPower")," for that block, the slash request is dropped and never sent to the provider."),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Small validators can opt out of validating specific consumers without being punished for it.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"The bottom ",(0,a.kt)("inlineCode",{parentName:"li"},"x%")," is still part of the total voting power of the consumer chain. This means that if the soft opt-out threshold is set to ",(0,a.kt)("inlineCode",{parentName:"li"},"10%")," for example, and every validator in the bottom ",(0,a.kt)("inlineCode",{parentName:"li"},"10%")," opts out from validating the consumer, then a ",(0,a.kt)("inlineCode",{parentName:"li"},"24%")," downtime of the remaining voting power would halt the chain. This may be especially problematic during consumer upgrades."),(0,a.kt)("li",{parentName:"ul"},"In nominal scenarios, consumers with soft opt out enabled will be constructing slash packets for small vals, which may be dropped. This is wasted computation, but necessary to keep implementation simple. Note that the sdk's ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/cosmos-sdk/blob/d3f09c222243bb3da3464969f0366330dcb977a8/x/slashing/keeper/infractions.go#L75"},"full downtime logic")," is always executed on the consumer, which can be computationally expensive and slow down certain blocks.")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Validators in the bottom of the valset who don't have to validate, may receive large delegation(s) which suddenly boost the validator to the subset that has to validate. This may catch the validator off guard.")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Original issue with some napkin math ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/784"},"#784"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/e23b6b4c.19be60c2.js b/legacy/assets/js/e23b6b4c.19be60c2.js new file mode 100644 index 0000000000..0bec15a791 --- /dev/null +++ b/legacy/assets/js/e23b6b4c.19be60c2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5349],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>m});var i=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?r(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):r(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,i,a=function(e,n){if(null==e)return{};var t,i,a={},r=Object.keys(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=i.createContext({}),c=function(e){var n=i.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},p=function(e){var n=c(e.components);return i.createElement(l.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},h=i.forwardRef((function(e,n){var t=e.components,a=e.mdxType,r=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(t),h=a,m=d["".concat(l,".").concat(h)]||d[h]||u[h]||r;return t?i.createElement(m,o(o({ref:n},p),{},{components:t})):i.createElement(m,o({ref:n},p))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var r=t.length,o=new Array(r);o[0]=h;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:a,o[1]=s;for(var c=2;c<r;c++)o[c]=t[c];return i.createElement.apply(null,o)}return i.createElement.apply(null,t)}h.displayName="MDXCreateElement"},5516:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>s,toc:()=>c});var i=t(7462),a=(t(7294),t(3905));const r={sidebar_position:1},o="Overview",s={unversionedId:"validators/overview",id:"version-v2.0.0/validators/overview",title:"Overview",description:"We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.",source:"@site/versioned_docs/version-v2.0.0/validators/overview.md",sourceDirName:"validators",slug:"/validators/overview",permalink:"/interchain-security/legacy/v2.0.0/validators/overview",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Offboarding Checklist",permalink:"/interchain-security/legacy/v2.0.0/consumer-development/offboarding"},next:{title:"Joining Replicated Security testnet",permalink:"/interchain-security/legacy/v2.0.0/validators/joining-testnet"}},l={},c=[{value:"Startup sequence overview",id:"startup-sequence-overview",level:2},{value:"1. Consumer Chain init + 2. Genesis generation",id:"1-consumer-chain-init--2-genesis-generation",level:3},{value:"3. Submit Proposal",id:"3-submit-proposal",level:3},{value:"4. CCV Genesis state generation",id:"4-ccv-genesis-state-generation",level:3},{value:"5. Updating the genesis file",id:"5-updating-the-genesis-file",level:3},{value:"6. Chain start",id:"6-chain-start",level:3},{value:"7. Creating IBC connections",id:"7-creating-ibc-connections",level:3},{value:"Downtime Infractions",id:"downtime-infractions",level:2},{value:"Double-signing Infractions",id:"double-signing-infractions",level:2},{value:"Key assignment",id:"key-assignment",level:2},{value:"References:",id:"references",level:2}],p={toc:c},d="wrapper";function u(e){let{components:n,...r}=e;return(0,a.kt)(d,(0,i.Z)({},p,r,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"overview"},"Overview"),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"We advise that you join the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security"},"Replicated Security testnet")," to gain hands-on experience with running consumer chains.")),(0,a.kt)("p",null,"At present, replicated security requires all validators of the provider chain (ie. Cosmos Hub) to run validator nodes for all governance-approved consumer chains."),(0,a.kt)("p",null,"Once a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," passes, validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains."),(0,a.kt)("p",null,"Provider chain and consumer chains represent standalone chains that only share the validator set ie. the same validator operators are tasked with running all chains."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 175 validators for Cosmos Hub).")),(0,a.kt)("h2",{id:"startup-sequence-overview"},"Startup sequence overview"),(0,a.kt)("p",null,"Consumer chains cannot start and be secured by the validator set of the provider unless a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," is passed.\nEach proposal contains defines a ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider."),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"Validators are required to run consumer chain binaries only after ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," has passed.")),(0,a.kt)("p",null,"Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains."),(0,a.kt)("p",null,"The image below illustrates the startup sequence\n",(0,a.kt)("img",{alt:"startup",src:t(7728).Z,width:"942",height:"632"})),(0,a.kt)("h3",{id:"1-consumer-chain-init--2-genesis-generation"},"1. Consumer Chain init + 2. Genesis generation"),(0,a.kt)("p",null,"Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")),(0,a.kt)("h3",{id:"3-submit-proposal"},"3. Submit Proposal"),(0,a.kt)("p",null,"Consumer chain team (or their advocates) submits a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal"),".\nThe most important parameters for validators are:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"spawn_time")," - the time after which the consumer chain must be started"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"genesis_hash")," - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and ",(0,a.kt)("inlineCode",{parentName:"li"},"spawn_time")," is reached"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"binary_hash")," - hash of the consumer chain binary used to validate the software builds")),(0,a.kt)("h3",{id:"4-ccv-genesis-state-generation"},"4. CCV Genesis state generation"),(0,a.kt)("p",null,"After reaching ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json"),". The CCV validator set consists of the validator set on the provider at ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time"),"."),(0,a.kt)("p",null,"The state can be queried on the provider chain (in this case the Cosmos Hub):"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json\n")),(0,a.kt)("p",null,"This is used by the launch coordinator to create the final ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," that will be distributed to validators in step 5."),(0,a.kt)("h3",{id:"5-updating-the-genesis-file"},"5. Updating the genesis file"),(0,a.kt)("p",null,"Upon reaching the ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," the initial validator set state will become available on the provider chain. The initial validator set is included in the ",(0,a.kt)("strong",{parentName:"p"},"final genesis.json")," of the consumer chain."),(0,a.kt)("h3",{id:"6-chain-start"},"6. Chain start"),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences.")),(0,a.kt)("p",null,"The new ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," to start their consumer chain node."),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"Please pay attention to any onboarding repositories provided by the consumer chain teams.\nRecommendations are available in ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.0.0/consumer-development/onboarding"},"Consumer Onboarding Checklist"),".\nAnother comprehensive guide is available in the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md"},"Replicated Security testnet repo"),".")),(0,a.kt)("h3",{id:"7-creating-ibc-connections"},"7. Creating IBC connections"),(0,a.kt)("p",null,"Finally, to fully establish replicated security an IBC relayer is used to establish connections and create the required channels."),(0,a.kt)("admonition",{type:"warning"},(0,a.kt)("p",{parentName:"admonition"},"The relayer can establish the connection only after the consumer chain starts producing blocks.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> \nhermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1\nhermes start\n")),(0,a.kt)("h2",{id:"downtime-infractions"},"Downtime Infractions"),(0,a.kt)("p",null,"At present, the consumer chain can report evidence about downtime infractions to the provider chain. The ",(0,a.kt)("inlineCode",{parentName:"p"},"min_signed_per_window")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"signed_blocks_window")," can be different on each consumer chain and are subject to changes via consumer chain governance."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains."),(0,a.kt)("p",{parentName:"admonition"},"To unjail, the validator must wait for the jailing period to elapse on the provider chain and ",(0,a.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html#unjail-validator"},"submit an unjail transaction")," on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains."),(0,a.kt)("p",{parentName:"admonition"},"More information is available in ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.0.0/features/slashing#downtime-infractions"},"Downtime Slashing documentation"))),(0,a.kt)("h2",{id:"double-signing-infractions"},"Double-signing Infractions"),(0,a.kt)("p",null,"To learn more about equivocation handling in replicated security check out the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.0.0/features/slashing#double-signing-equivocation"},"Slashing")," and ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.0.0/features/proposals#equivocationproposal"},"EquivocationProposal")," documentation sections"),(0,a.kt)("h2",{id:"key-assignment"},"Key assignment"),(0,a.kt)("p",null,"Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use."),(0,a.kt)("p",null,"For more information check our the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.0.0/features/key-assignment"},"Key assignment overview and guide")),(0,a.kt)("h2",{id:"references"},"References:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-faq.html"},"Cosmos Hub Validators FAQ")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-setup.html"},"Cosmos Hub Running a validator")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md#chain-launch"},"Startup Sequence")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-setup.html#unjail-validator"},"Submit Unjailing Transaction"))))}u.isMDXComponent=!0},7728:(e,n,t)=>{t.d(n,{Z:()=>i});const i=t.p+"assets/images/hypha-consumer-start-process-2141109f76c584706dd994d7965fd692.svg"}}]); \ No newline at end of file diff --git a/legacy/assets/js/e3e9e529.4655caa7.js b/legacy/assets/js/e3e9e529.4655caa7.js new file mode 100644 index 0000000000..c68db90da3 --- /dev/null +++ b/legacy/assets/js/e3e9e529.4655caa7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3302],{369:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"v3.3.0","label":"v3.3.0","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-v3.3.0","isLast":false,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Interchain Security Docs","href":"/interchain-security/legacy/v3.3.0/","docId":"index"},{"type":"category","label":"Introduction","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/legacy/v3.3.0/introduction/overview","docId":"introduction/overview"},{"type":"link","label":"Terminology","href":"/interchain-security/legacy/v3.3.0/introduction/terminology","docId":"introduction/terminology"},{"type":"link","label":"Interchain Security Parameters","href":"/interchain-security/legacy/v3.3.0/introduction/params","docId":"introduction/params"},{"type":"link","label":"Technical Specification","href":"/interchain-security/legacy/v3.3.0/introduction/technical-specification","docId":"introduction/technical-specification"}]},{"type":"category","label":"Features","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Key Assignment","href":"/interchain-security/legacy/v3.3.0/features/key-assignment","docId":"features/key-assignment"},{"type":"link","label":"Reward distribution","href":"/interchain-security/legacy/v3.3.0/features/reward-distribution","docId":"features/reward-distribution"},{"type":"link","label":"ICS Provider Proposals","href":"/interchain-security/legacy/v3.3.0/features/proposals","docId":"features/proposals"},{"type":"link","label":"Consumer Initiated Slashing","href":"/interchain-security/legacy/v3.3.0/features/slashing","docId":"features/slashing"}]},{"type":"category","label":"Consumer Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Developing an ICS consumer chain","href":"/interchain-security/legacy/v3.3.0/consumer-development/app-integration","docId":"consumer-development/app-integration"},{"type":"link","label":"Consumer Chain Governance","href":"/interchain-security/legacy/v3.3.0/consumer-development/consumer-chain-governance","docId":"consumer-development/consumer-chain-governance"},{"type":"link","label":"Onboarding Checklist","href":"/interchain-security/legacy/v3.3.0/consumer-development/onboarding","docId":"consumer-development/onboarding"},{"type":"link","label":"Offboarding Checklist","href":"/interchain-security/legacy/v3.3.0/consumer-development/offboarding","docId":"consumer-development/offboarding"},{"type":"link","label":"Changeover Procedure","href":"/interchain-security/legacy/v3.3.0/consumer-development/changeover-procedure","docId":"consumer-development/changeover-procedure"},{"type":"link","label":"Consumer Genesis Transformation","href":"/interchain-security/legacy/v3.3.0/consumer-development/consumer-genesis-transformation","docId":"consumer-development/consumer-genesis-transformation"}]},{"type":"category","label":"Validators Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/legacy/v3.3.0/validators/overview","docId":"validators/overview"},{"type":"link","label":"Joining Replicated Security testnet","href":"/interchain-security/legacy/v3.3.0/validators/joining-testnet","docId":"validators/joining-testnet"},{"type":"link","label":"Withdrawing consumer chain validator rewards","href":"/interchain-security/legacy/v3.3.0/validators/withdraw_rewards","docId":"validators/withdraw_rewards"},{"type":"link","label":"Validator instructions for Changeover Procedure","href":"/interchain-security/legacy/v3.3.0/validators/changeover-procedure","docId":"validators/changeover-procedure"},{"type":"link","label":"Joining Neutron","href":"/interchain-security/legacy/v3.3.0/validators/joining-neutron","docId":"validators/joining-neutron"},{"type":"link","label":"Joining Stride","href":"/interchain-security/legacy/v3.3.0/validators/joining-stride","docId":"validators/joining-stride"}]},{"type":"link","label":"Frequently Asked Questions","href":"/interchain-security/legacy/v3.3.0/faq","docId":"frequently-asked-questions"},{"type":"category","label":"ADRs","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"ADRs","href":"/interchain-security/legacy/v3.3.0/adrs/intro","docId":"adrs/intro"},{"type":"link","label":"ADR Template","href":"/interchain-security/legacy/v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-prop","docId":"adrs/adr-007-pause-unbonding-on-eqv-prop"},{"type":"link","label":"ADR Template","href":"/interchain-security/legacy/v3.3.0/adrs/adr-template","docId":"adrs/adr-template"},{"type":"link","label":"Key Assignment","href":"/interchain-security/legacy/v3.3.0/adrs/adr-001-key-assignment","docId":"adrs/adr-001-key-assignment"},{"type":"link","label":"Jail Throttling","href":"/interchain-security/legacy/v3.3.0/adrs/adr-002-throttle","docId":"adrs/adr-002-throttle"},{"type":"link","label":"Equivocation governance proposal","href":"/interchain-security/legacy/v3.3.0/adrs/adr-003-equivocation-gov-proposal","docId":"adrs/adr-003-equivocation-gov-proposal"},{"type":"link","label":"Cryptographic verification of equivocation evidence","href":"/interchain-security/legacy/v3.3.0/adrs/adr-005-cryptographic-equivocation-verification","docId":"adrs/adr-005-cryptographic-equivocation-verification"},{"type":"link","label":"Throttle with retries","href":"/interchain-security/legacy/v3.3.0/adrs/adr-008-throttle-retries","docId":"adrs/adr-008-throttle-retries"},{"type":"link","label":"Soft Opt-Out","href":"/interchain-security/legacy/v3.3.0/adrs/adr-009-soft-opt-out","docId":"adrs/adr-009-soft-opt-out"},{"type":"link","label":"Standalone to Consumer Changeover","href":"/interchain-security/legacy/v3.3.0/adrs/adr-010-standalone-changeover","docId":"adrs/adr-010-standalone-changeover"},{"type":"link","label":"Improving testing and increasing confidence","href":"/interchain-security/legacy/v3.3.0/adrs/adr-011-improving-test-confidence","docId":"adrs/adr-011-improving-test-confidence"},{"type":"link","label":"Separate Releasing","href":"/interchain-security/legacy/v3.3.0/adrs/adr-012-separate-releasing","docId":"adrs/adr-012-separate-releasing"},{"type":"link","label":"Slashing on the provider for consumer equivocation","href":"/interchain-security/legacy/v3.3.0/adrs/adr-013-equivocation-slashing","docId":"adrs/adr-013-equivocation-slashing"}]}]},"docs":{"adrs/adr-001-key-assignment":{"id":"adrs/adr-001-key-assignment","title":"Key Assignment","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-002-throttle":{"id":"adrs/adr-002-throttle","title":"Jail Throttling","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-003-equivocation-gov-proposal":{"id":"adrs/adr-003-equivocation-gov-proposal","title":"Equivocation governance proposal","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-005-cryptographic-equivocation-verification":{"id":"adrs/adr-005-cryptographic-equivocation-verification","title":"Cryptographic verification of equivocation evidence","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-007-pause-unbonding-on-eqv-prop":{"id":"adrs/adr-007-pause-unbonding-on-eqv-prop","title":"ADR Template","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-008-throttle-retries":{"id":"adrs/adr-008-throttle-retries","title":"Throttle with retries","description":"ADR 008: Throttle with retries","sidebar":"tutorialSidebar"},"adrs/adr-009-soft-opt-out":{"id":"adrs/adr-009-soft-opt-out","title":"Soft Opt-Out","description":"ADR 009: Soft Opt-Out","sidebar":"tutorialSidebar"},"adrs/adr-010-standalone-changeover":{"id":"adrs/adr-010-standalone-changeover","title":"Standalone to Consumer Changeover","description":"ADR 010: Standalone to Consumer Changeover","sidebar":"tutorialSidebar"},"adrs/adr-011-improving-test-confidence":{"id":"adrs/adr-011-improving-test-confidence","title":"Improving testing and increasing confidence","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-012-separate-releasing":{"id":"adrs/adr-012-separate-releasing","title":"Separate Releasing","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-013-equivocation-slashing":{"id":"adrs/adr-013-equivocation-slashing","title":"Slashing on the provider for consumer equivocation","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-template":{"id":"adrs/adr-template","title":"ADR Template","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/intro":{"id":"adrs/intro","title":"ADRs","description":"This is a location to record all high-level architecture decisions in the Interchain Security project.","sidebar":"tutorialSidebar"},"consumer-development/app-integration":{"id":"consumer-development/app-integration","title":"Developing an ICS consumer chain","description":"When developing an ICS consumer chain, besides just focusing on your chain\'s logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.","sidebar":"tutorialSidebar"},"consumer-development/changeover-procedure":{"id":"consumer-development/changeover-procedure","title":"Changeover Procedure","description":"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.","sidebar":"tutorialSidebar"},"consumer-development/consumer-chain-governance":{"id":"consumer-development/consumer-chain-governance","title":"Consumer Chain Governance","description":"Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the \\"Whitelist\\" section below.","sidebar":"tutorialSidebar"},"consumer-development/consumer-genesis-transformation":{"id":"consumer-development/consumer-genesis-transformation","title":"Consumer Genesis Transformation","description":"Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentaion on Onboarding and Changeover).","sidebar":"tutorialSidebar"},"consumer-development/offboarding":{"id":"consumer-development/offboarding","title":"Offboarding Checklist","description":"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).","sidebar":"tutorialSidebar"},"consumer-development/onboarding":{"id":"consumer-development/onboarding","title":"Onboarding Checklist","description":"The following checklists will aid in onboarding a new consumer chain to replicated security.","sidebar":"tutorialSidebar"},"features/key-assignment":{"id":"features/key-assignment","title":"Key Assignment","description":"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.","sidebar":"tutorialSidebar"},"features/proposals":{"id":"features/proposals","title":"ICS Provider Proposals","description":"Interchain security module introduces 3 new proposal types to the provider.","sidebar":"tutorialSidebar"},"features/reward-distribution":{"id":"features/reward-distribution","title":"Reward distribution","description":"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.","sidebar":"tutorialSidebar"},"features/slashing":{"id":"features/slashing","title":"Consumer Initiated Slashing","description":"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.","sidebar":"tutorialSidebar"},"frequently-asked-questions":{"id":"frequently-asked-questions","title":"Frequently Asked Questions","description":"What is the meaning of Validator Set Replication?","sidebar":"tutorialSidebar"},"index":{"id":"index","title":"Interchain Security Docs","description":"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.","sidebar":"tutorialSidebar"},"introduction/overview":{"id":"introduction/overview","title":"Overview","description":"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.","sidebar":"tutorialSidebar"},"introduction/params":{"id":"introduction/params","title":"Interchain Security Parameters","description":"The parameters necessary for Interchain Security (ICS) are defined in","sidebar":"tutorialSidebar"},"introduction/technical-specification":{"id":"introduction/technical-specification","title":"Technical Specification","description":"For a technical deep dive into the replicated security protocol, see the specification.","sidebar":"tutorialSidebar"},"introduction/terminology":{"id":"introduction/terminology","title":"Terminology","description":"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.","sidebar":"tutorialSidebar"},"validators/changeover-procedure":{"id":"validators/changeover-procedure","title":"Validator instructions for Changeover Procedure","description":"More details available in Changeover Procedure documentation.","sidebar":"tutorialSidebar"},"validators/joining-neutron":{"id":"validators/joining-neutron","title":"Joining Neutron","description":"Neutron is the first consumer chain to implement ICS.","sidebar":"tutorialSidebar"},"validators/joining-stride":{"id":"validators/joining-stride","title":"Joining Stride","description":"Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.","sidebar":"tutorialSidebar"},"validators/joining-testnet":{"id":"validators/joining-testnet","title":"Joining Replicated Security testnet","description":"Introduction","sidebar":"tutorialSidebar"},"validators/overview":{"id":"validators/overview","title":"Overview","description":"We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.","sidebar":"tutorialSidebar"},"validators/withdraw_rewards":{"id":"validators/withdraw_rewards","title":"Withdrawing consumer chain validator rewards","description":"Here are example steps for withdrawing rewards from consumer chains in the provider chain","sidebar":"tutorialSidebar"}}}')}}]); \ No newline at end of file diff --git a/legacy/assets/js/e6400f0f.e3e0a98b.js b/legacy/assets/js/e6400f0f.e3e0a98b.js new file mode 100644 index 0000000000..ff09e52450 --- /dev/null +++ b/legacy/assets/js/e6400f0f.e3e0a98b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1064],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},o=Object.keys(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(r),m=i,f=d["".concat(l,".").concat(m)]||d[m]||u[m]||o;return r?n.createElement(f,a(a({ref:t},p),{},{components:r})):n.createElement(f,a({ref:t},p))}));function f(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=r.length,a=new Array(o);a[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:i,a[1]=s;for(var c=2;c<o;c++)a[c]=r[c];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},9925:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var n=r(7462),i=(r(7294),r(3905));const o={sidebar_position:6},a="Joining Stride",s={unversionedId:"validators/joining-stride",id:"version-v3.3.0/validators/joining-stride",title:"Joining Stride",description:"Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.",source:"@site/versioned_docs/version-v3.3.0/validators/joining-stride.md",sourceDirName:"validators",slug:"/validators/joining-stride",permalink:"/interchain-security/legacy/v3.3.0/validators/joining-stride",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"tutorialSidebar",previous:{title:"Joining Neutron",permalink:"/interchain-security/legacy/v3.3.0/validators/joining-neutron"},next:{title:"Frequently Asked Questions",permalink:"/interchain-security/legacy/v3.3.0/faq"}},l={},c=[{value:"Note",id:"note",level:2},{value:"Resources",id:"resources",level:2}],p={toc:c},d="wrapper";function u(e){let{components:t,...r}=e;return(0,i.kt)(d,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"joining-stride"},"Joining Stride"),(0,i.kt)("p",null,"Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using ",(0,i.kt)("inlineCode",{parentName:"p"},"cosmoshub-4")," validator set."),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"stride-1")," network (mainnet) will perform a software upgrade and at height ",(0,i.kt)("inlineCode",{parentName:"p"},"4616678")," that will transition the network to using the Cosmos Hub's (",(0,i.kt)("inlineCode",{parentName:"p"},"cosmoshub-4"),") validator set."),(0,i.kt)("p",null," You can find instructions about the Stride consumer chain launch and joining the mainnet ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/Stride-Labs/mainnet/tree/main/ics-instructions"},"here"),"."),(0,i.kt)("p",null," This ",(0,i.kt)("a",{parentName:"p",href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt"},"Excalidraw graphic")," explains the timeline of Stride's changeover procedure."),(0,i.kt)("h2",{id:"note"},"Note"),(0,i.kt)("p",null,"Stride re-uses an existing ",(0,i.kt)("inlineCode",{parentName:"p"},"transfer")," channel to send consumer rewards to the provider chain, in order to preserve existing transfer IBC denom between ",(0,i.kt)("inlineCode",{parentName:"p"},"stride-1")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"cosmoshub-4"),"."),(0,i.kt)("h2",{id:"resources"},"Resources"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://docs.stride.zone/docs"},"Stride docs")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt"},"Changeover procedure timeline")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/Stride-Labs/mainnet/tree/main/ics-instructions"},"Changeover upgrade docs"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/e9d00230.ef9e3baa.js b/legacy/assets/js/e9d00230.ef9e3baa.js new file mode 100644 index 0000000000..4d219d1600 --- /dev/null +++ b/legacy/assets/js/e9d00230.ef9e3baa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4158],{3905:(e,t,o)=>{o.d(t,{Zo:()=>c,kt:()=>m});var n=o(7294);function a(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function r(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,n)}return o}function i(e){for(var t=1;t<arguments.length;t++){var o=null!=arguments[t]?arguments[t]:{};t%2?r(Object(o),!0).forEach((function(t){a(e,t,o[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(o)):r(Object(o)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(o,t))}))}return e}function l(e,t){if(null==e)return{};var o,n,a=function(e,t){if(null==e)return{};var o,n,a={},r=Object.keys(e);for(n=0;n<r.length;n++)o=r[n],t.indexOf(o)>=0||(a[o]=e[o]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n<r.length;n++)o=r[n],t.indexOf(o)>=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(a[o]=e[o])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),o=t;return e&&(o="function"==typeof e?e(t):i(i({},t),e)),o},c=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var o=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=u(o),h=a,m=d["".concat(s,".").concat(h)]||d[h]||p[h]||r;return o?n.createElement(m,i(i({ref:t},c),{},{components:o})):n.createElement(m,i({ref:t},c))}));function m(e,t){var o=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=o.length,i=new Array(r);i[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,i[1]=l;for(var u=2;u<r;u++)i[u]=o[u];return n.createElement.apply(null,i)}return n.createElement.apply(null,o)}h.displayName="MDXCreateElement"},5796:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>p,frontMatter:()=>r,metadata:()=>l,toc:()=>u});var n=o(7462),a=(o(7294),o(3905));const r={sidebar_position:10,title:"Soft Opt-Out"},i=void 0,l={unversionedId:"adrs/adr-009-soft-opt-out",id:"version-v3.2.0/adrs/adr-009-soft-opt-out",title:"Soft Opt-Out",description:"ADR 009: Soft Opt-Out",source:"@site/versioned_docs/version-v3.2.0/adrs/adr-009-soft-opt-out.md",sourceDirName:"adrs",slug:"/adrs/adr-009-soft-opt-out",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-009-soft-opt-out",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:10,frontMatter:{sidebar_position:10,title:"Soft Opt-Out"},sidebar:"tutorialSidebar",previous:{title:"Throttle with retries",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-008-throttle-retries"},next:{title:"Standalone to Consumer Changeover",permalink:"/interchain-security/legacy/v3.2.0/adrs/adr-010-standalone-changeover"}},s={},u=[{value:"ADR 009: Soft Opt-Out",id:"adr-009-soft-opt-out",level:2},{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],c={toc:u},d="wrapper";function p(e){let{components:t,...o}=e;return(0,a.kt)(d,(0,n.Z)({},c,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"adr-009-soft-opt-out"},"ADR 009: Soft Opt-Out"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"6/13/23: Initial draft of ADR. Feature already implemented and in production.")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"Some small validators may not have the resources needed to validate all consumer chains. Therefore a need exists to allow the bottom ",(0,a.kt)("inlineCode",{parentName:"p"},"x%")," of validators to opt-out of validating a consumer chain. Meaning downtime infractions for these validators are dropped without ever reaching the provider."),(0,a.kt)("p",null,"This document specifies a modification to the ccv protocol which allows the bottom x% of the validator set by power to opt out of validating consumer chains without being jailed or otherwise punished for it. The feature is implemented with entirely consumer-side code."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"A consumer param exists, known as ",(0,a.kt)("inlineCode",{parentName:"p"},"SoftOptOutThreshold"),", which is a string decimal in the range of ","[0, 0.2]",", that determines the portion of validators which are allowed to opt out of validating that specific consumer."),(0,a.kt)("p",null,"In every consumer beginblocker, a function is ran which determines the so called ",(0,a.kt)("em",{parentName:"p"},"smallest non opt-out voting power"),". Validators with voting power greater than or equal to this value must validate the consumer chain, while validators below this value may opt out of validating the consumer chain."),(0,a.kt)("p",null,"The smallest non opt-out voting power is recomputed every beginblocker in ",(0,a.kt)("inlineCode",{parentName:"p"},"UpdateSmallestNonOptOutPower()"),". In a nutshell, the method obtains the total voting power of the consumer, iterates through the full valset (ordered power ascending) keeping track of a power sum, and when ",(0,a.kt)("inlineCode",{parentName:"p"},"powerSum / totalPower > SoftOptOutThreshold"),", the ",(0,a.kt)("inlineCode",{parentName:"p"},"SmallestNonOptOutPower")," is found and persisted."),(0,a.kt)("p",null,"Then, whenever the ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash()")," interface is executed on the consumer, if the voting power of the relevant validator being slashed is less than ",(0,a.kt)("inlineCode",{parentName:"p"},"SmallestNonOptOutPower")," for that block, the slash request is dropped and never sent to the provider."),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Small validators can opt out of validating specific consumers without being punished for it.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"The bottom ",(0,a.kt)("inlineCode",{parentName:"li"},"x%")," is still part of the total voting power of the consumer chain. This means that if the soft opt-out threshold is set to ",(0,a.kt)("inlineCode",{parentName:"li"},"10%")," for example, and every validator in the bottom ",(0,a.kt)("inlineCode",{parentName:"li"},"10%")," opts out from validating the consumer, then a ",(0,a.kt)("inlineCode",{parentName:"li"},"24%")," downtime of the remaining voting power would halt the chain. This may be especially problematic during consumer upgrades."),(0,a.kt)("li",{parentName:"ul"},"In nominal scenarios, consumers with soft opt out enabled will be constructing slash packets for small vals, which may be dropped. This is wasted computation, but necessary to keep implementation simple. Note that the sdk's ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/cosmos-sdk/blob/d3f09c222243bb3da3464969f0366330dcb977a8/x/slashing/keeper/infractions.go#L75"},"full downtime logic")," is always executed on the consumer, which can be computationally expensive and slow down certain blocks.")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Validators in the bottom of the valset who don't have to validate, may receive large delegation(s) which suddenly boost the validator to the subset that has to validate. This may catch the validator off guard.")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Original issue with some napkin math ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/784"},"#784"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/eb02ef83.484e8e31.js b/legacy/assets/js/eb02ef83.484e8e31.js new file mode 100644 index 0000000000..bb60a1635b --- /dev/null +++ b/legacy/assets/js/eb02ef83.484e8e31.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1657],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>m});var i=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,i)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?r(Object(a),!0).forEach((function(t){n(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):r(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function l(e,t){if(null==e)return{};var a,i,n=function(e,t){if(null==e)return{};var a,i,n={},r=Object.keys(e);for(i=0;i<r.length;i++)a=r[i],t.indexOf(a)>=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)a=r[i],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var s=i.createContext({}),h=function(e){var t=i.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},d=function(e){var t=h(e.components);return i.createElement(s.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},u=i.forwardRef((function(e,t){var a=e.components,n=e.mdxType,r=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=h(a),u=n,m=c["".concat(s,".").concat(u)]||c[u]||p[u]||r;return a?i.createElement(m,o(o({ref:t},d),{},{components:a})):i.createElement(m,o({ref:t},d))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=a.length,o=new Array(r);o[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:n,o[1]=l;for(var h=2;h<r;h++)o[h]=a[h];return i.createElement.apply(null,o)}return i.createElement.apply(null,a)}u.displayName="MDXCreateElement"},5304:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>p,frontMatter:()=>r,metadata:()=>l,toc:()=>h});var i=a(7462),n=(a(7294),a(3905));const r={sidebar_position:3,title:"Jail Throttling"},o="ADR 002: Jail Throttling",l={unversionedId:"adrs/adr-002-throttle",id:"version-v3.1.0/adrs/adr-002-throttle",title:"Jail Throttling",description:"Changelog",source:"@site/versioned_docs/version-v3.1.0/adrs/adr-002-throttle.md",sourceDirName:"adrs",slug:"/adrs/adr-002-throttle",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-002-throttle",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Jail Throttling"},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-001-key-assignment"},next:{title:"Equivocation governance proposal",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-003-equivocation-gov-proposal"}},s={},h=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"State Required - Slash Meter",id:"state-required---slash-meter",level:3},{value:"State Required - Global entry queue",id:"state-required---global-entry-queue",level:3},{value:"State Required - Per-chain data queue",id:"state-required---per-chain-data-queue",level:3},{value:"Reasoning - Multiple queues",id:"reasoning---multiple-queues",level:3},{value:"Protocol Overview - OnRecvSlashPacket",id:"protocol-overview---onrecvslashpacket",level:3},{value:"Protocol Overview - OnRecvVSCMaturedPacket",id:"protocol-overview---onrecvvscmaturedpacket",level:3},{value:"Endblocker Step 1 - Slash Meter Replenishment",id:"endblocker-step-1---slash-meter-replenishment",level:3},{value:"Endblocker Step 2 - HandleLeadingVSCMaturedPackets",id:"endblocker-step-2---handleleadingvscmaturedpackets",level:3},{value:"Endblocker Step 3 - HandleThrottleQueues",id:"endblocker-step-3---handlethrottlequeues",level:3},{value:"System Properties",id:"system-properties",level:3},{value:"Main Throttling Property",id:"main-throttling-property",level:3},{value:"How Unjailing Affects the Main Throttling Property",id:"how-unjailing-affects-the-main-throttling-property",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],d={toc:h},c="wrapper";function p(e){let{components:t,...a}=e;return(0,n.kt)(c,(0,i.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"adr-002-jail-throttling"},"ADR 002: Jail Throttling"),(0,n.kt)("h2",{id:"changelog"},"Changelog"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"2023-01-26: Initial Draft"),(0,n.kt)("li",{parentName:"ul"},"2023-02-07: Property refined, ADR ready to review/merge")),(0,n.kt)("h2",{id:"status"},"Status"),(0,n.kt)("p",null,"Accepted"),(0,n.kt)("h2",{id:"context"},"Context"),(0,n.kt)("p",null,"The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols. In practice, this assumption may not hold. A malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider."),(0,n.kt)("p",null,"Before the throttling feature was implemented, the following attack was possible. Attacker(s) would create provider validators just below the provider's active set. Using a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once. Control of the provider would then pass over to the attackers' validators. This enables the attacker(s) to halt the provider. Or even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC."),(0,n.kt)("h2",{id:"decision"},"Decision"),(0,n.kt)("p",null,"The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack. Ie. this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time."),(0,n.kt)("h3",{id:"state-required---slash-meter"},"State Required - Slash Meter"),(0,n.kt)("p",null,"There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time. This meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params."),(0,n.kt)("h3",{id:"state-required---global-entry-queue"},"State Required - Global entry queue"),(0,n.kt)("p",null,'There exists a single queue which stores "global slash entries". These entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering. This queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.'),(0,n.kt)("h3",{id:"state-required---per-chain-data-queue"},"State Required - Per-chain data queue"),(0,n.kt)("p",null,'For each established consumer, there exists a queue which stores "throttled packet data". Ie. pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering. Order is enforced by IBC sequence number. These "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.'),(0,n.kt)("h3",{id:"reasoning---multiple-queues"},"Reasoning - Multiple queues"),(0,n.kt)("p",null,"For reasoning on why this feature was implemented with multiple queues, see ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"spec"),". Specifically the section on ",(0,n.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order"),". There are other ways to ensure such a property (like a queue of linked lists, etc.), but the implemented protocol seemed to be the most understandable and easiest to implement with a KV store."),(0,n.kt)("h3",{id:"protocol-overview---onrecvslashpacket"},"Protocol Overview - OnRecvSlashPacket"),(0,n.kt)("p",null,"Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"A global slash entry is queued."),(0,n.kt)("li",{parentName:"ol"},"The data of such a packet is added to the per-chain queue.")),(0,n.kt)("h3",{id:"protocol-overview---onrecvvscmaturedpacket"},"Protocol Overview - OnRecvVSCMaturedPacket"),(0,n.kt)("p",null,"Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue."),(0,n.kt)("h3",{id:"endblocker-step-1---slash-meter-replenishment"},"Endblocker Step 1 - Slash Meter Replenishment"),(0,n.kt)("p",null,"Once the slash meter becomes not full, it'll be replenished after ",(0,n.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishPeriod (param)")," by incrementing the meter with its allowance for the replenishment block, where ",(0,n.kt)("inlineCode",{parentName:"p"},"allowance")," = ",(0,n.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction (param)")," * ",(0,n.kt)("inlineCode",{parentName:"p"},"currentTotalVotingPower"),". The slash meter will never exceed its current allowance (fn of the total voting power for the block) in value. Note a few things:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power. In such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods."),(0,n.kt)("li",{parentName:"ol"},"Total voting power of a chain changes over time, especially as validators are jailed. As validators are jailed, total voting power decreases, and so does the jailing allowance. See below for more detailed throttling property discussion."),(0,n.kt)("li",{parentName:"ol"},"The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1. If the ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction (param)")," is set too low, integer rounding will put this minimum value into effect. That is, if ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," * ",(0,n.kt)("inlineCode",{parentName:"li"},"currentTotalVotingPower")," < 1, then the effective allowance would be 1. This min value of allowance ensures that there's some packets handled over time, even if that is a very long time. It's a crude solution to an edge case caused by too small of a replenishment fraction.")),(0,n.kt)("p",null,"The behavior described above is achieved by executing ",(0,n.kt)("inlineCode",{parentName:"p"},"CheckForSlashMeterReplenishment()")," every endblock, BEFORE ",(0,n.kt)("inlineCode",{parentName:"p"},"HandleThrottleQueues()")," is executed."),(0,n.kt)("h3",{id:"endblocker-step-2---handleleadingvscmaturedpackets"},"Endblocker Step 2 - HandleLeadingVSCMaturedPackets"),(0,n.kt)("p",null,'Every block it is possible that VSCMatured packet data was queued before any slash packet data. Since this "leading" VSCMatured packet data does not have to be throttled (see ',(0,n.kt)("em",{parentName:"p"},"VSC Maturity and Slashing Order"),"), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes."),(0,n.kt)("h3",{id:"endblocker-step-3---handlethrottlequeues"},"Endblocker Step 3 - HandleThrottleQueues"),(0,n.kt)("p",null,"Every endblocker the following pseudo-code is executed to handle data from the throttle queues."),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-typescript"},"meter := getSlashMeter()\n\n// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist \nwhile meter.IsPositiveOrZero() && entriesExist() {\n // Get next entry in queue\n entry := getNextGlobalSlashEntry()\n // Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet\n valPower := entry.getValPower()\n meter = meter - valPower\n // Using the per-chain queue, handle the single slash packet using its queued data,\n // then handle all trailing VSCMatured packets for this consumer\n handleSlashPacketAndTrailingVSCMaturedPackets(entry)\n // Delete entry in global queue, delete handled data\n entry.Delete()\n deleteThrottledSlashPacketData()\n deleteTrailingVSCMaturedPacketData()\n}\n")),(0,n.kt)("h3",{id:"system-properties"},"System Properties"),(0,n.kt)("p",null,"All CCV system properties should be maintained by implementing this feature, see: ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing"},"CCV spec - Consumer Initiated Slashing"),"."),(0,n.kt)("p",null,"One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than ",(0,n.kt)("inlineCode",{parentName:"p"},"MaxThrottledPackets (param)"),", then the provider binary will panic, and the provider chain will halt. Therefore this param should be set carefully. See ",(0,n.kt)("inlineCode",{parentName:"p"},"SetThrottledPacketDataSize"),". This behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators."),(0,n.kt)("h3",{id:"main-throttling-property"},"Main Throttling Property"),(0,n.kt)("p",null,"Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions."),(0,n.kt)("p",null,"First, we define the following:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},'A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.'),(0,n.kt)("li",{parentName:"ul"},'The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.'),(0,n.kt)("li",{parentName:"ul"},"There is a list of honest validators s.t if they are jailed, ",(0,n.kt)("inlineCode",{parentName:"li"},"X"),"% of the initial validator set will be jailed.")),(0,n.kt)("p",null,"For the following property to hold, these assumptions must be true:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack."),(0,n.kt)("li",{parentName:"ol"},"No validator has more than ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," of total voting power on the provider."),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," is large enough that ",(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishFraction")," * ",(0,n.kt)("inlineCode",{parentName:"li"},"currentTotalVotingPower")," > 1. Ie. the replenish fraction is set high enough that we can ignore the effects of rounding."),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("inlineCode",{parentName:"li"},"SlashMeterReplenishPeriod")," is sufficiently longer than the time it takes to produce a block.")),(0,n.kt)("p",null,(0,n.kt)("em",{parentName:"p"},"Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined.")),(0,n.kt)("p",null,"Property:"),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"The time it takes to jail/tombstone ",(0,n.kt)("inlineCode",{parentName:"p"},"X"),"% of the initial validator set will be greater than or equal to ",(0,n.kt)("inlineCode",{parentName:"p"},"(X * SlashMeterReplenishPeriod / SlashMeterReplenishFraction) - 2 * SlashMeterReplenishPeriod"))),(0,n.kt)("p",null,"Intuition:"),(0,n.kt)("p",null,"Let's use the following notation:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"$C$: Number of replenishment cycles"),(0,n.kt)("li",{parentName:"ul"},"$P$: $\\text{SlashMeterReplenishPeriod}$"),(0,n.kt)("li",{parentName:"ul"},"$F$: $\\text{SlashMeterReplenishFraction}$"),(0,n.kt)("li",{parentName:"ul"},"$V_{\\mathit{max}}$: Max power of a validator as a fraction of total voting power")),(0,n.kt)("p",null,"In $C$ number of replenishment cycles, the fraction of total voting power that can be removed, $a$, is $a \\leq F \\cdot C + V",(0,n.kt)("em",{parentName:"p"},"{\\mathit{max}}$ (where $V"),"{\\mathit{max}}$ is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value)."),(0,n.kt)("p",null,"So, we need at least $C \\geq \\frac{a - V_{\\mathit{max}}}{F}$ cycles to remove $a$ fraction of the total voting power."),(0,n.kt)("p",null,"Since we defined the start of the attack to be the moment when the first slash request arrives, then $F$ fraction of the initial validator set can be jailed immediately. For the remaining $X - F$ fraction of the initial validator set to be jailed, it takes at least $C \\geq \\frac{(X - F) - V",(0,n.kt)("em",{parentName:"p"},"{\\mathit{max}}}{F}$ cycles. Using the assumption that $V"),"{\\mathit{max}} \\leq F$ (assumption 2), we get $C \\geq \\frac{X - 2F}{F}$ cycles."),(0,n.kt)("p",null,"In order to execute $C$ cycles, we need $C \\cdot P$ time."),(0,n.kt)("p",null,"Thus, jailing the remaining $X - F$ fraction of the initial validator set corresponds to $\\frac{P \\cdot (X - 2F)}{F}$ time."),(0,n.kt)("p",null,"In other words, the attack must take at least $\\frac{P \\cdot X}{F} - 2P$ time (in the units of replenish period $P$)."),(0,n.kt)("p",null,"This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests. For example, if ",(0,n.kt)("inlineCode",{parentName:"p"},"SlashMeterReplenishFraction")," is set to 0.06, then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub. Note that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power."),(0,n.kt)("p",null,"Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings."),(0,n.kt)("h3",{id:"how-unjailing-affects-the-main-throttling-property"},"How Unjailing Affects the Main Throttling Property"),(0,n.kt)("p",null,"Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained."),(0,n.kt)("p",null,"If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider."),(0,n.kt)("p",null,"In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack."),(0,n.kt)("h2",{id:"consequences"},"Consequences"),(0,n.kt)("h3",{id:"positive"},"Positive"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"The described attack is slowed down in seemingly all cases."),(0,n.kt)("li",{parentName:"ul"},"If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded.")),(0,n.kt)("h3",{id:"negative"},"Negative"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below. However, this is sacrificing liveness in a edge case scenario for the sake of security. As an improvement, ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/713"},"using retries")," would fully prevent this attack vector.")),(0,n.kt)("h3",{id:"neutral"},"Neutral"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Additional state is introduced to the provider chain."),(0,n.kt)("li",{parentName:"ul"},"VSCMatured and slash packet data is not always handled in the same block that it is received.")),(0,n.kt)("h2",{id:"references"},"References"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/404"},"Original issue inspiring throttling feature")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/594"},"Issue on DOS vector")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/685"},"Consideration of another attack vector"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/ebdc1949.59e9d9fa.js b/legacy/assets/js/ebdc1949.59e9d9fa.js new file mode 100644 index 0000000000..867e72ff45 --- /dev/null +++ b/legacy/assets/js/ebdc1949.59e9d9fa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[915],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},r=Object.keys(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),c=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),m=a,h=u["".concat(l,".").concat(m)]||u[m]||d[m]||r;return n?o.createElement(h,i(i({ref:t},p),{},{components:n})):o.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,i[1]=s;for(var c=2;c<r;c++)i[c]=n[c];return o.createElement.apply(null,i)}return o.createElement.apply(null,n)}m.displayName="MDXCreateElement"},5256:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>r,metadata:()=>s,toc:()=>c});var o=n(7462),a=(n(7294),n(3905));const r={sidebar_position:4,title:"Equivocation governance proposal"},i="ADR 003: Equivocation governance proposal",s={unversionedId:"adrs/adr-003-equivocation-gov-proposal",id:"version-v3.1.0/adrs/adr-003-equivocation-gov-proposal",title:"Equivocation governance proposal",description:"Changelog",source:"@site/versioned_docs/version-v3.1.0/adrs/adr-003-equivocation-gov-proposal.md",sourceDirName:"adrs",slug:"/adrs/adr-003-equivocation-gov-proposal",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-003-equivocation-gov-proposal",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Equivocation governance proposal"},sidebar:"tutorialSidebar",previous:{title:"Jail Throttling",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-002-throttle"},next:{title:"Throttle with retries",permalink:"/interchain-security/legacy/v3.1.0/adrs/adr-008-throttle-retries"}},l={},c=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],p={toc:c},u="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-003-equivocation-governance-proposal"},"ADR 003: Equivocation governance proposal"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"2023-02-06: Initial draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain."),(0,a.kt)("p",null,"For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain."),(0,a.kt)("p",null,"A new kind of governance proposal is added to the ",(0,a.kt)("inlineCode",{parentName:"p"},"provider")," module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain."),(0,a.kt)("p",null,"If such proposal passes, the proposal handler delegates to the ",(0,a.kt)("inlineCode",{parentName:"p"},"evidence")," module to process the equivocation. This module ensures the evidence isn\u2019t too old, or else ignores it (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/21021b837882d1d40f1d79bcbc4fad2e79a3fefe/x/evidence/keeper/infraction.go#L54-L62"},"code"),"). ",(0,a.kt)("em",{parentName:"p"},"Too old")," is determined by 2 consensus params : "),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"evidence.max_age_duration")," number of nanoseconds before an evidence is considered too old"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"evidence.max_age_numblocks")," number of blocks before an evidence is considered too old.")),(0,a.kt)("p",null,"On the hub, those parameters are equals to "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682\n(...)\n"evidence": {\n "max_age_num_blocks": "1000000",\n "max_age_duration": "172800000000000",\n (...)\n},\n(...)\n')),(0,a.kt)("p",null,"A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the ",(0,a.kt)("inlineCode",{parentName:"p"},"evidence")," module when the proposal passes and is handled by the hub."),(0,a.kt)("p",null,"For ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks=1M"),", the parameter is big enough if we consider the hub produces 12k blocks per day (",(0,a.kt)("inlineCode",{parentName:"p"},"blocks_per_year/365 = 436,0000/365"),"). The evidence can be up to 83 days old (",(0,a.kt)("inlineCode",{parentName:"p"},"1,000,000/12,000"),") and not be ignored."),(0,a.kt)("p",null,"For ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_duration=172,800,000,000,000"),", the parameter is too low, because the value is in nanoseconds so it\u2019s 2 days. Fortunately the condition that checks those 2 parameters uses a ",(0,a.kt)("strong",{parentName:"p"},"AND"),", so if ",(0,a.kt)("inlineCode",{parentName:"p"},"max_age_num_blocks")," condition passes, the evidence won\u2019t be ignored."),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Remove the possibility from a malicious consumer chain to \u201cattack\u201d the provider chain by slashing/jailing validators."),(0,a.kt)("li",{parentName:"ul"},"Provide a more acceptable implementation for the validator community.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Punishment action of double-signing isn\u2019t \u201cautomated\u201d, a governance proposal is required which takes more time."),(0,a.kt)("li",{parentName:"ul"},"You need to pay 250ATOM to submit an equivocation evidence.")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"PR that ignores non downtime slash packet : ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/692"},"https://github.com/cosmos/interchain-security/pull/692")),(0,a.kt)("li",{parentName:"ul"},"PR that adds the governance slash proposal: ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/703"},"https://github.com/cosmos/interchain-security/pull/703"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/ed4bc87d.1be93e7e.js b/legacy/assets/js/ed4bc87d.1be93e7e.js new file mode 100644 index 0000000000..012374eb48 --- /dev/null +++ b/legacy/assets/js/ed4bc87d.1be93e7e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3932],{3905:(e,r,t)=>{t.d(r,{Zo:()=>l,kt:()=>h});var n=t(7294);function i(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function o(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function a(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?o(Object(t),!0).forEach((function(r){i(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function s(e,r){if(null==e)return{};var t,n,i=function(e,r){if(null==e)return{};var t,n,i={},o=Object.keys(e);for(n=0;n<o.length;n++)t=o[n],r.indexOf(t)>=0||(i[t]=e[t]);return i}(e,r);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)t=o[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var d=n.createContext({}),c=function(e){var r=n.useContext(d),t=r;return e&&(t="function"==typeof e?e(r):a(a({},r),e)),t},l=function(e){var r=c(e.components);return n.createElement(d.Provider,{value:r},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},m=n.forwardRef((function(e,r){var t=e.components,i=e.mdxType,o=e.originalType,d=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=c(t),m=i,h=u["".concat(d,".").concat(m)]||u[m]||p[m]||o;return t?n.createElement(h,a(a({ref:r},l),{},{components:t})):n.createElement(h,a({ref:r},l))}));function h(e,r){var t=arguments,i=r&&r.mdxType;if("string"==typeof e||i){var o=t.length,a=new Array(o);a[0]=m;var s={};for(var d in r)hasOwnProperty.call(r,d)&&(s[d]=r[d]);s.originalType=e,s[u]="string"==typeof e?e:i,a[1]=s;for(var c=2;c<o;c++)a[c]=t[c];return n.createElement.apply(null,a)}return n.createElement.apply(null,t)}m.displayName="MDXCreateElement"},8757:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>d,contentTitle:()=>a,default:()=>p,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var n=t(7462),i=(t(7294),t(3905));const o={sidebar_position:2},a="Reward distribution",s={unversionedId:"features/reward-distribution",id:"version-v3.2.0/features/reward-distribution",title:"Reward distribution",description:"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.",source:"@site/versioned_docs/version-v3.2.0/features/reward-distribution.md",sourceDirName:"features",slug:"/features/reward-distribution",permalink:"/interchain-security/legacy/v3.2.0/features/reward-distribution",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/legacy/v3.2.0/features/key-assignment"},next:{title:"ICS Provider Proposals",permalink:"/interchain-security/legacy/v3.2.0/features/proposals"}},d={},c=[{value:"Note",id:"note",level:2},{value:"Instructions for adding a denom",id:"instructions-for-adding-a-denom",level:3},{value:"Parameters",id:"parameters",level:2},{value:"<code>consumer_redistribution_fraction</code>",id:"consumer_redistribution_fraction",level:3},{value:"<code>blocks_per_distribution_transmission</code>",id:"blocks_per_distribution_transmission",level:3},{value:"<code>transfer_timeout_period</code>",id:"transfer_timeout_period",level:3},{value:"<code>distribution_transmission_channel</code>",id:"distribution_transmission_channel",level:3},{value:"<code>provider_fee_pool_addr_str</code>",id:"provider_fee_pool_addr_str",level:3}],l={toc:c},u="wrapper";function p(e){let{components:r,...t}=e;return(0,i.kt)(u,(0,n.Z)({},l,t,{components:r,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"reward-distribution"},"Reward distribution"),(0,i.kt)("p",null,"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.\nIn replicated security block rewards and fees are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel that gets created during consumer chain initialization."),(0,i.kt)("p",null,"Reward distribution on the provider is handled by the distribution module - validators and delegators receive a fraction of the consumer chain tokens as staking rewards.\nThe distributed reward tokens are IBC tokens and therefore cannot be staked on the provider chain."),(0,i.kt)("p",null,"Sending and distributing rewards from consumer chains to provider chain is handled by the ",(0,i.kt)("inlineCode",{parentName:"p"},"Reward Distribution")," sub-protocol."),(0,i.kt)("h2",{id:"note"},"Note"),(0,i.kt)("p",null,"The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerRewardsPool"),".\nThere is a new transaction type called ",(0,i.kt)("inlineCode",{parentName:"p"},"RegisterConsumerRewardDenom"),". This transaction allows consumer chains to register denoms to be used as consumer chain rewards on the provider.\nThe cost to register a denom is configurable (",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerRewardDenomRegistrationFee")," chain param) and the full amount of this fee is transferred to the community pool of the provider chain. Only denoms registered through this transaction are then transferred from the ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerRewardsPool")," to the ",(0,i.kt)("inlineCode",{parentName:"p"},"FeePoolAddress"),", to be distributed out to delegators and validators."),(0,i.kt)("h3",{id:"instructions-for-adding-a-denom"},"Instructions for adding a denom"),(0,i.kt)("p",null,"The transaction must be carried out on the provider chain. Please use the ",(0,i.kt)("inlineCode",{parentName:"p"},"ibc/*")," denom trace format."),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre"},"# reward denoms must be registered on the provider chain (gaia in this example)\ngaiad tx provider register-consumer-reward-denom ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9 --from mykey\n"))),(0,i.kt)("h2",{id:"parameters"},"Parameters"),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"The following chain parameters dictate consumer chain distribution amount and frequency.\nThey are set at consumer genesis and ",(0,i.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction"),"\n",(0,i.kt)("inlineCode",{parentName:"p"},"transfer_timeout_period")," must be provided in every ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerChainAddition")," proposal.")),(0,i.kt)("h3",{id:"consumer_redistribution_fraction"},(0,i.kt)("inlineCode",{parentName:"h3"},"consumer_redistribution_fraction")),(0,i.kt)("p",null,'The fraction of tokens allocated to the consumer redistribution address during distribution events. The fraction is a string representing a decimal number. For example "0.75" would represent 75%.'),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"Example:"),(0,i.kt)("p",{parentName:"admonition"},"With ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction")," set to ",(0,i.kt)("inlineCode",{parentName:"p"},"0.75")," the consumer chain would send 75% of its block rewards and accumulated fees to the consumer redistribution address, and the remaining 25% to the provider chain every ",(0,i.kt)("inlineCode",{parentName:"p"},"n")," blocks where ",(0,i.kt)("inlineCode",{parentName:"p"},"n == blocks_per_distribution_transmission"),".")),(0,i.kt)("h3",{id:"blocks_per_distribution_transmission"},(0,i.kt)("inlineCode",{parentName:"h3"},"blocks_per_distribution_transmission")),(0,i.kt)("p",null,"The number of blocks between IBC token transfers from the consumer chain to the provider chain."),(0,i.kt)("h3",{id:"transfer_timeout_period"},(0,i.kt)("inlineCode",{parentName:"h3"},"transfer_timeout_period")),(0,i.kt)("p",null,"Timeout period for consumer chain reward distribution IBC packets."),(0,i.kt)("h3",{id:"distribution_transmission_channel"},(0,i.kt)("inlineCode",{parentName:"h3"},"distribution_transmission_channel")),(0,i.kt)("p",null,"Provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."),(0,i.kt)("h3",{id:"provider_fee_pool_addr_str"},(0,i.kt)("inlineCode",{parentName:"h3"},"provider_fee_pool_addr_str")),(0,i.kt)("p",null,"Provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/ee5432e5.78f242e9.js b/legacy/assets/js/ee5432e5.78f242e9.js new file mode 100644 index 0000000000..4ead3e55aa --- /dev/null +++ b/legacy/assets/js/ee5432e5.78f242e9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2876],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>y});var i=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,i)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){n(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,i,n=function(e,t){if(null==e)return{};var r,i,n={},o=Object.keys(e);for(i=0;i<o.length;i++)r=o[i],t.indexOf(r)>=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i<o.length;i++)r=o[i],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=i.createContext({}),l=function(e){var t=i.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},u=function(e){var t=l(e.components);return i.createElement(s.Provider,{value:t},e.children)},h="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},p=i.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),h=l(r),p=n,y=h["".concat(s,".").concat(p)]||h[p]||d[p]||o;return r?i.createElement(y,a(a({ref:t},u),{},{components:r})):i.createElement(y,a({ref:t},u))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,a=new Array(o);a[0]=p;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[h]="string"==typeof e?e:n,a[1]=c;for(var l=2;l<o;l++)a[l]=r[l];return i.createElement.apply(null,a)}return i.createElement.apply(null,r)}p.displayName="MDXCreateElement"},2087:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>d,frontMatter:()=>o,metadata:()=>c,toc:()=>l});var i=r(7462),n=(r(7294),r(3905));const o={sidebar_position:2},a="Terminology",c={unversionedId:"introduction/terminology",id:"version-v3.2.0/introduction/terminology",title:"Terminology",description:"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.",source:"@site/versioned_docs/version-v3.2.0/introduction/terminology.md",sourceDirName:"introduction",slug:"/introduction/terminology",permalink:"/interchain-security/legacy/v3.2.0/introduction/terminology",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/interchain-security/legacy/v3.2.0/introduction/overview"},next:{title:"Interchain Security Parameters",permalink:"/interchain-security/legacy/v3.2.0/introduction/params"}},s={},l=[{value:"Shared Security",id:"shared-security",level:2},{value:"Interchain Security",id:"interchain-security",level:2},{value:"Replicated Security",id:"replicated-security",level:2},{value:"Mesh security",id:"mesh-security",level:2},{value:"Consumer Chain",id:"consumer-chain",level:2},{value:"Standalone Chain",id:"standalone-chain",level:2},{value:"Changeover Procedure",id:"changeover-procedure",level:2}],u={toc:l},h="wrapper";function d(e){let{components:t,...r}=e;return(0,n.kt)(h,(0,i.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"terminology"},"Terminology"),(0,n.kt)("p",null,"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions."),(0,n.kt)("h2",{id:"shared-security"},"Shared Security"),(0,n.kt)("p",null,"Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share its proof-of-stake security with another blockchain or off-chain process."),(0,n.kt)("h2",{id:"interchain-security"},"Interchain Security"),(0,n.kt)("p",null,"Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC."),(0,n.kt)("h2",{id:"replicated-security"},"Replicated Security"),(0,n.kt)("p",null,'A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC. Note this documentation is focused on explaining the concepts from replicated security.'),(0,n.kt)("h2",{id:"mesh-security"},"Mesh security"),(0,n.kt)("p",null,"A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see ",(0,n.kt)("a",{parentName:"p",href:"https://informal.systems/blog/replicated-vs-mesh-security"},"Replicated vs. Mesh Security on the Informal Blog"),"."),(0,n.kt)("h2",{id:"consumer-chain"},"Consumer Chain"),(0,n.kt)("p",null,"Chain that is secured by the validator set of the provider, instead of its own.\nReplicated security allows the provider chain validator set to validate blocks on the consumer chain."),(0,n.kt)("h2",{id:"standalone-chain"},"Standalone Chain"),(0,n.kt)("p",null,"Chain that is secured by its own validator set. This chain does not participate in replicated security."),(0,n.kt)("p",null,'Standalone chains may sometimes be called "sovereign" - the terms are synonymous.'),(0,n.kt)("h2",{id:"changeover-procedure"},"Changeover Procedure"),(0,n.kt)("p",null,"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the ",(0,n.kt)("strong",{parentName:"p"},"changeover procedure")," and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/ee6b1b56.6b17dbc1.js b/legacy/assets/js/ee6b1b56.6b17dbc1.js new file mode 100644 index 0000000000..821bed71f6 --- /dev/null +++ b/legacy/assets/js/ee6b1b56.6b17dbc1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[141],{3905:(e,r,t)=>{t.d(r,{Zo:()=>d,kt:()=>f});var n=t(7294);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function o(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?i(Object(t),!0).forEach((function(r){a(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function c(e,r){if(null==e)return{};var t,n,a=function(e,r){if(null==e)return{};var t,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=n.createContext({}),u=function(e){var r=n.useContext(s),t=r;return e&&(t="function"==typeof e?e(r):o(o({},r),e)),t},d=function(e){var r=u(e.components);return n.createElement(s.Provider,{value:r},e.children)},l="mdxType",m={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},p=n.forwardRef((function(e,r){var t=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,d=c(e,["components","mdxType","originalType","parentName"]),l=u(t),p=a,f=l["".concat(s,".").concat(p)]||l[p]||m[p]||i;return t?n.createElement(f,o(o({ref:r},d),{},{components:t})):n.createElement(f,o({ref:r},d))}));function f(e,r){var t=arguments,a=r&&r.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=p;var c={};for(var s in r)hasOwnProperty.call(r,s)&&(c[s]=r[s]);c.originalType=e,c[l]="string"==typeof e?e:a,o[1]=c;for(var u=2;u<i;u++)o[u]=t[u];return n.createElement.apply(null,o)}return n.createElement.apply(null,t)}p.displayName="MDXCreateElement"},2307:(e,r,t)=>{t.d(r,{Z:()=>i});var n=t(7294);const a=function(e){return n.createElement("a",{href:e.href,className:"border shadow rounded-sm border-stone-200 dark:border-stone-800 dark:bg-neutral-900 hover:border-stone-300 hover:shadow-lg dark:hover:border-stone-200 transition-all duration-200 no-underline"},n.createElement("div",{className:"p-6"},n.createElement("h2",{className:""},e.header),n.createElement("p",{className:""},e.summary)))};const i=function(e){return n.createElement("div",{className:"card-section grid grid-cols-1 lg:grid-cols-2 gap-4 no-underline"},e.cards.map(((e,r)=>n.createElement(a,{key:r,href:e.href,header:e.header,summary:e.summary}))))}},8758:(e,r,t)=>{t.d(r,{Z:()=>n});const n=[{href:"/interchain-security/introduction/overview",header:"Basic concepts",summary:"Get started with the basic concepts and ideas."},{href:"/interchain-security/consumer-development/app-integration",header:"Start building",summary:"Click here to start building with Interchain security"},{href:"/interchain-security/features/key-assignment",header:"Feature: Key Assignment",summary:"Learn about the key assignment feature"},{href:"/interchain-security/features/reward-distribution",header:"Feature: Reward Distribution",summary:"Learn about consumer chain rewards distribution"},{href:"/interchain-security/consumer-development/onboarding",header:"Onboarding Checklist",summary:"Checklist to help you integrate Interchain Security, get support and onboard validators"},{href:"/interchain-security/faq",header:"FAQ",summary:"Frequently asked questions about the protocol and its implications"}]},2226:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>d,contentTitle:()=>s,default:()=>f,frontMatter:()=>c,metadata:()=>u,toc:()=>l});var n=t(7462),a=(t(7294),t(3905)),i=t(2307),o=t(8758);const c={sidebar_position:1},s="Interchain Security Docs",u={unversionedId:"index",id:"version-v3.1.0/index",title:"Interchain Security Docs",description:"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.",source:"@site/versioned_docs/version-v3.1.0/index.mdx",sourceDirName:".",slug:"/",permalink:"/interchain-security/legacy/v3.1.0/",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",next:{title:"Overview",permalink:"/interchain-security/legacy/v3.1.0/introduction/overview"}},d={},l=[],m={toc:l},p="wrapper";function f(e){let{components:r,...t}=e;return(0,a.kt)(p,(0,n.Z)({},m,t,{components:r,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"interchain-security-docs"},"Interchain Security Docs"),(0,a.kt)("p",null,"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains."),(0,a.kt)("p",null,"Here you can find information about replicated security, consumer chain development and instructions for validator onboarding."),(0,a.kt)(i.Z,{cards:o.Z,mdxType:"CardSection"}))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/f0becab0.b3d4183e.js b/legacy/assets/js/f0becab0.b3d4183e.js new file mode 100644 index 0000000000..f0ea380f15 --- /dev/null +++ b/legacy/assets/js/f0becab0.b3d4183e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[222],{3905:(e,r,t)=>{t.d(r,{Zo:()=>d,kt:()=>f});var n=t(7294);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function o(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?i(Object(t),!0).forEach((function(r){a(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function c(e,r){if(null==e)return{};var t,n,a=function(e,r){if(null==e)return{};var t,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)t=i[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=n.createContext({}),u=function(e){var r=n.useContext(s),t=r;return e&&(t="function"==typeof e?e(r):o(o({},r),e)),t},d=function(e){var r=u(e.components);return n.createElement(s.Provider,{value:r},e.children)},l="mdxType",m={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},p=n.forwardRef((function(e,r){var t=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,d=c(e,["components","mdxType","originalType","parentName"]),l=u(t),p=a,f=l["".concat(s,".").concat(p)]||l[p]||m[p]||i;return t?n.createElement(f,o(o({ref:r},d),{},{components:t})):n.createElement(f,o({ref:r},d))}));function f(e,r){var t=arguments,a=r&&r.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=p;var c={};for(var s in r)hasOwnProperty.call(r,s)&&(c[s]=r[s]);c.originalType=e,c[l]="string"==typeof e?e:a,o[1]=c;for(var u=2;u<i;u++)o[u]=t[u];return n.createElement.apply(null,o)}return n.createElement.apply(null,t)}p.displayName="MDXCreateElement"},2307:(e,r,t)=>{t.d(r,{Z:()=>i});var n=t(7294);const a=function(e){return n.createElement("a",{href:e.href,className:"border shadow rounded-sm border-stone-200 dark:border-stone-800 dark:bg-neutral-900 hover:border-stone-300 hover:shadow-lg dark:hover:border-stone-200 transition-all duration-200 no-underline"},n.createElement("div",{className:"p-6"},n.createElement("h2",{className:""},e.header),n.createElement("p",{className:""},e.summary)))};const i=function(e){return n.createElement("div",{className:"card-section grid grid-cols-1 lg:grid-cols-2 gap-4 no-underline"},e.cards.map(((e,r)=>n.createElement(a,{key:r,href:e.href,header:e.header,summary:e.summary}))))}},8758:(e,r,t)=>{t.d(r,{Z:()=>n});const n=[{href:"/interchain-security/introduction/overview",header:"Basic concepts",summary:"Get started with the basic concepts and ideas."},{href:"/interchain-security/consumer-development/app-integration",header:"Start building",summary:"Click here to start building with Interchain security"},{href:"/interchain-security/features/key-assignment",header:"Feature: Key Assignment",summary:"Learn about the key assignment feature"},{href:"/interchain-security/features/reward-distribution",header:"Feature: Reward Distribution",summary:"Learn about consumer chain rewards distribution"},{href:"/interchain-security/consumer-development/onboarding",header:"Onboarding Checklist",summary:"Checklist to help you integrate Interchain Security, get support and onboard validators"},{href:"/interchain-security/faq",header:"FAQ",summary:"Frequently asked questions about the protocol and its implications"}]},7414:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>d,contentTitle:()=>s,default:()=>f,frontMatter:()=>c,metadata:()=>u,toc:()=>l});var n=t(7462),a=(t(7294),t(3905)),i=t(2307),o=t(8758);const c={sidebar_position:1},s="Interchain Security Docs",u={unversionedId:"index",id:"version-v3.2.0/index",title:"Interchain Security Docs",description:"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.",source:"@site/versioned_docs/version-v3.2.0/index.mdx",sourceDirName:".",slug:"/",permalink:"/interchain-security/legacy/v3.2.0/",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",next:{title:"Overview",permalink:"/interchain-security/legacy/v3.2.0/introduction/overview"}},d={},l=[],m={toc:l},p="wrapper";function f(e){let{components:r,...t}=e;return(0,a.kt)(p,(0,n.Z)({},m,t,{components:r,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"interchain-security-docs"},"Interchain Security Docs"),(0,a.kt)("p",null,"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains."),(0,a.kt)("p",null,"Here you can find information about replicated security, consumer chain development and instructions for validator onboarding."),(0,a.kt)(i.Z,{cards:o.Z,mdxType:"CardSection"}))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/f143d156.8e2b8300.js b/legacy/assets/js/f143d156.8e2b8300.js new file mode 100644 index 0000000000..9328638f37 --- /dev/null +++ b/legacy/assets/js/f143d156.8e2b8300.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[7511],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>m});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),d=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=d(e.components);return a.createElement(l.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=d(n),h=i,m=p["".concat(l,".").concat(h)]||p[h]||u[h]||r;return n?a.createElement(m,o(o({ref:t},c),{},{components:n})):a.createElement(m,o({ref:t},c))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:i,o[1]=s;for(var d=2;d<r;d++)o[d]=n[d];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},3062:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>s,toc:()=>d});var a=n(7462),i=(n(7294),n(3905));const r={sidebar_position:4},o="Validator instructions for Changeover Procedure",s={unversionedId:"validators/changeover-procedure",id:"version-v3.2.0/validators/changeover-procedure",title:"Validator instructions for Changeover Procedure",description:"More details available in Changeover Procedure documentation.",source:"@site/versioned_docs/version-v3.2.0/validators/changeover-procedure.md",sourceDirName:"validators",slug:"/validators/changeover-procedure",permalink:"/interchain-security/legacy/v3.2.0/validators/changeover-procedure",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Withdrawing consumer chain validator rewards",permalink:"/interchain-security/legacy/v3.2.0/validators/withdraw_rewards"},next:{title:"Joining Neutron",permalink:"/interchain-security/legacy/v3.2.0/validators/joining-neutron"}},l={},d=[{value:"Timeline",id:"timeline",level:2},{value:"1. <code>ConsumerAdditionProposal</code> on provider chain",id:"1-consumeradditionproposal-on-provider-chain",level:3},{value:"2. <code>SoftwareUpgradeProposal</code> on the standalone/consumer chain",id:"2-softwareupgradeproposal-on-the-standaloneconsumer-chain",level:3},{value:"3. Assigning a consumer key",id:"3-assigning-a-consumer-key",level:3},{value:"4. Perform the software ugprade on standalone chain",id:"4-perform-the-software-ugprade-on-standalone-chain",level:3},{value:"FAQ",id:"faq",level:2},{value:"Can I reuse the same validator key for the <code>consumer</code> chain that I am already using on the <code>standalone</code> chain? Will I need to perform a <code>AssignConsumerKey</code> tx with this key before spawn time?",id:"can-i-reuse-the-same-validator-key-for-the-consumer-chain-that-i-am-already-using-on-the-standalone-chain-will-i-need-to-perform-a-assignconsumerkey-tx-with-this-key-before-spawn-time",level:3},{value:"Can I continue using the same node that was validating the <code>standalone</code> chain?",id:"can-i-continue-using-the-same-node-that-was-validating-the-standalone-chain",level:3},{value:"Can I set up a new node to validate the <code>standalone/consumer</code> chain after it transitions to replicated security?",id:"can-i-set-up-a-new-node-to-validate-the-standaloneconsumer-chain-after-it-transitions-to-replicated-security",level:3},{value:"What happens to the <code>standalone</code> validator set after it after it transitions to replicated security?",id:"what-happens-to-the-standalone-validator-set-after-it-after-it-transitions-to-replicated-security",level:3},{value:"Credits",id:"credits",level:2}],c={toc:d},p="wrapper";function u(e){let{components:t,...r}=e;return(0,i.kt)(p,(0,a.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"validator-instructions-for-changeover-procedure"},"Validator instructions for Changeover Procedure"),(0,i.kt)("p",null,"More details available in ",(0,i.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.2.0/consumer-development/changeover-procedure"},"Changeover Procedure documentation"),"."),(0,i.kt)("p",null,"A major difference betwen launching a new consumer chain vs. onboarding a standalone chain to ICS is that there is no consumer genesis available for the standalone chain. Since a standalone chain already exists, its state must be preserved once it transitions to being a consumer chain."),(0,i.kt)("h2",{id:"timeline"},"Timeline"),(0,i.kt)("p",null,"Upgrading standalone chains can be best visualised using a timeline, such as the one available ",(0,i.kt)("a",{parentName:"p",href:"https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt"},"Excalidraw graphic by Stride"),"."),(0,i.kt)("p",null,"There is some flexibility with regards to how the changeover procedure is executed, so please make sure to follow the guides provided by the team doing the changeover."),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"Standalone to consumer transition timeline",src:n(4191).Z,width:"5307",height:"2157"})),(0,i.kt)("h3",{id:"1-consumeradditionproposal-on-provider-chain"},"1. ",(0,i.kt)("inlineCode",{parentName:"h3"},"ConsumerAdditionProposal")," on provider chain"),(0,i.kt)("p",null,"This step will add the standalone chain to the list of consumer chains secured by the provider.\nThis step dictates the ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time"),". After ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time")," the CCV state (initial validator set of the provider) will be available to the consumer."),(0,i.kt)("p",null,"To obtain it from the provider use:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad q provider consumer-genesis stride-1 -o json > ccv-state.json\njq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' genesis.json ccv-state.json > ccv.json\n")),(0,i.kt)("h3",{id:"2-softwareupgradeproposal-on-the-standaloneconsumer-chain"},"2. ",(0,i.kt)("inlineCode",{parentName:"h3"},"SoftwareUpgradeProposal")," on the standalone/consumer chain"),(0,i.kt)("p",null,"This upgrade proposal will introduce ICS to the standalone chain, making it a consumer."),(0,i.kt)("h3",{id:"3-assigning-a-consumer-key"},"3. Assigning a consumer key"),(0,i.kt)("p",null,"After ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time"),", make sure to assign a consumer key if you intend to use one."),(0,i.kt)("p",null,"Instructions are available ",(0,i.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.2.0/features/key-assignment"},"here")),(0,i.kt)("h3",{id:"4-perform-the-software-ugprade-on-standalone-chain"},"4. Perform the software ugprade on standalone chain"),(0,i.kt)("p",null,"Please use instructions provided by the standalone chain team and make sure to reach out if you are facing issues.\nThe upgrade preparation depends on your setup, so please make sure you prepare ahead of time."),(0,i.kt)("admonition",{type:"danger"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"ccv.json")," from step 1. must be made available on the machine running the standalone/consumer chain at standalone chain ",(0,i.kt)("inlineCode",{parentName:"p"},"upgrade_height"),". This file contains the initial validator set and parameters required for normal ICS operation."),(0,i.kt)("p",{parentName:"admonition"},"Usually, the file is placed in ",(0,i.kt)("inlineCode",{parentName:"p"},"$NODE_HOME/config")," but this is not a strict requirement. The exact details are available in the upgrade code of the standalone/consumer chain.")),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Performing this upgrade will transition the standalone chain to be a consumer chain.")),(0,i.kt)("p",null,'After 3 blocks, the standalone chain will stop using the "old" validator set and begin using the ',(0,i.kt)("inlineCode",{parentName:"p"},"provider")," validator set."),(0,i.kt)("h2",{id:"faq"},"FAQ"),(0,i.kt)("h3",{id:"can-i-reuse-the-same-validator-key-for-the-consumer-chain-that-i-am-already-using-on-the-standalone-chain-will-i-need-to-perform-a-assignconsumerkey-tx-with-this-key-before-spawn-time"},"Can I reuse the same validator key for the ",(0,i.kt)("inlineCode",{parentName:"h3"},"consumer")," chain that I am already using on the ",(0,i.kt)("inlineCode",{parentName:"h3"},"standalone")," chain? Will I need to perform a ",(0,i.kt)("inlineCode",{parentName:"h3"},"AssignConsumerKey")," tx with this key before spawn time?"),(0,i.kt)("p",null,"Validators must either assign a key or use the same key as on the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider"),"."),(0,i.kt)("p",null,"If you are validating both the ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," and the ",(0,i.kt)("inlineCode",{parentName:"p"},"provider"),", you ",(0,i.kt)("strong",{parentName:"p"},"can")," use your current ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," key with some caveats:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"you must submit an ",(0,i.kt)("inlineCode",{parentName:"li"},"AssignConsumerKey")," tx with your current ",(0,i.kt)("inlineCode",{parentName:"li"},"standalone")," validator key"),(0,i.kt)("li",{parentName:"ul"},"it is best to submit ",(0,i.kt)("inlineCode",{parentName:"li"},"AssignConsumerKey")," tx before ",(0,i.kt)("inlineCode",{parentName:"li"},"spawn_time")),(0,i.kt)("li",{parentName:"ul"},"if you do not submit the Tx, it is assumed that you will be re-using your ",(0,i.kt)("inlineCode",{parentName:"li"},"provider")," key to validate the ",(0,i.kt)("inlineCode",{parentName:"li"},"standalone/consumer")," chain")),(0,i.kt)("h3",{id:"can-i-continue-using-the-same-node-that-was-validating-the-standalone-chain"},"Can I continue using the same node that was validating the ",(0,i.kt)("inlineCode",{parentName:"h3"},"standalone")," chain?"),(0,i.kt)("p",null,"Yes."),(0,i.kt)("p",null,"Please assign your consensus key as stated aboce."),(0,i.kt)("h3",{id:"can-i-set-up-a-new-node-to-validate-the-standaloneconsumer-chain-after-it-transitions-to-replicated-security"},"Can I set up a new node to validate the ",(0,i.kt)("inlineCode",{parentName:"h3"},"standalone/consumer")," chain after it transitions to replicated security?"),(0,i.kt)("p",null,"Yes."),(0,i.kt)("p",null,"If you are planning to do this please make sure that the node is synced with ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," network and to submit ",(0,i.kt)("inlineCode",{parentName:"p"},"AssignConsumerKey")," tx before ",(0,i.kt)("inlineCode",{parentName:"p"},"spawn_time"),"."),(0,i.kt)("h3",{id:"what-happens-to-the-standalone-validator-set-after-it-after-it-transitions-to-replicated-security"},"What happens to the ",(0,i.kt)("inlineCode",{parentName:"h3"},"standalone")," validator set after it after it transitions to replicated security?"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," chain validators will stop being validators after the first 3 blocks are created while using replicated security. The ",(0,i.kt)("inlineCode",{parentName:"p"},"standalone")," validators will become ",(0,i.kt)("strong",{parentName:"p"},"governors")," and still can receive delegations if the ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer")," chain is using the ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer-democracy")," module."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Governors DO NOT VALIDATE BLOCKS"),"."),(0,i.kt)("p",null,"Instead, they can participate in the governance process and take on other chain-specific roles."),(0,i.kt)("h2",{id:"credits"},"Credits"),(0,i.kt)("p",null,"Thank you Stride team for providing detailed instructions about the changeover procedure."))}u.isMDXComponent=!0},4191:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/ics_changeover_timeline_stride-9bcad1834fef24a0fea7f2c80c9ccd71.png"}}]); \ No newline at end of file diff --git a/legacy/assets/js/f249e987.cf824747.js b/legacy/assets/js/f249e987.cf824747.js new file mode 100644 index 0000000000..66da0e6506 --- /dev/null +++ b/legacy/assets/js/f249e987.cf824747.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9117],{3905:(e,r,t)=>{t.d(r,{Zo:()=>u,kt:()=>f});var n=t(7294);function i(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function o(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function a(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?o(Object(t),!0).forEach((function(r){i(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function s(e,r){if(null==e)return{};var t,n,i=function(e,r){if(null==e)return{};var t,n,i={},o=Object.keys(e);for(n=0;n<o.length;n++)t=o[n],r.indexOf(t)>=0||(i[t]=e[t]);return i}(e,r);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)t=o[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var d=n.createContext({}),c=function(e){var r=n.useContext(d),t=r;return e&&(t="function"==typeof e?e(r):a(a({},r),e)),t},u=function(e){var r=c(e.components);return n.createElement(d.Provider,{value:r},e.children)},l="mdxType",p={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},m=n.forwardRef((function(e,r){var t=e.components,i=e.mdxType,o=e.originalType,d=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),l=c(t),m=i,f=l["".concat(d,".").concat(m)]||l[m]||p[m]||o;return t?n.createElement(f,a(a({ref:r},u),{},{components:t})):n.createElement(f,a({ref:r},u))}));function f(e,r){var t=arguments,i=r&&r.mdxType;if("string"==typeof e||i){var o=t.length,a=new Array(o);a[0]=m;var s={};for(var d in r)hasOwnProperty.call(r,d)&&(s[d]=r[d]);s.originalType=e,s[l]="string"==typeof e?e:i,a[1]=s;for(var c=2;c<o;c++)a[c]=t[c];return n.createElement.apply(null,a)}return n.createElement.apply(null,t)}m.displayName="MDXCreateElement"},4071:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>d,contentTitle:()=>a,default:()=>p,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var n=t(7462),i=(t(7294),t(3905));const o={sidebar_position:2},a="Reward distribution",s={unversionedId:"features/reward-distribution",id:"version-v2.0.0/features/reward-distribution",title:"Reward distribution",description:"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.",source:"@site/versioned_docs/version-v2.0.0/features/reward-distribution.md",sourceDirName:"features",slug:"/features/reward-distribution",permalink:"/interchain-security/legacy/v2.0.0/features/reward-distribution",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/legacy/v2.0.0/features/key-assignment"},next:{title:"ICS Provider Proposals",permalink:"/interchain-security/legacy/v2.0.0/features/proposals"}},d={},c=[{value:"Parameters",id:"parameters",level:2},{value:"<code>consumer_redistribution_fraction</code>",id:"consumer_redistribution_fraction",level:3},{value:"<code>blocks_per_distribution_transmission</code>",id:"blocks_per_distribution_transmission",level:3},{value:"<code>transfer_timeout_period</code>",id:"transfer_timeout_period",level:3},{value:"<code>distribution_transmission_channel</code>",id:"distribution_transmission_channel",level:3},{value:"<code>provider_fee_pool_addr_str</code>",id:"provider_fee_pool_addr_str",level:3}],u={toc:c},l="wrapper";function p(e){let{components:r,...t}=e;return(0,i.kt)(l,(0,n.Z)({},u,t,{components:r,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"reward-distribution"},"Reward distribution"),(0,i.kt)("p",null,"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.\nIn replicated security block rewards and fees are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel that gets created during consumer chain initialization."),(0,i.kt)("p",null,"Reward distribution on the provider is handled by the distribution module - validators and delegators receive a fraction of the consumer chain tokens as staking rewards.\nThe distributed reward tokens are IBC tokens and therefore cannot be staked on the provider chain."),(0,i.kt)("p",null,"Sending and distributing rewards from consumer chains to provider chain is handled by the ",(0,i.kt)("inlineCode",{parentName:"p"},"Reward Distribution")," sub-protocol."),(0,i.kt)("h2",{id:"parameters"},"Parameters"),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"The following chain parameters dictate consumer chain distribution amount and frequency.\nThey are set at consumer genesis and ",(0,i.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction"),"\n",(0,i.kt)("inlineCode",{parentName:"p"},"transfer_timeout_period")," must be provided in every ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerChainAddition")," proposal.")),(0,i.kt)("h3",{id:"consumer_redistribution_fraction"},(0,i.kt)("inlineCode",{parentName:"h3"},"consumer_redistribution_fraction")),(0,i.kt)("p",null,'The fraction of tokens sent from consumer to provider during distribution events. The fraction is a string representing a decimal number. For example "0.75" would represent 75%.'),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"Example:"),(0,i.kt)("p",{parentName:"admonition"},"With ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction")," set to ",(0,i.kt)("inlineCode",{parentName:"p"},"0.75")," the consumer chain would send 75% of its block rewards and accumulated fees to the consumer chain and the remaining 25% to the provider chain every ",(0,i.kt)("inlineCode",{parentName:"p"},"n")," blocks where ",(0,i.kt)("inlineCode",{parentName:"p"},"n == blocks_per_distribution_transmission"),".")),(0,i.kt)("h3",{id:"blocks_per_distribution_transmission"},(0,i.kt)("inlineCode",{parentName:"h3"},"blocks_per_distribution_transmission")),(0,i.kt)("p",null,"The number of blocks between IBC token transfers from the consumer chain to the provider chain."),(0,i.kt)("h3",{id:"transfer_timeout_period"},(0,i.kt)("inlineCode",{parentName:"h3"},"transfer_timeout_period")),(0,i.kt)("p",null,"Timeout period for consumer chain reward distribution IBC packets."),(0,i.kt)("h3",{id:"distribution_transmission_channel"},(0,i.kt)("inlineCode",{parentName:"h3"},"distribution_transmission_channel")),(0,i.kt)("p",null,"Provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."),(0,i.kt)("h3",{id:"provider_fee_pool_addr_str"},(0,i.kt)("inlineCode",{parentName:"h3"},"provider_fee_pool_addr_str")),(0,i.kt)("p",null,"Provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/f37bbee8.118148f8.js b/legacy/assets/js/f37bbee8.118148f8.js new file mode 100644 index 0000000000..47ebbff59b --- /dev/null +++ b/legacy/assets/js/f37bbee8.118148f8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3739],{3905:(e,n,t)=>{t.d(n,{Zo:()=>m,kt:()=>d});var r=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function c(e,n){if(null==e)return{};var t,r,o=function(e,n){if(null==e)return{};var t,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var s=r.createContext({}),l=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},m=function(e){var n=l(e.components);return r.createElement(s.Provider,{value:n},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},p=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,m=c(e,["components","mdxType","originalType","parentName"]),u=l(t),p=o,d=u["".concat(s,".").concat(p)]||u[p]||h[p]||a;return t?r.createElement(d,i(i({ref:n},m),{},{components:t})):r.createElement(d,i({ref:n},m))}));function d(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=p;var c={};for(var s in n)hasOwnProperty.call(n,s)&&(c[s]=n[s]);c.originalType=e,c[u]="string"==typeof e?e:o,i[1]=c;for(var l=2;l<a;l++)i[l]=t[l];return r.createElement.apply(null,i)}return r.createElement.apply(null,t)}p.displayName="MDXCreateElement"},310:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>h,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var r=t(7462),o=(t(7294),t(3905));const a={sidebar_position:2},i="Consumer Chain Governance",c={unversionedId:"consumer-development/consumer-chain-governance",id:"version-v3.2.0/consumer-development/consumer-chain-governance",title:"Consumer Chain Governance",description:'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.',source:"@site/versioned_docs/version-v3.2.0/consumer-development/consumer-chain-governance.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-chain-governance",permalink:"/interchain-security/legacy/v3.2.0/consumer-development/consumer-chain-governance",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/legacy/v3.2.0/consumer-development/app-integration"},next:{title:"Onboarding Checklist",permalink:"/interchain-security/legacy/v3.2.0/consumer-development/onboarding"}},s={},l=[{value:"Democracy module",id:"democracy-module",level:2},{value:"CosmWasm",id:"cosmwasm",level:2},{value:"The Whitelist",id:"the-whitelist",level:2}],m={toc:l},u="wrapper";function h(e){let{components:n,...t}=e;return(0,o.kt)(u,(0,r.Z)({},m,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-chain-governance"},"Consumer Chain Governance"),(0,o.kt)("p",null,'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.'),(0,o.kt)("h2",{id:"democracy-module"},"Democracy module"),(0,o.kt)("p",null,"The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy."),(0,o.kt)("p",null,"Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus."),(0,o.kt)("p",null,"For an example, see the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy"},"Democracy Consumer")),(0,o.kt)("h2",{id:"cosmwasm"},"CosmWasm"),(0,o.kt)("p",null,"There are several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain."),(0,o.kt)("p",null,"For an example, see ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/neutron-org/neutron/"},"Neutron"),"."),(0,o.kt)("h2",{id:"the-whitelist"},"The Whitelist"),(0,o.kt)("p",null,"Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/neutron-org/neutron/blob/main/app/proposals_allowlisting.go"},"Neutron's")," whitelist."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/f4495aae.7cec05a4.js b/legacy/assets/js/f4495aae.7cec05a4.js new file mode 100644 index 0000000000..5bb3157b5c --- /dev/null +++ b/legacy/assets/js/f4495aae.7cec05a4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5045],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>v});var i=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function r(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,i,o=function(e,n){if(null==e)return{};var t,i,o={},a=Object.keys(e);for(i=0;i<a.length;i++)t=a[i],n.indexOf(t)>=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i<a.length;i++)t=a[i],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=i.createContext({}),u=function(e){var n=i.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):r(r({},n),e)),t},p=function(e){var n=u(e.components);return i.createElement(l.Provider,{value:n},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},h=i.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=u(t),h=o,v=d["".concat(l,".").concat(h)]||d[h]||c[h]||a;return t?i.createElement(v,r(r({ref:n},p),{},{components:t})):i.createElement(v,r({ref:n},p))}));function v(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,r=new Array(a);r[0]=h;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:o,r[1]=s;for(var u=2;u<a;u++)r[u]=t[u];return i.createElement.apply(null,r)}return i.createElement.apply(null,t)}h.displayName="MDXCreateElement"},3896:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>r,default:()=>c,frontMatter:()=>a,metadata:()=>s,toc:()=>u});var i=t(7462),o=(t(7294),t(3905));const a={sidebar_position:2,title:"ADR Template"},r="ADR 007: Pause validator unbonding during equivocation proposal",s={unversionedId:"adrs/adr-007-pause-unbonding-on-eqv-prop",id:"version-v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-prop",title:"ADR Template",description:"Changelog",source:"@site/versioned_docs/version-v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-prop.md",sourceDirName:"adrs",slug:"/adrs/adr-007-pause-unbonding-on-eqv-prop",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-prop",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:2,frontMatter:{sidebar_position:2,title:"ADR Template"},sidebar:"tutorialSidebar",previous:{title:"ADRs",permalink:"/interchain-security/legacy/v3.3.0/adrs/intro"},next:{title:"ADR Template",permalink:"/interchain-security/legacy/v3.3.0/adrs/adr-template"}},l={},u=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"How",id:"how",level:3},{value:"When pause",id:"when-pause",level:3},{value:"When unpause",id:"when-unpause",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],p={toc:u},d="wrapper";function c(e){let{components:n,...t}=e;return(0,o.kt)(d,(0,i.Z)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"adr-007-pause-validator-unbonding-during-equivocation-proposal"},"ADR 007: Pause validator unbonding during equivocation proposal"),(0,o.kt)("h2",{id:"changelog"},"Changelog"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"2023-05-16: Initial Draft")),(0,o.kt)("h2",{id:"status"},"Status"),(0,o.kt)("p",null,"Proposed"),(0,o.kt)("h2",{id:"context"},"Context"),(0,o.kt)("p",null,"Currently, if an equivocation slashing proposal is created after more than one\nweek has passed since the equivocation, it is possible that the validator in\nquestion could unbond and get away without being slashed, since the unbonding\nperiod is 3 weeks, and the voting period is 2 weeks. For this reason, it might\nbe good to pause unbondings for validators named in an equivocation slashing\nproposal until the proposal's voting period is over."),(0,o.kt)("h2",{id:"decision"},"Decision"),(0,o.kt)("h3",{id:"how"},"How"),(0,o.kt)("p",null,"Pausing the unbonding period is already possible thanks to the changes in the\n",(0,o.kt)("inlineCode",{parentName:"p"},"staking")," module of the cosmos-sdk:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"stakingKeeper.PutUnbondingOnHold")," pauses an unbonding period"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"stakingKeeper.UnbondingCanComplete")," unpauses an unbonding period")),(0,o.kt)("p",null,"These methods use a reference counter under the hood, that gets incremented\nevery time ",(0,o.kt)("inlineCode",{parentName:"p"},"PutUnbondingOnHold")," is called, and decreased when\n",(0,o.kt)("inlineCode",{parentName:"p"},"UnbondingCanComplete")," is called instead. A specific unbonding is considered\nfully unpaused when its underlying reference counter reaches 0. Therefore, as\nlong as we safeguard consistency - i.e. we make sure we eventually decrement\nthe reference counter for each time we have incremented it - we can safely use\nthis existing mechanism without conflicts with the ",(0,o.kt)("em",{parentName:"p"},"Completion of Unbonding\nOperations")," system."),(0,o.kt)("h3",{id:"when-pause"},"When pause"),(0,o.kt)("p",null,"The unbonding period (if there is any unbonding) should be paused once an\nequivocation proposal enters the voting period. For that, the ",(0,o.kt)("inlineCode",{parentName:"p"},"gov")," module's\nhook ",(0,o.kt)("inlineCode",{parentName:"p"},"AfterProposalDeposit")," can be used. "),(0,o.kt)("p",null,"If the hook is triggered with a an equivocation proposal in voting period, then\nfor each equivocation of the proposal, the unbonding operations of the related\nvalidator that were initiated after the equivocation block time must be paused"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"i.e. the underlying reference counter has to be increased.")),(0,o.kt)("p",null,"Note that even after the voting period has started, a proposal can receive\nadditional deposits. The hook is triggered however at arrival of a deposit, so\na check to verify that the proposal is not already in voting period is\nrequired."),(0,o.kt)("h3",{id:"when-unpause"},"When unpause"),(0,o.kt)("p",null,"We can use a ",(0,o.kt)("inlineCode",{parentName:"p"},"gov")," module's hook also here and it is\n",(0,o.kt)("inlineCode",{parentName:"p"},"AfterProposalVotingPeriodEnded"),"."),(0,o.kt)("p",null,"If the hook is triggered with an equivocation proposal, then for each\nassociated equivocation, the unbonding operations of the related validator that\nwere initiated between the equivocation block time and the start of the\nproposal voting period must be unpaused - i.e. decrease the underlying\nreference counter - regardless of the proposal outcome."),(0,o.kt)("h2",{id:"consequences"},"Consequences"),(0,o.kt)("h3",{id:"positive"},"Positive"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Validators subject to an equivocation proposal cannot finish unbonding\ntheir tokens before the end of the voting period.")),(0,o.kt)("h3",{id:"negative"},"Negative"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"A malicious consumer chain could forge slash packets enabling submission of\nan equivocation proposal on the provider chain, resulting in the freezing of\nvalidator's unbondings for an undeterminated amount of time."),(0,o.kt)("li",{parentName:"ul"},"Misbehavior on a consumer chain can potentially go unpunished, if no one\nsubmits an equivocation proposal in time, or if the proposal doesn't pass.")),(0,o.kt)("h3",{id:"neutral"},"Neutral"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"This feature can't be used for social slashing, because an equivocation\nproposal is only accepted if there's a slash log for the related\nvalidator(s), meaning the consumer chain has reported the equivocation to\nthe provider chain.")),(0,o.kt)("h2",{id:"references"},"References"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/747"},"https://github.com/cosmos/interchain-security/issues/747")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/pull/791"},"https://github.com/cosmos/interchain-security/pull/791"))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/f496e447.958e6164.js b/legacy/assets/js/f496e447.958e6164.js new file mode 100644 index 0000000000..b0e14f992a --- /dev/null +++ b/legacy/assets/js/f496e447.958e6164.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[544],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>y});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?c(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):c(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function a(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},c=Object.keys(e);for(r=0;r<c.length;r++)n=c[r],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(r=0;r<c.length;r++)n=c[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var p=r.createContext({}),s=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},l=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,c=e.originalType,p=e.parentName,l=a(e,["components","mdxType","originalType","parentName"]),u=s(n),d=i,y=u["".concat(p,".").concat(d)]||u[d]||f[d]||c;return n?r.createElement(y,o(o({ref:t},l),{},{components:n})):r.createElement(y,o({ref:t},l))}));function y(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var c=n.length,o=new Array(c);o[0]=d;var a={};for(var p in t)hasOwnProperty.call(t,p)&&(a[p]=t[p]);a.originalType=e,a[u]="string"==typeof e?e:i,o[1]=a;for(var s=2;s<c;s++)o[s]=n[s];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},3898:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>f,frontMatter:()=>c,metadata:()=>a,toc:()=>s});var r=n(7462),i=(n(7294),n(3905));const c={sidebar_position:4},o="Technical Specification",a={unversionedId:"introduction/technical-specification",id:"version-v3.2.0/introduction/technical-specification",title:"Technical Specification",description:"For a technical deep dive into the replicated security protocol, see the specification.",source:"@site/versioned_docs/version-v3.2.0/introduction/technical-specification.md",sourceDirName:"introduction",slug:"/introduction/technical-specification",permalink:"/interchain-security/legacy/v3.2.0/introduction/technical-specification",draft:!1,tags:[],version:"v3.2.0",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Parameters",permalink:"/interchain-security/legacy/v3.2.0/introduction/params"},next:{title:"Key Assignment",permalink:"/interchain-security/legacy/v3.2.0/features/key-assignment"}},p={},s=[],l={toc:s},u="wrapper";function f(e){let{components:t,...n}=e;return(0,i.kt)(u,(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"technical-specification"},"Technical Specification"),(0,i.kt)("p",null,"For a technical deep dive into the replicated security protocol, see the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/README.md"},"specification"),"."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/f4ce0483.d7b208a3.js b/legacy/assets/js/f4ce0483.d7b208a3.js new file mode 100644 index 0000000000..d1eb5a425b --- /dev/null +++ b/legacy/assets/js/f4ce0483.d7b208a3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[468],{3905:(e,r,n)=>{n.d(r,{Zo:()=>u,kt:()=>h});var t=n(7294);function o(e,r,n){return r in e?Object.defineProperty(e,r,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[r]=n,e}function a(e,r){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);r&&(t=t.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),n.push.apply(n,t)}return n}function i(e){for(var r=1;r<arguments.length;r++){var n=null!=arguments[r]?arguments[r]:{};r%2?a(Object(n),!0).forEach((function(r){o(e,r,n[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(n,r))}))}return e}function s(e,r){if(null==e)return{};var n,t,o=function(e,r){if(null==e)return{};var n,t,o={},a=Object.keys(e);for(t=0;t<a.length;t++)n=a[t],r.indexOf(n)>=0||(o[n]=e[n]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(t=0;t<a.length;t++)n=a[t],r.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=t.createContext({}),l=function(e){var r=t.useContext(c),n=r;return e&&(n="function"==typeof e?e(r):i(i({},r),e)),n},u=function(e){var r=l(e.components);return t.createElement(c.Provider,{value:r},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var r=e.children;return t.createElement(t.Fragment,{},r)}},p=t.forwardRef((function(e,r){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=l(n),p=o,h=d["".concat(c,".").concat(p)]||d[p]||m[p]||a;return n?t.createElement(h,i(i({ref:r},u),{},{components:n})):t.createElement(h,i({ref:r},u))}));function h(e,r){var n=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=p;var s={};for(var c in r)hasOwnProperty.call(r,c)&&(s[c]=r[c]);s.originalType=e,s[d]="string"==typeof e?e:o,i[1]=s;for(var l=2;l<a;l++)i[l]=n[l];return t.createElement.apply(null,i)}return t.createElement.apply(null,n)}p.displayName="MDXCreateElement"},2625:(e,r,n)=>{n.r(r),n.d(r,{assets:()=>c,contentTitle:()=>i,default:()=>m,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var t=n(7462),o=(n(7294),n(3905));const a={sidebar_position:6},i="Consumer Genesis Transformation",s={unversionedId:"consumer-development/consumer-genesis-transformation",id:"version-v3.3.1-lsm/consumer-development/consumer-genesis-transformation",title:"Consumer Genesis Transformation",description:"Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentaion on Onboarding and Changeover).",source:"@site/versioned_docs/version-v3.3.1-lsm/consumer-development/consumer-genesis-transformation.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-genesis-transformation",permalink:"/interchain-security/legacy/consumer-development/consumer-genesis-transformation",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"tutorialSidebar",previous:{title:"Changeover Procedure",permalink:"/interchain-security/legacy/consumer-development/changeover-procedure"},next:{title:"Overview",permalink:"/interchain-security/legacy/validators/overview"}},c={},l=[{value:"1. Prerequisite",id:"1-prerequisite",level:2},{value:"2. Export the CCV data",id:"2-export-the-ccv-data",level:2},{value:"3. Transform CCV data",id:"3-transform-ccv-data",level:2}],u={toc:l},d="wrapper";function m(e){let{components:r,...n}=e;return(0,o.kt)(d,(0,t.Z)({},u,n,{components:r,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-genesis-transformation"},"Consumer Genesis Transformation"),(0,o.kt)("p",null,"Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentaion on ",(0,o.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/onboarding"},"Onboarding")," and ",(0,o.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/changeover-procedure"},"Changeover"),").\nIn case that the provider chain is running an older version of the InterChainSecurity (ICS) module than the consumer chain the exported CCV data might need to be transformed to the format supported by the ICS implementation run on the consumer chain. This is the case if the cosumer chain runs version 4 of ICS or later and the provider is running version 3 or older of the ICS module."),(0,o.kt)("p",null,"To transform such CCV data follow the instructions below"),(0,o.kt)("h2",{id:"1-prerequisite"},"1. Prerequisite"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Provider chain is running version 3 or older of the ICS provider module"),(0,o.kt)("li",{parentName:"ul"},"Consumer is running version 4 or later of the ICS consumer module."),(0,o.kt)("li",{parentName:"ul"},"interchain-security-cd application complies to the version run on the consumer chain")),(0,o.kt)("h2",{id:"2-export-the-ccv-data"},"2. Export the CCV data"),(0,o.kt)("p",null,"Export the CCV data from the provider chain as descibed in the ",(0,o.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/onboarding"},"Onboarding")," and ",(0,o.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/changeover-procedure"},"Changeover"),") your following.\nAs a result the CCV data will be stored in a file in JSON format."),(0,o.kt)("h2",{id:"3-transform-ccv-data"},"3. Transform CCV data"),(0,o.kt)("p",null,"To transform the CCV data to the newer format run the following command."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"interchain-security-cd genesis transform [genesis-file]\n")),(0,o.kt)("p",null,"where 'genesis-file' is the path to the file containing the CCV data exported in ",(0,o.kt)("a",{parentName:"p",href:"#2-export-the-ccv-data"},"step 2"),".\nAs a result the CCV data in the new format will be written to standard output."),(0,o.kt)("p",null,"Use the new CCV data as described in the procedure you're following."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/f5589540.6c0ad7d0.js b/legacy/assets/js/f5589540.6c0ad7d0.js new file mode 100644 index 0000000000..5cba9be8b2 --- /dev/null +++ b/legacy/assets/js/f5589540.6c0ad7d0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6499],{3905:(e,n,t)=>{t.d(n,{Zo:()=>m,kt:()=>d});var r=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function c(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function i(e,n){if(null==e)return{};var t,r,o=function(e,n){if(null==e)return{};var t,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var s=r.createContext({}),l=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):c(c({},n),e)),t},m=function(e){var n=l(e.components);return r.createElement(s.Provider,{value:n},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},p=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,m=i(e,["components","mdxType","originalType","parentName"]),u=l(t),p=o,d=u["".concat(s,".").concat(p)]||u[p]||h[p]||a;return t?r.createElement(d,c(c({ref:n},m),{},{components:t})):r.createElement(d,c({ref:n},m))}));function d(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,c=new Array(a);c[0]=p;var i={};for(var s in n)hasOwnProperty.call(n,s)&&(i[s]=n[s]);i.originalType=e,i[u]="string"==typeof e?e:o,c[1]=i;for(var l=2;l<a;l++)c[l]=t[l];return r.createElement.apply(null,c)}return r.createElement.apply(null,t)}p.displayName="MDXCreateElement"},4906:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>c,default:()=>h,frontMatter:()=>a,metadata:()=>i,toc:()=>l});var r=t(7462),o=(t(7294),t(3905));const a={sidebar_position:2},c="Consumer Chain Governance",i={unversionedId:"consumer-development/consumer-chain-governance",id:"consumer-development/consumer-chain-governance",title:"Consumer Chain Governance",description:'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.',source:"@site/docs/consumer-development/consumer-chain-governance.md",sourceDirName:"consumer-development",slug:"/consumer-development/consumer-chain-governance",permalink:"/interchain-security/legacy/consumer-development/consumer-chain-governance",draft:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Developing an ICS consumer chain",permalink:"/interchain-security/legacy/consumer-development/app-integration"},next:{title:"Onboarding Checklist",permalink:"/interchain-security/legacy/consumer-development/onboarding"}},s={},l=[{value:"Democracy module",id:"democracy-module",level:2},{value:"CosmWasm",id:"cosmwasm",level:2},{value:"The Whitelist",id:"the-whitelist",level:2}],m={toc:l},u="wrapper";function h(e){let{components:n,...t}=e;return(0,o.kt)(u,(0,r.Z)({},m,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-chain-governance"},"Consumer Chain Governance"),(0,o.kt)("p",null,'Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the "Whitelist" section below.'),(0,o.kt)("h2",{id:"democracy-module"},"Democracy module"),(0,o.kt)("p",null,"The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy."),(0,o.kt)("p",null,"Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus."),(0,o.kt)("p",null,"For an example, see the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/tree/main/app/consumer-democracy"},"Democracy Consumer")),(0,o.kt)("h2",{id:"cosmwasm"},"CosmWasm"),(0,o.kt)("p",null,"There are several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain."),(0,o.kt)("p",null,"For an example, see ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/neutron-org/neutron/"},"Neutron"),"."),(0,o.kt)("h2",{id:"the-whitelist"},"The Whitelist"),(0,o.kt)("p",null,"Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/neutron-org/neutron/blob/main/app/proposals_allowlisting.go"},"Neutron's")," whitelist."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/f5746d50.6a4430ce.js b/legacy/assets/js/f5746d50.6a4430ce.js new file mode 100644 index 0000000000..254ba89399 --- /dev/null +++ b/legacy/assets/js/f5746d50.6a4430ce.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8313],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>m});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?i(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,a,r=function(e,n){if(null==e)return{};var t,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=a.createContext({}),c=function(e){var n=a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=c(e.components);return a.createElement(l.Provider,{value:n},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},y=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=c(t),y=r,m=d["".concat(l,".").concat(y)]||d[y]||p[y]||i;return t?a.createElement(m,o(o({ref:n},u),{},{components:t})):a.createElement(m,o({ref:n},u))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,o=new Array(i);o[0]=y;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var c=2;c<i;c++)o[c]=t[c];return a.createElement.apply(null,o)}return a.createElement.apply(null,t)}y.displayName="MDXCreateElement"},7519:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var a=t(7462),r=(t(7294),t(3905));const i={sidebar_position:1},o="Key Assignment",s={unversionedId:"features/key-assignment",id:"version-v3.3.0/features/key-assignment",title:"Key Assignment",description:"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.",source:"@site/versioned_docs/version-v3.3.0/features/key-assignment.md",sourceDirName:"features",slug:"/features/key-assignment",permalink:"/interchain-security/legacy/v3.3.0/features/key-assignment",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Technical Specification",permalink:"/interchain-security/legacy/v3.3.0/introduction/technical-specification"},next:{title:"Reward distribution",permalink:"/interchain-security/legacy/v3.3.0/features/reward-distribution"}},l={},c=[{value:"Rules",id:"rules",level:2},{value:"Adding a key",id:"adding-a-key",level:2},{value:"Changing a key",id:"changing-a-key",level:2},{value:"Removing a key",id:"removing-a-key",level:2}],u={toc:c},d="wrapper";function p(e){let{components:n,...t}=e;return(0,r.kt)(d,(0,a.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"key-assignment"},"Key Assignment"),(0,r.kt)("p",null,"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.\nThere are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains."),(0,r.kt)("p",null,"The feature is outlined in this ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v3.3.0/adrs/adr-001-key-assignment"},"ADR-001")),(0,r.kt)("p",null,"By sending an ",(0,r.kt)("inlineCode",{parentName:"p"},"AssignConsumerKey")," transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity.")),(0,r.kt)("h2",{id:"rules"},"Rules"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"a key can be assigned before the consumer addition proposal passes on the provider"),(0,r.kt)("li",{parentName:"ul"},"validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider"),(0,r.kt)("li",{parentName:"ul"},"validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X"),(0,r.kt)("li",{parentName:"ul"},"a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Validators can use a different key for each consumer chain.")),(0,r.kt)("h2",{id:"adding-a-key"},"Adding a key"),(0,r.kt)("p",null,"First, create a new node on the consumer chain using the equivalent:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"consumerd init <moniker>\n")),(0,r.kt)("p",null,"Then query your node for the consensus key."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}\n')),(0,r.kt)("p",null,"Then, make an ",(0,r.kt)("inlineCode",{parentName:"p"},"assign-consensus-key")," transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad tx provider assign-consensus-key <consumer-chain-id> '<pubkey>' --from <tx-signer> --home <home_dir> --gas 900000 -b sync -y -o json\n")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"consumer-chain-id")," is the string identifier of the consumer chain, as assigned on the provider chain"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"consumer-pub-key")," has the following format ",(0,r.kt)("inlineCode",{parentName:"li"},'{"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}'))),(0,r.kt)("p",null,"Check that the key was assigned correctly by querying the provider:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad query provider validator-consumer-key <consumer-chain-id> cosmosvalcons1e....3xsj3ayzf4uv6\n")),(0,r.kt)("p",null,"You must use a ",(0,r.kt)("inlineCode",{parentName:"p"},"valcons")," address. You can obtain it by querying your node on the provider ",(0,r.kt)("inlineCode",{parentName:"p"},"gaiad tendermint show-address")),(0,r.kt)("p",null,"OR"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad query provider validator-provider-key <consumer-chain-id> consumervalcons1e....123asdnoaisdao\n")),(0,r.kt)("p",null,"You must use a ",(0,r.kt)("inlineCode",{parentName:"p"},"valcons")," address. You can obtain it by querying your node on the consumer ",(0,r.kt)("inlineCode",{parentName:"p"},"consumerd tendermint show-address")),(0,r.kt)("p",null,"OR"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad query provider all-pairs-valconsensus-address <consumer-chain-id>\n")),(0,r.kt)("p",null,"You just need to use the ",(0,r.kt)("inlineCode",{parentName:"p"},"chainId")," of consumer to query all pairs valconsensus address with ",(0,r.kt)("inlineCode",{parentName:"p"},"consumer-pub-key")," for each of pair"),(0,r.kt)("h2",{id:"changing-a-key"},"Changing a key"),(0,r.kt)("p",null,"To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied"),(0,r.kt)("h2",{id:"removing-a-key"},"Removing a key"),(0,r.kt)("p",null,"To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the ",(0,r.kt)("inlineCode",{parentName:"p"},"Adding a key")," section and using your provider consensus key."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/f6addb2b.507409b8.js b/legacy/assets/js/f6addb2b.507409b8.js new file mode 100644 index 0000000000..b1b10dc9a9 --- /dev/null +++ b/legacy/assets/js/f6addb2b.507409b8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[35],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>m});var i=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?r(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):r(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,i,a=function(e,n){if(null==e)return{};var t,i,a={},r=Object.keys(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)t=r[i],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=i.createContext({}),c=function(e){var n=i.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},p=function(e){var n=c(e.components);return i.createElement(l.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},h=i.forwardRef((function(e,n){var t=e.components,a=e.mdxType,r=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(t),h=a,m=d["".concat(l,".").concat(h)]||d[h]||u[h]||r;return t?i.createElement(m,o(o({ref:n},p),{},{components:t})):i.createElement(m,o({ref:n},p))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var r=t.length,o=new Array(r);o[0]=h;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:a,o[1]=s;for(var c=2;c<r;c++)o[c]=t[c];return i.createElement.apply(null,o)}return i.createElement.apply(null,t)}h.displayName="MDXCreateElement"},7805:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>s,toc:()=>c});var i=t(7462),a=(t(7294),t(3905));const r={sidebar_position:1},o="Overview",s={unversionedId:"validators/overview",id:"validators/overview",title:"Overview",description:"We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.",source:"@site/docs/validators/overview.md",sourceDirName:"validators",slug:"/validators/overview",permalink:"/interchain-security/legacy/validators/overview",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Consumer Genesis Transformation",permalink:"/interchain-security/legacy/consumer-development/consumer-genesis-transformation"},next:{title:"Joining Replicated Security testnet",permalink:"/interchain-security/legacy/validators/joining-testnet"}},l={},c=[{value:"Startup sequence overview",id:"startup-sequence-overview",level:2},{value:"1. Consumer Chain init + 2. Genesis generation",id:"1-consumer-chain-init--2-genesis-generation",level:3},{value:"3. Submit Proposal",id:"3-submit-proposal",level:3},{value:"4. CCV Genesis state generation",id:"4-ccv-genesis-state-generation",level:3},{value:"5. Updating the genesis file",id:"5-updating-the-genesis-file",level:3},{value:"6. Chain start",id:"6-chain-start",level:3},{value:"7. Creating IBC connections",id:"7-creating-ibc-connections",level:3},{value:"Downtime Infractions",id:"downtime-infractions",level:2},{value:"Double-signing Infractions",id:"double-signing-infractions",level:2},{value:"Key assignment",id:"key-assignment",level:2},{value:"References:",id:"references",level:2}],p={toc:c},d="wrapper";function u(e){let{components:n,...r}=e;return(0,a.kt)(d,(0,i.Z)({},p,r,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"overview"},"Overview"),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"We advise that you join the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/tree/master/replicated-security"},"Replicated Security testnet")," to gain hands-on experience with running consumer chains.")),(0,a.kt)("p",null,"At present, replicated security requires all validators of the provider chain (ie. Cosmos Hub) to run validator nodes for all governance-approved consumer chains."),(0,a.kt)("p",null,"Once a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," passes, validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains."),(0,a.kt)("p",null,"Provider chain and consumer chains represent standalone chains that only share the validator set ie. the same validator operators are tasked with running all chains."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 180 validators for Cosmos Hub).")),(0,a.kt)("h2",{id:"startup-sequence-overview"},"Startup sequence overview"),(0,a.kt)("p",null,"Consumer chains cannot start and be secured by the validator set of the provider unless a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")," is passed.\nEach proposal contains defines a ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider."),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"Validators are required to run consumer chain binaries only after ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," has passed.")),(0,a.kt)("p",null,"Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains."),(0,a.kt)("p",null,"The image below illustrates the startup sequence\n",(0,a.kt)("img",{alt:"startup",src:t(1717).Z,width:"942",height:"632"})),(0,a.kt)("h3",{id:"1-consumer-chain-init--2-genesis-generation"},"1. Consumer Chain init + 2. Genesis generation"),(0,a.kt)("p",null,"Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal")),(0,a.kt)("h3",{id:"3-submit-proposal"},"3. Submit Proposal"),(0,a.kt)("p",null,"Consumer chain team (or their advocates) submits a ",(0,a.kt)("inlineCode",{parentName:"p"},"ConsumerAdditionProposal"),".\nThe most important parameters for validators are:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"spawn_time")," - the time after which the consumer chain must be started"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"genesis_hash")," - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and ",(0,a.kt)("inlineCode",{parentName:"li"},"spawn_time")," is reached"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"binary_hash")," - hash of the consumer chain binary used to validate the software builds")),(0,a.kt)("h3",{id:"4-ccv-genesis-state-generation"},"4. CCV Genesis state generation"),(0,a.kt)("p",null,"After reaching ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json"),". The CCV validator set consists of the validator set on the provider at ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time"),"."),(0,a.kt)("p",null,"The state can be queried on the provider chain (in this case the Cosmos Hub):"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json\n")),(0,a.kt)("p",null,"This is used by the launch coordinator to create the final ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," that will be distributed to validators in step 5."),(0,a.kt)("h3",{id:"5-updating-the-genesis-file"},"5. Updating the genesis file"),(0,a.kt)("p",null,"Upon reaching the ",(0,a.kt)("inlineCode",{parentName:"p"},"spawn_time")," the initial validator set state will become available on the provider chain. The initial validator set is included in the ",(0,a.kt)("strong",{parentName:"p"},"final genesis.json")," of the consumer chain."),(0,a.kt)("h3",{id:"6-chain-start"},"6. Chain start"),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences.")),(0,a.kt)("p",null,"The new ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided ",(0,a.kt)("inlineCode",{parentName:"p"},"genesis.json")," to start their consumer chain node."),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"Please pay attention to any onboarding repositories provided by the consumer chain teams.\nRecommendations are available in ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/consumer-development/onboarding"},"Consumer Onboarding Checklist"),".\nAnother comprehensive guide is available in the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md"},"Replicated Security testnet repo"),".")),(0,a.kt)("h3",{id:"7-creating-ibc-connections"},"7. Creating IBC connections"),(0,a.kt)("p",null,"Finally, to fully establish replicated security an IBC relayer is used to establish connections and create the required channels."),(0,a.kt)("admonition",{type:"warning"},(0,a.kt)("p",{parentName:"admonition"},"The relayer can establish the connection only after the consumer chain starts producing blocks.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> \nhermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1\nhermes start\n")),(0,a.kt)("h2",{id:"downtime-infractions"},"Downtime Infractions"),(0,a.kt)("p",null,"At present, the consumer chain can report evidence about downtime infractions to the provider chain. The ",(0,a.kt)("inlineCode",{parentName:"p"},"min_signed_per_window")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"signed_blocks_window")," can be different on each consumer chain and are subject to changes via consumer chain governance."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains."),(0,a.kt)("p",{parentName:"admonition"},"To unjail, the validator must wait for the jailing period to elapse on the provider chain and ",(0,a.kt)("a",{parentName:"p",href:"https://hub.cosmos.network/main/validators/validator-setup.html#unjail-validator"},"submit an unjail transaction")," on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains."),(0,a.kt)("p",{parentName:"admonition"},"More information is available in ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/features/slashing#downtime-infractions"},"Downtime Slashing documentation"))),(0,a.kt)("h2",{id:"double-signing-infractions"},"Double-signing Infractions"),(0,a.kt)("p",null,"To learn more about equivocation handling in replicated security check out the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/features/slashing#double-signing-equivocation"},"Slashing")," and ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/features/proposals#equivocationproposal"},"EquivocationProposal")," documentation sections"),(0,a.kt)("h2",{id:"key-assignment"},"Key assignment"),(0,a.kt)("p",null,"Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use."),(0,a.kt)("p",null,"For more information check our the ",(0,a.kt)("a",{parentName:"p",href:"/interchain-security/legacy/features/key-assignment"},"Key assignment overview and guide")),(0,a.kt)("h2",{id:"references"},"References:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-faq.html"},"Cosmos Hub Validators FAQ")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-setup.html"},"Cosmos Hub Running a validator")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md#chain-launch"},"Startup Sequence")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://hub.cosmos.network/main/validators/validator-setup.html#unjail-validator"},"Submit Unjailing Transaction"))))}u.isMDXComponent=!0},1717:(e,n,t)=>{t.d(n,{Z:()=>i});const i=t.p+"assets/images/hypha-consumer-start-process-2141109f76c584706dd994d7965fd692.svg"}}]); \ No newline at end of file diff --git a/legacy/assets/js/f7a87f6d.bb9958dd.js b/legacy/assets/js/f7a87f6d.bb9958dd.js new file mode 100644 index 0000000000..4e44621ca6 --- /dev/null +++ b/legacy/assets/js/f7a87f6d.bb9958dd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2117],{5693:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"v3.3.1-lsm","label":"v3.3.1-lsm","banner":null,"badge":true,"noIndex":false,"className":"docs-version-v3.3.1-lsm","isLast":true,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Interchain Security Docs","href":"/interchain-security/legacy/","docId":"index"},{"type":"category","label":"Introduction","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/legacy/introduction/overview","docId":"introduction/overview"},{"type":"link","label":"Terminology","href":"/interchain-security/legacy/introduction/terminology","docId":"introduction/terminology"},{"type":"link","label":"Interchain Security Parameters","href":"/interchain-security/legacy/introduction/params","docId":"introduction/params"},{"type":"link","label":"Technical Specification","href":"/interchain-security/legacy/introduction/technical-specification","docId":"introduction/technical-specification"}]},{"type":"category","label":"Features","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Key Assignment","href":"/interchain-security/legacy/features/key-assignment","docId":"features/key-assignment"},{"type":"link","label":"Reward distribution","href":"/interchain-security/legacy/features/reward-distribution","docId":"features/reward-distribution"},{"type":"link","label":"ICS Provider Proposals","href":"/interchain-security/legacy/features/proposals","docId":"features/proposals"},{"type":"link","label":"Consumer Initiated Slashing","href":"/interchain-security/legacy/features/slashing","docId":"features/slashing"}]},{"type":"category","label":"Consumer Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Developing an ICS consumer chain","href":"/interchain-security/legacy/consumer-development/app-integration","docId":"consumer-development/app-integration"},{"type":"link","label":"Consumer Chain Governance","href":"/interchain-security/legacy/consumer-development/consumer-chain-governance","docId":"consumer-development/consumer-chain-governance"},{"type":"link","label":"Onboarding Checklist","href":"/interchain-security/legacy/consumer-development/onboarding","docId":"consumer-development/onboarding"},{"type":"link","label":"Offboarding Checklist","href":"/interchain-security/legacy/consumer-development/offboarding","docId":"consumer-development/offboarding"},{"type":"link","label":"Changeover Procedure","href":"/interchain-security/legacy/consumer-development/changeover-procedure","docId":"consumer-development/changeover-procedure"},{"type":"link","label":"Consumer Genesis Transformation","href":"/interchain-security/legacy/consumer-development/consumer-genesis-transformation","docId":"consumer-development/consumer-genesis-transformation"}]},{"type":"category","label":"Validators Guide","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Overview","href":"/interchain-security/legacy/validators/overview","docId":"validators/overview"},{"type":"link","label":"Joining Replicated Security testnet","href":"/interchain-security/legacy/validators/joining-testnet","docId":"validators/joining-testnet"},{"type":"link","label":"Withdrawing consumer chain validator rewards","href":"/interchain-security/legacy/validators/withdraw_rewards","docId":"validators/withdraw_rewards"},{"type":"link","label":"Validator instructions for Changeover Procedure","href":"/interchain-security/legacy/validators/changeover-procedure","docId":"validators/changeover-procedure"},{"type":"link","label":"Joining Neutron","href":"/interchain-security/legacy/validators/joining-neutron","docId":"validators/joining-neutron"},{"type":"link","label":"Joining Stride","href":"/interchain-security/legacy/validators/joining-stride","docId":"validators/joining-stride"}]},{"type":"link","label":"Frequently Asked Questions","href":"/interchain-security/legacy/faq","docId":"frequently-asked-questions"},{"type":"category","label":"ADRs","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"ADRs","href":"/interchain-security/legacy/adrs/intro","docId":"adrs/intro"},{"type":"link","label":"ADR Template","href":"/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop","docId":"adrs/adr-007-pause-unbonding-on-eqv-prop"},{"type":"link","label":"ADR Template","href":"/interchain-security/legacy/adrs/adr-template","docId":"adrs/adr-template"},{"type":"link","label":"Key Assignment","href":"/interchain-security/legacy/adrs/adr-001-key-assignment","docId":"adrs/adr-001-key-assignment"},{"type":"link","label":"Jail Throttling","href":"/interchain-security/legacy/adrs/adr-002-throttle","docId":"adrs/adr-002-throttle"},{"type":"link","label":"Equivocation governance proposal","href":"/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposal","docId":"adrs/adr-003-equivocation-gov-proposal"},{"type":"link","label":"Cryptographic verification of equivocation evidence","href":"/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification","docId":"adrs/adr-005-cryptographic-equivocation-verification"},{"type":"link","label":"Throttle with retries","href":"/interchain-security/legacy/adrs/adr-008-throttle-retries","docId":"adrs/adr-008-throttle-retries"},{"type":"link","label":"Soft Opt-Out","href":"/interchain-security/legacy/adrs/adr-009-soft-opt-out","docId":"adrs/adr-009-soft-opt-out"},{"type":"link","label":"Standalone to Consumer Changeover","href":"/interchain-security/legacy/adrs/adr-010-standalone-changeover","docId":"adrs/adr-010-standalone-changeover"},{"type":"link","label":"Improving testing and increasing confidence","href":"/interchain-security/legacy/adrs/adr-011-improving-test-confidence","docId":"adrs/adr-011-improving-test-confidence"},{"type":"link","label":"Separate Releasing","href":"/interchain-security/legacy/adrs/adr-012-separate-releasing","docId":"adrs/adr-012-separate-releasing"},{"type":"link","label":"Slashing on the provider for consumer equivocation","href":"/interchain-security/legacy/adrs/adr-013-equivocation-slashing","docId":"adrs/adr-013-equivocation-slashing"}]}]},"docs":{"adrs/adr-001-key-assignment":{"id":"adrs/adr-001-key-assignment","title":"Key Assignment","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-002-throttle":{"id":"adrs/adr-002-throttle","title":"Jail Throttling","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-003-equivocation-gov-proposal":{"id":"adrs/adr-003-equivocation-gov-proposal","title":"Equivocation governance proposal","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-005-cryptographic-equivocation-verification":{"id":"adrs/adr-005-cryptographic-equivocation-verification","title":"Cryptographic verification of equivocation evidence","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-007-pause-unbonding-on-eqv-prop":{"id":"adrs/adr-007-pause-unbonding-on-eqv-prop","title":"ADR Template","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-008-throttle-retries":{"id":"adrs/adr-008-throttle-retries","title":"Throttle with retries","description":"ADR 008: Throttle with retries","sidebar":"tutorialSidebar"},"adrs/adr-009-soft-opt-out":{"id":"adrs/adr-009-soft-opt-out","title":"Soft Opt-Out","description":"ADR 009: Soft Opt-Out","sidebar":"tutorialSidebar"},"adrs/adr-010-standalone-changeover":{"id":"adrs/adr-010-standalone-changeover","title":"Standalone to Consumer Changeover","description":"ADR 010: Standalone to Consumer Changeover","sidebar":"tutorialSidebar"},"adrs/adr-011-improving-test-confidence":{"id":"adrs/adr-011-improving-test-confidence","title":"Improving testing and increasing confidence","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-012-separate-releasing":{"id":"adrs/adr-012-separate-releasing","title":"Separate Releasing","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-013-equivocation-slashing":{"id":"adrs/adr-013-equivocation-slashing","title":"Slashing on the provider for consumer equivocation","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/adr-template":{"id":"adrs/adr-template","title":"ADR Template","description":"Changelog","sidebar":"tutorialSidebar"},"adrs/intro":{"id":"adrs/intro","title":"ADRs","description":"This is a location to record all high-level architecture decisions in the Interchain Security project.","sidebar":"tutorialSidebar"},"consumer-development/app-integration":{"id":"consumer-development/app-integration","title":"Developing an ICS consumer chain","description":"When developing an ICS consumer chain, besides just focusing on your chain\'s logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol.","sidebar":"tutorialSidebar"},"consumer-development/changeover-procedure":{"id":"consumer-development/changeover-procedure","title":"Changeover Procedure","description":"Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.","sidebar":"tutorialSidebar"},"consumer-development/consumer-chain-governance":{"id":"consumer-development/consumer-chain-governance","title":"Consumer Chain Governance","description":"Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We\'ll cover what these are in the \\"Whitelist\\" section below.","sidebar":"tutorialSidebar"},"consumer-development/consumer-genesis-transformation":{"id":"consumer-development/consumer-genesis-transformation","title":"Consumer Genesis Transformation","description":"Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentaion on Onboarding and Changeover).","sidebar":"tutorialSidebar"},"consumer-development/offboarding":{"id":"consumer-development/offboarding","title":"Offboarding Checklist","description":"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).","sidebar":"tutorialSidebar"},"consumer-development/onboarding":{"id":"consumer-development/onboarding","title":"Onboarding Checklist","description":"The following checklists will aid in onboarding a new consumer chain to replicated security.","sidebar":"tutorialSidebar"},"features/key-assignment":{"id":"features/key-assignment","title":"Key Assignment","description":"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.","sidebar":"tutorialSidebar"},"features/proposals":{"id":"features/proposals","title":"ICS Provider Proposals","description":"Interchain security module introduces 3 new proposal types to the provider.","sidebar":"tutorialSidebar"},"features/reward-distribution":{"id":"features/reward-distribution","title":"Reward distribution","description":"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.","sidebar":"tutorialSidebar"},"features/slashing":{"id":"features/slashing","title":"Consumer Initiated Slashing","description":"A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain.","sidebar":"tutorialSidebar"},"frequently-asked-questions":{"id":"frequently-asked-questions","title":"Frequently Asked Questions","description":"What is the meaning of Validator Set Replication?","sidebar":"tutorialSidebar"},"index":{"id":"index","title":"Interchain Security Docs","description":"Welcome to the official Interchain Security module documentation for Cosmos-SDK based chains.","sidebar":"tutorialSidebar"},"introduction/overview":{"id":"introduction/overview","title":"Overview","description":"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.","sidebar":"tutorialSidebar"},"introduction/params":{"id":"introduction/params","title":"Interchain Security Parameters","description":"The parameters necessary for Interchain Security (ICS) are defined in","sidebar":"tutorialSidebar"},"introduction/technical-specification":{"id":"introduction/technical-specification","title":"Technical Specification","description":"For a technical deep dive into the replicated security protocol, see the specification.","sidebar":"tutorialSidebar"},"introduction/terminology":{"id":"introduction/terminology","title":"Terminology","description":"You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.","sidebar":"tutorialSidebar"},"validators/changeover-procedure":{"id":"validators/changeover-procedure","title":"Validator instructions for Changeover Procedure","description":"More details available in Changeover Procedure documentation.","sidebar":"tutorialSidebar"},"validators/joining-neutron":{"id":"validators/joining-neutron","title":"Joining Neutron","description":"Neutron is the first consumer chain to implement ICS.","sidebar":"tutorialSidebar"},"validators/joining-stride":{"id":"validators/joining-stride","title":"Joining Stride","description":"Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.","sidebar":"tutorialSidebar"},"validators/joining-testnet":{"id":"validators/joining-testnet","title":"Joining Replicated Security testnet","description":"Introduction","sidebar":"tutorialSidebar"},"validators/overview":{"id":"validators/overview","title":"Overview","description":"We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.","sidebar":"tutorialSidebar"},"validators/withdraw_rewards":{"id":"validators/withdraw_rewards","title":"Withdrawing consumer chain validator rewards","description":"Here are example steps for withdrawing rewards from consumer chains in the provider chain","sidebar":"tutorialSidebar"}}}')}}]); \ No newline at end of file diff --git a/legacy/assets/js/f8317958.137ca363.js b/legacy/assets/js/f8317958.137ca363.js new file mode 100644 index 0000000000..3d0967e68d --- /dev/null +++ b/legacy/assets/js/f8317958.137ca363.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8930],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>m});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?i(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,a,r=function(e,n){if(null==e)return{};var t,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=a.createContext({}),c=function(e){var n=a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=c(e.components);return a.createElement(l.Provider,{value:n},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},y=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=c(t),y=r,m=d["".concat(l,".").concat(y)]||d[y]||p[y]||i;return t?a.createElement(m,o(o({ref:n},u),{},{components:t})):a.createElement(m,o({ref:n},u))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,o=new Array(i);o[0]=y;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var c=2;c<i;c++)o[c]=t[c];return a.createElement.apply(null,o)}return a.createElement.apply(null,t)}y.displayName="MDXCreateElement"},971:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var a=t(7462),r=(t(7294),t(3905));const i={sidebar_position:1},o="Key Assignment",s={unversionedId:"features/key-assignment",id:"version-v2.4.0-lsm/features/key-assignment",title:"Key Assignment",description:"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.",source:"@site/versioned_docs/version-v2.4.0-lsm/features/key-assignment.md",sourceDirName:"features",slug:"/features/key-assignment",permalink:"/interchain-security/legacy/v2.4.0-lsm/features/key-assignment",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Technical Specification",permalink:"/interchain-security/legacy/v2.4.0-lsm/introduction/technical-specification"},next:{title:"Reward distribution",permalink:"/interchain-security/legacy/v2.4.0-lsm/features/reward-distribution"}},l={},c=[{value:"Rules",id:"rules",level:2},{value:"Adding a key",id:"adding-a-key",level:2},{value:"Changing a key",id:"changing-a-key",level:2},{value:"Removing a key",id:"removing-a-key",level:2}],u={toc:c},d="wrapper";function p(e){let{components:n,...t}=e;return(0,r.kt)(d,(0,a.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"key-assignment"},"Key Assignment"),(0,r.kt)("p",null,"Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate.\nThere are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains."),(0,r.kt)("p",null,"The feature is outlined in this ",(0,r.kt)("a",{parentName:"p",href:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-001-key-assignment"},"ADR-001")),(0,r.kt)("p",null,"By sending an ",(0,r.kt)("inlineCode",{parentName:"p"},"AssignConsumerKey")," transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity.")),(0,r.kt)("h2",{id:"rules"},"Rules"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"a key can be assigned before the consumer addition proposal passes on the provider"),(0,r.kt)("li",{parentName:"ul"},"validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider"),(0,r.kt)("li",{parentName:"ul"},"validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X"),(0,r.kt)("li",{parentName:"ul"},"a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Validators can use a different key for each consumer chain. ")),(0,r.kt)("h2",{id:"adding-a-key"},"Adding a key"),(0,r.kt)("p",null,"First, create a new node on the consumer chain using the equivalent:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"consumerd init <moniker>\n")),(0,r.kt)("p",null,"Then query your node for the consensus key."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}\n')),(0,r.kt)("p",null,"Then, make an ",(0,r.kt)("inlineCode",{parentName:"p"},"assign-consensus-key")," transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"gaiad tx provider assign-consensus-key <consumer-chain-id> '<pubkey>' --from <tx-signer> --home <home_dir> --gas 900000 -b block -y -o json\n")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"consumer-chain-id")," is the string identifier of the consumer chain, as assigned on the provider chain"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"consumer-pub-key")," has the following format ",(0,r.kt)("inlineCode",{parentName:"li"},'{"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}'))),(0,r.kt)("p",null,"Check that the key was assigned correcly by querying the provider:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad query provider validator-consumer-key <consumer-chain-id> cosmosvalcons1e....3xsj3ayzf4uv6\n")),(0,r.kt)("p",null,"You must use a ",(0,r.kt)("inlineCode",{parentName:"p"},"valcons")," address. You can obtain it by querying your node on the provider ",(0,r.kt)("inlineCode",{parentName:"p"},"gaiad tendermint show-address")),(0,r.kt)("p",null,"OR"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad query provider validator-provider-key <consumer-chain-id> consumervalcons1e....123asdnoaisdao\n")),(0,r.kt)("p",null,"You must use a ",(0,r.kt)("inlineCode",{parentName:"p"},"valcons")," address. You can obtain it by querying your node on the consumer ",(0,r.kt)("inlineCode",{parentName:"p"},"consumerd tendermint show-address")),(0,r.kt)("h2",{id:"changing-a-key"},"Changing a key"),(0,r.kt)("p",null,"To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied"),(0,r.kt)("h2",{id:"removing-a-key"},"Removing a key"),(0,r.kt)("p",null,"To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the ",(0,r.kt)("inlineCode",{parentName:"p"},"Adding a key")," section and using your provider consensus key."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/fbda1364.213bf4e3.js b/legacy/assets/js/fbda1364.213bf4e3.js new file mode 100644 index 0000000000..7603bcbae9 --- /dev/null +++ b/legacy/assets/js/fbda1364.213bf4e3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5868],{3905:(e,r,t)=>{t.d(r,{Zo:()=>l,kt:()=>h});var n=t(7294);function i(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function o(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function a(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?o(Object(t),!0).forEach((function(r){i(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function s(e,r){if(null==e)return{};var t,n,i=function(e,r){if(null==e)return{};var t,n,i={},o=Object.keys(e);for(n=0;n<o.length;n++)t=o[n],r.indexOf(t)>=0||(i[t]=e[t]);return i}(e,r);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)t=o[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var d=n.createContext({}),c=function(e){var r=n.useContext(d),t=r;return e&&(t="function"==typeof e?e(r):a(a({},r),e)),t},l=function(e){var r=c(e.components);return n.createElement(d.Provider,{value:r},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},m=n.forwardRef((function(e,r){var t=e.components,i=e.mdxType,o=e.originalType,d=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=c(t),m=i,h=u["".concat(d,".").concat(m)]||u[m]||p[m]||o;return t?n.createElement(h,a(a({ref:r},l),{},{components:t})):n.createElement(h,a({ref:r},l))}));function h(e,r){var t=arguments,i=r&&r.mdxType;if("string"==typeof e||i){var o=t.length,a=new Array(o);a[0]=m;var s={};for(var d in r)hasOwnProperty.call(r,d)&&(s[d]=r[d]);s.originalType=e,s[u]="string"==typeof e?e:i,a[1]=s;for(var c=2;c<o;c++)a[c]=t[c];return n.createElement.apply(null,a)}return n.createElement.apply(null,t)}m.displayName="MDXCreateElement"},7792:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>d,contentTitle:()=>a,default:()=>p,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var n=t(7462),i=(t(7294),t(3905));const o={sidebar_position:2},a="Reward distribution",s={unversionedId:"features/reward-distribution",id:"version-v3.1.0/features/reward-distribution",title:"Reward distribution",description:"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.",source:"@site/versioned_docs/version-v3.1.0/features/reward-distribution.md",sourceDirName:"features",slug:"/features/reward-distribution",permalink:"/interchain-security/legacy/v3.1.0/features/reward-distribution",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Key Assignment",permalink:"/interchain-security/legacy/v3.1.0/features/key-assignment"},next:{title:"ICS Provider Proposals",permalink:"/interchain-security/legacy/v3.1.0/features/proposals"}},d={},c=[{value:"Note",id:"note",level:2},{value:"Instructions for adding a denom",id:"instructions-for-adding-a-denom",level:3},{value:"Parameters",id:"parameters",level:2},{value:"<code>consumer_redistribution_fraction</code>",id:"consumer_redistribution_fraction",level:3},{value:"<code>blocks_per_distribution_transmission</code>",id:"blocks_per_distribution_transmission",level:3},{value:"<code>transfer_timeout_period</code>",id:"transfer_timeout_period",level:3},{value:"<code>distribution_transmission_channel</code>",id:"distribution_transmission_channel",level:3},{value:"<code>provider_fee_pool_addr_str</code>",id:"provider_fee_pool_addr_str",level:3}],l={toc:c},u="wrapper";function p(e){let{components:r,...t}=e;return(0,i.kt)(u,(0,n.Z)({},l,t,{components:r,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"reward-distribution"},"Reward distribution"),(0,i.kt)("p",null,"Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators.\nIn replicated security block rewards and fees are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel that gets created during consumer chain initialization."),(0,i.kt)("p",null,"Reward distribution on the provider is handled by the distribution module - validators and delegators receive a fraction of the consumer chain tokens as staking rewards.\nThe distributed reward tokens are IBC tokens and therefore cannot be staked on the provider chain."),(0,i.kt)("p",null,"Sending and distributing rewards from consumer chains to provider chain is handled by the ",(0,i.kt)("inlineCode",{parentName:"p"},"Reward Distribution")," sub-protocol."),(0,i.kt)("h2",{id:"note"},"Note"),(0,i.kt)("p",null,"The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerRewardsPool"),".\nThere is a new transaction type called ",(0,i.kt)("inlineCode",{parentName:"p"},"RegisterConsumerRewardDenom"),". This transaction allows consumer chains to register denoms to be used as consumer chain rewards on the provider.\nThe cost to register a denom is configurable (",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerRewardDenomRegistrationFee")," chain param) and the full amount of this fee is transferred to the community pool of the provider chain. Only denoms registered through this transaction are then transferred from the ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerRewardsPool")," to the ",(0,i.kt)("inlineCode",{parentName:"p"},"FeePoolAddress"),", to be distributed out to delegators and validators."),(0,i.kt)("h3",{id:"instructions-for-adding-a-denom"},"Instructions for adding a denom"),(0,i.kt)("p",null,"The transaction must be carried out on the provider chain. Please use the ",(0,i.kt)("inlineCode",{parentName:"p"},"ibc/*")," denom trace format."),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre"},"# reward denoms must be registered on the provider chain (gaia in this example)\ngaiad tx provider register-consumer-reward-denom ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9 --from mykey\n"))),(0,i.kt)("h2",{id:"parameters"},"Parameters"),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"The following chain parameters dictate consumer chain distribution amount and frequency.\nThey are set at consumer genesis and ",(0,i.kt)("inlineCode",{parentName:"p"},"blocks_per_distribution_transmission"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction"),"\n",(0,i.kt)("inlineCode",{parentName:"p"},"transfer_timeout_period")," must be provided in every ",(0,i.kt)("inlineCode",{parentName:"p"},"ConsumerChainAddition")," proposal.")),(0,i.kt)("h3",{id:"consumer_redistribution_fraction"},(0,i.kt)("inlineCode",{parentName:"h3"},"consumer_redistribution_fraction")),(0,i.kt)("p",null,'The fraction of tokens allocated to the consumer redistribution address during distribution events. The fraction is a string representing a decimal number. For example "0.75" would represent 75%.'),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"Example:"),(0,i.kt)("p",{parentName:"admonition"},"With ",(0,i.kt)("inlineCode",{parentName:"p"},"consumer_redistribution_fraction")," set to ",(0,i.kt)("inlineCode",{parentName:"p"},"0.75")," the consumer chain would send 75% of its block rewards and accumulated fees to the consumer redistribution address, and the remaining 25% to the provider chain every ",(0,i.kt)("inlineCode",{parentName:"p"},"n")," blocks where ",(0,i.kt)("inlineCode",{parentName:"p"},"n == blocks_per_distribution_transmission"),".")),(0,i.kt)("h3",{id:"blocks_per_distribution_transmission"},(0,i.kt)("inlineCode",{parentName:"h3"},"blocks_per_distribution_transmission")),(0,i.kt)("p",null,"The number of blocks between IBC token transfers from the consumer chain to the provider chain."),(0,i.kt)("h3",{id:"transfer_timeout_period"},(0,i.kt)("inlineCode",{parentName:"h3"},"transfer_timeout_period")),(0,i.kt)("p",null,"Timeout period for consumer chain reward distribution IBC packets."),(0,i.kt)("h3",{id:"distribution_transmission_channel"},(0,i.kt)("inlineCode",{parentName:"h3"},"distribution_transmission_channel")),(0,i.kt)("p",null,"Provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."),(0,i.kt)("h3",{id:"provider_fee_pool_addr_str"},(0,i.kt)("inlineCode",{parentName:"h3"},"provider_fee_pool_addr_str")),(0,i.kt)("p",null,"Provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/fc1c61d3.764fc729.js b/legacy/assets/js/fc1c61d3.764fc729.js new file mode 100644 index 0000000000..c43dd98fee --- /dev/null +++ b/legacy/assets/js/fc1c61d3.764fc729.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4150],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>h});var r=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function s(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?s(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):s(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function i(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},s=Object.keys(e);for(r=0;r<s.length;r++)t=s[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r<s.length;r++)t=s[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var d=r.createContext({}),l=function(e){var n=r.useContext(d),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=l(e.components);return r.createElement(d.Provider,{value:n},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,s=e.originalType,d=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),c=l(t),m=a,h=c["".concat(d,".").concat(m)]||c[m]||p[m]||s;return t?r.createElement(h,o(o({ref:n},u),{},{components:t})):r.createElement(h,o({ref:n},u))}));function h(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var s=t.length,o=new Array(s);o[0]=m;var i={};for(var d in n)hasOwnProperty.call(n,d)&&(i[d]=n[d]);i.originalType=e,i[c]="string"==typeof e?e:a,o[1]=i;for(var l=2;l<s;l++)o[l]=t[l];return r.createElement.apply(null,o)}return r.createElement.apply(null,t)}m.displayName="MDXCreateElement"},567:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>p,frontMatter:()=>s,metadata:()=>i,toc:()=>l});var r=t(7462),a=(t(7294),t(3905));const s={sidebar_position:3,title:"Key Assignment"},o="ADR 001: Key Assignment",i={unversionedId:"adrs/adr-001-key-assignment",id:"version-v2.4.0-lsm/adrs/adr-001-key-assignment",title:"Key Assignment",description:"Changelog",source:"@site/versioned_docs/version-v2.4.0-lsm/adrs/adr-001-key-assignment.md",sourceDirName:"adrs",slug:"/adrs/adr-001-key-assignment",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-001-key-assignment",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:3,frontMatter:{sidebar_position:3,title:"Key Assignment"},sidebar:"tutorialSidebar",previous:{title:"ADR Template",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-template"},next:{title:"Jail Throttling",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-002-throttle"}},d={},l=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Decision",id:"decision",level:2},{value:"State required",id:"state-required",level:3},{value:"Protocol overview",id:"protocol-overview",level:3},{value:"Consequences",id:"consequences",level:2},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"Neutral",id:"neutral",level:3},{value:"References",id:"references",level:2}],u={toc:l},c="wrapper";function p(e){let{components:n,...t}=e;return(0,a.kt)(c,(0,r.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-001-key-assignment"},"ADR 001: Key Assignment"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"2022-12-01: Initial Draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Accepted"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate."),(0,a.kt)("h2",{id:"decision"},"Decision"),(0,a.kt)("p",null,"It is possible to change the keys at any time by submitting a transaction (i.e., ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey"),")."),(0,a.kt)("h3",{id:"state-required"},"State required"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorConsumerPubKey")," - Stores the validator assigned keys for every consumer chain.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorByConsumerAddr")," - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"KeyAssignmentReplacements")," - Stores the key assignments that need to be replaced in the current block. Needed to apply the key assignments received in a block to the validator updates sent to the consumer chains.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"KeyAssignmentReplacementsBytePrefix | len(chainID) | chainID | providerConsAddress -> abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower},\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ConsumerAddrsToPrune")," - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ",(0,a.kt)("inlineCode",{parentName:"li"},"ValidatorByConsumerAddr"),". ")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses\n")),(0,a.kt)("h3",{id:"protocol-overview"},"Protocol overview"),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey(chainID, providerAddr, consumerKey)")," message:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"// get validator from staking module \nvalidator, found := stakingKeeper.GetValidator(providerAddr)\nif !found {\n return ErrNoValidatorFound\n}\nproviderConsAddr := validator.GetConsAddr()\n\n// make sure consumer key is not in use\nconsumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)\nif _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {\n return ErrInvalidConsumerConsensusPubKey\n}\n\n// check whether the consumer chain is already registered\n// i.e., a client to the consumer was already created\nif _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {\n // get the previous key assigned for this validator on this consumer chain\n oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)\n if found {\n // mark this old consumer key as prunable once the VSCMaturedPacket\n // for the current VSC ID is received\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n vscID := GetValidatorSetUpdateId()\n AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)\n } else {\n // the validator had no key assigned on this consumer chain\n oldConsumerKey := validator.TmConsPublicKey()\n }\n\n // check whether the validator is valid, i.e., its power is positive\n if currentPower := stakingKeeper.GetLastValidatorPower(providerAddr); currentPower > 0 {\n // to enable multiple calls of AssignConsumerKey in the same block by the same validator\n // the key assignment replacement should not be overwritten\n if _, found := GetKeyAssignmentReplacement(chainID, providerConsAddr); !found {\n // store old key and power for modifying the valset update in EndBlock\n oldKeyAssignment := abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower}\n SetKeyAssignmentReplacement(chainID, providerConsAddr, oldKeyAssignment)\n }\n }\n} else {\n // if the consumer chain is not registered, then remove the previous reverse mapping\n if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {\n oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)\n DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)\n }\n}\n\n\n// set the mapping from this validator's provider address to the new consumer key\nSetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)\n\n// set the reverse mapping: from this validator's new consensus address \n// on the consumer to its consensus address on the provider\nSetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)\n")),(0,a.kt)("p",null,"When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see ",(0,a.kt)("inlineCode",{parentName:"p"},"MakeConsumerGenesis"),"). "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {\n // ...\n // get initial valset from the staking module\n var updates []abci.ValidatorUpdate{}\n stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {\n validator := stakingKeeper.GetValidator(providerAddr)\n providerKey := validator.TmConsPublicKey()\n updates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})\n return false\n })\n\n // applies the key assignment to the initial validator\n for i, update := range updates {\n providerAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)\n if consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {\n updates[i].PubKey = consumerKey\n }\n }\n gen.InitialValSet = updates\n\n // get a hash of the consumer validator set from the update\n updatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)\n hash := tendermint.NewValidatorSet(updatesAsValSet).Hash()\n\n return gen, hash, nil\n}\n")),(0,a.kt)("p",null,"On ",(0,a.kt)("inlineCode",{parentName:"p"},"EndBlock")," while queueing ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCPacket"),"s to send to registered consumer chains:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func QueueVSCPackets() {\n valUpdateID := GetValidatorSetUpdateId()\n // get the validator updates from the staking module\n valUpdates := stakingKeeper.GetValidatorUpdates()\n\n IterateConsumerChains(func(chainID, clientID string) (stop bool) {\n // apply the key assignment to the validator updates\n valUpdates := ApplyKeyAssignmentToValUpdates(chainID, valUpdates)\n // ..\n })\n // ...\n}\n\nfunc ApplyKeyAssignmentToValUpdates(\n chainID string, \n valUpdates []abci.ValidatorUpdate,\n) (newUpdates []abci.ValidatorUpdate) {\n for _, valUpdate := range valUpdates {\n providerAddr := utils.TMCryptoPublicKeyToConsAddr(valUpdate.PubKey)\n\n // if a key assignment replacement is found, then\n // remove the valupdate with the old consumer key\n // and create two new valupdates\n prevConsumerKey, _, found := GetKeyAssignmentReplacement(chainID, providerAddr)\n if found {\n // set the old consumer key's power to 0\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: prevConsumerKey,\n Power: 0,\n })\n // set the new consumer key's power to the power in the update\n newConsumerKey := GetValidatorConsumerPubKey(chainID, providerAddr)\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: newConsumerKey,\n Power: valUpdate.Power,\n })\n // delete key assignment replacement\n DeleteKeyAssignmentReplacement(chainID, providerAddr)\n } else {\n // there is no key assignment replacement;\n // check if the validator's key is assigned\n consumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr)\n if found {\n // replace the update containing the provider key \n // with an update containing the consumer key\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: consumerKey,\n Power: valUpdate.Power,\n })\n } else {\n // keep the same update\n newUpdates = append(newUpdates, valUpdate)\n }\n }\n }\n\n // iterate over the remaining key assignment replacements\n IterateKeyAssignmentReplacements(chainID, func(\n pAddr sdk.ConsAddress,\n prevCKey tmprotocrypto.PublicKey,\n power int64,\n ) (stop bool) {\n // set the old consumer key's power to 0\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: prevCKey,\n Power: 0,\n })\n // set the new consumer key's power to the power in key assignment replacement\n newConsumerKey := GetValidatorConsumerPubKey(chainID, pAddr)\n newUpdates = append(newUpdates, abci.ValidatorUpdate{\n PubKey: newConsumerKey,\n Power: power,\n })\n return false\n })\n\n // remove all the key assignment replacements\n \n return newUpdates\n}\n")),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"SlashPacket")," from a consumer chain with id ",(0,a.kt)("inlineCode",{parentName:"p"},"chainID")," for a infraction of a validator ",(0,a.kt)("inlineCode",{parentName:"p"},"data.Validator"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {\n // ...\n // the slash packet validator address may be known only on the consumer chain;\n // in this case, it must be mapped back to the consensus address on the provider chain\n consumerAddr := sdk.ConsAddress(data.Validator.Address)\n providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)\n if !found {\n // the validator has the same key on the consumer as on the provider\n providerAddr = consumer\n }\n // ...\n}\n")),(0,a.kt)("p",null,"On receiving a ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCMatured"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {\n // ...\n // prune previous consumer validator address that are no longer needed\n consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n for _, addr := range consumerAddrs {\n DeleteValidatorByConsumerAddr(chainID, addr)\n }\n DeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)\n // ...\n}\n")),(0,a.kt)("p",null,"On stopping a consumer chain:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-golang"},"func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {\n // ...\n // deletes all the state needed for key assignments on this consumer chain\n // ...\n}\n")),(0,a.kt)("h2",{id:"consequences"},"Consequences"),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Validators can use different consensus keys on the consumer chains.")),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"None")),(0,a.kt)("h3",{id:"neutral"},"Neutral"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"The consensus state necessary to create a client to the consumer chain must use the hash returned by the ",(0,a.kt)("inlineCode",{parentName:"li"},"MakeConsumerGenesis")," method as the ",(0,a.kt)("inlineCode",{parentName:"li"},"nextValsHash"),"."),(0,a.kt)("li",{parentName:"ul"},"The consumer chain can no longer check the initial validator set against the consensus state on ",(0,a.kt)("inlineCode",{parentName:"li"},"InitGenesis"),".")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/26"},"Key assignment issue"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/fcd25e9d.359f4087.js b/legacy/assets/js/fcd25e9d.359f4087.js new file mode 100644 index 0000000000..1efbfc8e7d --- /dev/null +++ b/legacy/assets/js/fcd25e9d.359f4087.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9474],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),m=l(n),d=o,f=m["".concat(c,".").concat(d)]||m[d]||u[d]||i;return n?r.createElement(f,a(a({ref:t},p),{},{components:n})):r.createElement(f,a({ref:t},p))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[m]="string"==typeof e?e:o,a[1]=s;for(var l=2;l<i;l++)a[l]=n[l];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},419:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var r=n(7462),o=(n(7294),n(3905));const i={sidebar_position:4,title:"Offboarding Checklist"},a="Consumer Offboarding",s={unversionedId:"consumer-development/offboarding",id:"version-v3.3.1-lsm/consumer-development/offboarding",title:"Offboarding Checklist",description:"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).",source:"@site/versioned_docs/version-v3.3.1-lsm/consumer-development/offboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/offboarding",permalink:"/interchain-security/legacy/consumer-development/offboarding",draft:!1,tags:[],version:"v3.3.1-lsm",sidebarPosition:4,frontMatter:{sidebar_position:4,title:"Offboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Onboarding Checklist",permalink:"/interchain-security/legacy/consumer-development/onboarding"},next:{title:"Changeover Procedure",permalink:"/interchain-security/legacy/consumer-development/changeover-procedure"}},c={},l=[],p={toc:l},m="wrapper";function u(e){let{components:t,...n}=e;return(0,o.kt)(m,(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-offboarding"},"Consumer Offboarding"),(0,o.kt)("p",null,"To offboard a consumer chain simply submit a ",(0,o.kt)("inlineCode",{parentName:"p"},"ConsumerRemovalProposal")," governance proposal listing a ",(0,o.kt)("inlineCode",{parentName:"p"},"stop_time"),". After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates)."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.\n// If it passes, all the consumer chain\'s state is removed from the provider chain. The outstanding unbonding\n// operation funds are released.\n{\n // the title of the proposal\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n}\n')),(0,o.kt)("p",null,"More information will be listed in a future version of this document."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/fe5d7ad2.9e3601c3.js b/legacy/assets/js/fe5d7ad2.9e3601c3.js new file mode 100644 index 0000000000..66bcafdfa4 --- /dev/null +++ b/legacy/assets/js/fe5d7ad2.9e3601c3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5863],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>v});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,r=function(e,t){if(null==e)return{};var n,o,r={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=o.createContext({}),l=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},d=function(e){var t=l(e.components);return o.createElement(c.Provider,{value:t},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,v=u["".concat(c,".").concat(h)]||u[h]||p[h]||i;return n?o.createElement(v,a(a({ref:t},d),{},{components:n})):o.createElement(v,a({ref:t},d))}));function v(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:r,a[1]=s;for(var l=2;l<i;l++)a[l]=n[l];return o.createElement.apply(null,a)}return o.createElement.apply(null,n)}h.displayName="MDXCreateElement"},8636:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var o=n(7462),r=(n(7294),n(3905));const i={sidebar_position:1},a="Overview",s={unversionedId:"introduction/overview",id:"version-v2.0.0/introduction/overview",title:"Overview",description:"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.",source:"@site/versioned_docs/version-v2.0.0/introduction/overview.md",sourceDirName:"introduction",slug:"/introduction/overview",permalink:"/interchain-security/legacy/v2.0.0/introduction/overview",draft:!1,tags:[],version:"v2.0.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Docs",permalink:"/interchain-security/legacy/v2.0.0/"},next:{title:"Terminology",permalink:"/interchain-security/legacy/v2.0.0/introduction/terminology"}},c={},l=[{value:"Why Replicated Security?",id:"why-replicated-security",level:2},{value:"Core protocol",id:"core-protocol",level:2},{value:"Downtime Slashing",id:"downtime-slashing",level:3},{value:"Equivocation (Double Sign) Slashing",id:"equivocation-double-sign-slashing",level:3},{value:"Tokenomics and Rewards",id:"tokenomics-and-rewards",level:3}],d={toc:l},u="wrapper";function p(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"overview"},"Overview"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another."),(0,r.kt)("br",null),'Replicated security allows anyone to launch a "consumer" blockchain using the same validator set as the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit the full security and decentralization of the provider.'),(0,r.kt)("h2",{id:"why-replicated-security"},"Why Replicated Security?"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Full provider security. At launch, consumer chains are secured by the full validator set and market cap of the provider chain."),(0,r.kt)("li",{parentName:"ul"},"Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum."),(0,r.kt)("li",{parentName:"ul"},"Projects keep majority of gas fees. Depending on configuration, these fees either go to the project\u2019s community DAO, or can be used in the protocol in other ways."),(0,r.kt)("li",{parentName:"ul"},"No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. A governance vote will take place for a chain to get adopted by the provider validators which will encourage participation and signal strong buy-in into the project's long-term success."),(0,r.kt)("li",{parentName:"ul"},"Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set.")),(0,r.kt)("h2",{id:"core-protocol"},"Core protocol"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Protocol specification is available as ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md"},"ICS-028")," in the IBC repository.")),(0,r.kt)("p",null,"Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer."),(0,r.kt)("p",null,"To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider."),(0,r.kt)("h3",{id:"downtime-slashing"},"Downtime Slashing"),(0,r.kt)("p",null,"If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period."),(0,r.kt)("h3",{id:"equivocation-double-sign-slashing"},"Equivocation (Double Sign) Slashing"),(0,r.kt)("p",null,"Evidence of equivocation must be submitted to provider governance and be voted on. This behavior is an extra safeguard before a validator is slashed, and may be replaced by a more automated system in the future."),(0,r.kt)("h3",{id:"tokenomics-and-rewards"},"Tokenomics and Rewards"),(0,r.kt)("p",null,"Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/fee5bc5e.c989bfaf.js b/legacy/assets/js/fee5bc5e.c989bfaf.js new file mode 100644 index 0000000000..ca8c09905a --- /dev/null +++ b/legacy/assets/js/fee5bc5e.c989bfaf.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[8661],{3905:(e,r,t)=>{t.d(r,{Zo:()=>c,kt:()=>w});var a=t(7294);function n(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);r&&(a=a.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?i(Object(t),!0).forEach((function(r){n(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function s(e,r){if(null==e)return{};var t,a,n=function(e,r){if(null==e)return{};var t,a,n={},i=Object.keys(e);for(a=0;a<i.length;a++)t=i[a],r.indexOf(t)>=0||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)t=i[a],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(n[t]=e[t])}return n}var l=a.createContext({}),d=function(e){var r=a.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):o(o({},r),e)),t},c=function(e){var r=d(e.components);return a.createElement(l.Provider,{value:r},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var r=e.children;return a.createElement(a.Fragment,{},r)}},u=a.forwardRef((function(e,r){var t=e.components,n=e.mdxType,i=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=d(t),u=n,w=p["".concat(l,".").concat(u)]||p[u]||m[u]||i;return t?a.createElement(w,o(o({ref:r},c),{},{components:t})):a.createElement(w,o({ref:r},c))}));function w(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var i=t.length,o=new Array(i);o[0]=u;var s={};for(var l in r)hasOwnProperty.call(r,l)&&(s[l]=r[l]);s.originalType=e,s[p]="string"==typeof e?e:n,o[1]=s;for(var d=2;d<i;d++)o[d]=t[d];return a.createElement.apply(null,o)}return a.createElement.apply(null,t)}u.displayName="MDXCreateElement"},3773:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>l,contentTitle:()=>o,default:()=>m,frontMatter:()=>i,metadata:()=>s,toc:()=>d});var a=t(7462),n=(t(7294),t(3905));const i={sidebar_position:3},o="Withdrawing consumer chain validator rewards",s={unversionedId:"validators/withdraw_rewards",id:"version-v3.3.0/validators/withdraw_rewards",title:"Withdrawing consumer chain validator rewards",description:"Here are example steps for withdrawing rewards from consumer chains in the provider chain",source:"@site/versioned_docs/version-v3.3.0/validators/withdraw_rewards.md",sourceDirName:"validators",slug:"/validators/withdraw_rewards",permalink:"/interchain-security/legacy/v3.3.0/validators/withdraw_rewards",draft:!1,tags:[],version:"v3.3.0",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Joining Replicated Security testnet",permalink:"/interchain-security/legacy/v3.3.0/validators/joining-testnet"},next:{title:"Validator instructions for Changeover Procedure",permalink:"/interchain-security/legacy/v3.3.0/validators/changeover-procedure"}},l={},d=[{value:"Querying validator rewards",id:"querying-validator-rewards",level:2},{value:"Withdrawing rewards and commission",id:"withdrawing-rewards-and-commission",level:2},{value:"1. Withdraw rewards",id:"1-withdraw-rewards",level:3},{value:"2. Confirm withdrawal",id:"2-confirm-withdrawal",level:3}],c={toc:d},p="wrapper";function m(e){let{components:r,...t}=e;return(0,n.kt)(p,(0,a.Z)({},c,t,{components:r,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"withdrawing-consumer-chain-validator-rewards"},"Withdrawing consumer chain validator rewards"),(0,n.kt)("p",null,"Here are example steps for withdrawing rewards from consumer chains in the provider chain"),(0,n.kt)("admonition",{type:"info"},(0,n.kt)("p",{parentName:"admonition"},"The examples used are from ",(0,n.kt)("inlineCode",{parentName:"p"},"rs-testnet"),", the replicated security persistent testnet."),(0,n.kt)("p",{parentName:"admonition"},"Validator operator address: ",(0,n.kt)("inlineCode",{parentName:"p"},"cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6"),"\nSelf-delegation address: ",(0,n.kt)("inlineCode",{parentName:"p"},"cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf"))),(0,n.kt)("p",null,"Prior to withdrawing rewards, query balances for self-delegation address:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "1000000000000"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n')),(0,n.kt)("h2",{id:"querying-validator-rewards"},"Querying validator rewards"),(0,n.kt)("p",null,"Query rewards for the validator address:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6\n\nrewards:\n- amount: "158.069895000000000000"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "841842390516.072526500000000000"\n denom: uatom\n')),(0,n.kt)("p",null,"The ",(0,n.kt)("inlineCode",{parentName:"p"},"ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD")," denom represents rewards from a consumer chain."),(0,n.kt)("h2",{id:"withdrawing-rewards-and-commission"},"Withdrawing rewards and commission"),(0,n.kt)("h3",{id:"1-withdraw-rewards"},"1. Withdraw rewards"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y\n\ntxhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A\n")),(0,n.kt)("h3",{id:"2-confirm-withdrawal"},"2. Confirm withdrawal"),(0,n.kt)("p",null,"After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},'gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf\n\nbalances:\n- amount: "216"\n denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD\n- amount: "2233766225342"\n denom: uatom\npagination:\n next_key: null\n total: "0"\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/ff39e481.477a6c6b.js b/legacy/assets/js/ff39e481.477a6c6b.js new file mode 100644 index 0000000000..c5d468cc92 --- /dev/null +++ b/legacy/assets/js/ff39e481.477a6c6b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[6181],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),m=c(n),d=o,f=m["".concat(l,".").concat(d)]||m[d]||u[d]||i;return n?r.createElement(f,a(a({ref:t},p),{},{components:n})):r.createElement(f,a({ref:t},p))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[m]="string"==typeof e?e:o,a[1]=s;for(var c=2;c<i;c++)a[c]=n[c];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},6659:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var r=n(7462),o=(n(7294),n(3905));const i={sidebar_position:5,title:"Offboarding Checklist"},a="Consumer Offboarding",s={unversionedId:"consumer-development/offboarding",id:"version-v2.4.0-lsm/consumer-development/offboarding",title:"Offboarding Checklist",description:"To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).",source:"@site/versioned_docs/version-v2.4.0-lsm/consumer-development/offboarding.md",sourceDirName:"consumer-development",slug:"/consumer-development/offboarding",permalink:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/offboarding",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:5,frontMatter:{sidebar_position:5,title:"Offboarding Checklist"},sidebar:"tutorialSidebar",previous:{title:"Onboarding Checklist",permalink:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/onboarding"},next:{title:"Overview",permalink:"/interchain-security/legacy/v2.4.0-lsm/validators/overview"}},l={},c=[],p={toc:c},m="wrapper";function u(e){let{components:t,...n}=e;return(0,o.kt)(m,(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"consumer-offboarding"},"Consumer Offboarding"),(0,o.kt)("p",null,"To offboard a consumer chain simply submit a ",(0,o.kt)("inlineCode",{parentName:"p"},"ConsumerRemovalProposal")," governance proposal listing a ",(0,o.kt)("inlineCode",{parentName:"p"},"stop_time"),". After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates)."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.\n// If it passes, all the consumer chain\'s state is removed from the provider chain. The outstanding unbonding\n// operation funds are released.\n{\n // the title of the proposal\n "title": "This was a great chain",\n "description": "Here is a .md formatted string specifying removal details",\n // the chain-id of the consumer chain to be stopped\n "chain_id": "consumerchain-1",\n // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node\n "stop_time": "2023-03-07T12:40:00.000000Z",\n}\n')),(0,o.kt)("p",null,"More information will be listed in a future version of this document."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/ff887390.dc7e3908.js b/legacy/assets/js/ff887390.dc7e3908.js new file mode 100644 index 0000000000..5df48c8625 --- /dev/null +++ b/legacy/assets/js/ff887390.dc7e3908.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[146],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),h=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=h(e.components);return o.createElement(l.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),c=h(n),u=a,m=c["".concat(l,".").concat(u)]||c[u]||p[u]||i;return n?o.createElement(m,r(r({ref:t},d),{},{components:n})):o.createElement(m,r({ref:t},d))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,r=new Array(i);r[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:a,r[1]=s;for(var h=2;h<i;h++)r[h]=n[h];return o.createElement.apply(null,r)}return o.createElement.apply(null,n)}u.displayName="MDXCreateElement"},3160:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>h});var o=n(7462),a=(n(7294),n(3905));const i={sidebar_position:14,title:"Slashing on the provider for consumer equivocation"},r="ADR 013: Slashing on the provider for consumer equivocation",s={unversionedId:"adrs/adr-013-equivocation-slashing",id:"version-v2.4.0-lsm/adrs/adr-013-equivocation-slashing",title:"Slashing on the provider for consumer equivocation",description:"Changelog",source:"@site/versioned_docs/version-v2.4.0-lsm/adrs/adr-013-equivocation-slashing.md",sourceDirName:"adrs",slug:"/adrs/adr-013-equivocation-slashing",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-013-equivocation-slashing",draft:!1,tags:[],version:"v2.4.0-lsm",sidebarPosition:14,frontMatter:{sidebar_position:14,title:"Slashing on the provider for consumer equivocation"},sidebar:"tutorialSidebar",previous:{title:"Cryptographic verification of equivocation evidence",permalink:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verification"}},l={},h=[{value:"Changelog",id:"changelog",level:2},{value:"Status",id:"status",level:2},{value:"Context",id:"context",level:2},{value:"Single-chain slashing",id:"single-chain-slashing",level:3},{value:"Slashing undelegations and redelegations",id:"slashing-undelegations-and-redelegations",level:4},{value:"Slashing delegations",id:"slashing-delegations",level:4},{value:"Old evidence",id:"old-evidence",level:4},{value:"Slashing for equivocation on the consumer",id:"slashing-for-equivocation-on-the-consumer",level:3},{value:"Proposed solution",id:"proposed-solution",level:2},{value:"Implementation",id:"implementation",level:3},{value:"Positive",id:"positive",level:3},{value:"Negative",id:"negative",level:3},{value:"References",id:"references",level:2}],d={toc:h},c="wrapper";function p(e){let{components:t,...n}=e;return(0,a.kt)(c,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"adr-013-slashing-on-the-provider-for-consumer-equivocation"},"ADR 013: Slashing on the provider for consumer equivocation"),(0,a.kt)("h2",{id:"changelog"},"Changelog"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"1st Sept. 2023: Initial draft")),(0,a.kt)("h2",{id:"status"},"Status"),(0,a.kt)("p",null,"Proposed"),(0,a.kt)("h2",{id:"context"},"Context"),(0,a.kt)("p",null,"This ADR presents some approaches on how to slash on the provider chain validators that performed equivocations on consumer chains.\nCurrently, the provider chain can ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232"},"receive and verify evidence of equivocation"),", but it cannot slash the misbehaving validator."),(0,a.kt)("p",null,"In the remainder of this section, we explain how slashing is performed on a single chain and show why slashing on the provider for equivocation on the consumer is challenging."),(0,a.kt)("p",null,"Note that future versions of the Cosmos SDK, CometBFT, and ibc-go could modify the way we slash, etc. Therefore, a future reader of this ADR, should note that when we refer to Cosmos SDK, CometBFT, and ibc-go we specifically refer to their ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/intro/overview"},"v0.47"),", ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cometbft.com/v0.37/"},"v0.37")," and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/v7.3.0"},"v7.3.0")," versions respectively."),(0,a.kt)("h3",{id:"single-chain-slashing"},"Single-chain slashing"),(0,a.kt)("p",null,"Slashing is implemented across the ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/slashing"},"slashing"),"\nand ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/staking"},"staking")," modules.\nThe slashing module's keeper calls the staking module's ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash()")," method, passing among others, the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," (i.e., the height when the equivocation occurred), the validator's ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," at the infraction height, and the ",(0,a.kt)("inlineCode",{parentName:"p"},"slashFactor")," (currently set to ",(0,a.kt)("inlineCode",{parentName:"p"},"5%")," in case of equivocation on the Cosmos Hub)."),(0,a.kt)("h4",{id:"slashing-undelegations-and-redelegations"},"Slashing undelegations and redelegations"),(0,a.kt)("p",null,"To slash undelegations, ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash")," goes through all undelegations and checks whether they started before or after the infraction occurred. If an undelegation started before the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight"),", then it is ",(0,a.kt)("strong",{parentName:"p"},"not")," slashed, otherwise it is slashed by ",(0,a.kt)("inlineCode",{parentName:"p"},"slashFactor"),"."),(0,a.kt)("p",null,"The slashing of redelegations happens in a similar way, meaning that ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash")," goes through all redelegations and checks whether the redelegations started before or after the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight"),"."),(0,a.kt)("h4",{id:"slashing-delegations"},"Slashing delegations"),(0,a.kt)("p",null,"Besides undelegations and redelegations, the validator's delegations need to also be slashed.\nThis is performed by deducting the appropriate amount of tokens from the validator. Note that this deduction is computed based on the voting ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," the misbehaving validator had at the height of the equivocation. As a result of the tokens deduction,\nthe ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/staking#delegator-shares"},"tokens per share"),"\nreduce and hence later on, when delegators undelegate or redelegate, the delegators retrieve back less\ntokens, effectively having their tokens slashed. The rationale behind this slashing mechanism, as mentioned in the ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cosmos.network/v0.47/modules/staking#delegator-shares"},"Cosmos SDK documentation")," "),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"[...]"," is to simplify the accounting around slashing. Rather than iteratively slashing the tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, effectively reducing the value of each issued delegator share.")),(0,a.kt)("p",null,"This approach of slashing delegations does not utilize the\n",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," in any way and hence the following scenario could occur:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"a validator ",(0,a.kt)("inlineCode",{parentName:"li"},"V")," performs an equivocation at a height ",(0,a.kt)("inlineCode",{parentName:"li"},"Hi")),(0,a.kt)("li",{parentName:"ol"},"a new delegator ",(0,a.kt)("inlineCode",{parentName:"li"},"D")," delegates to ",(0,a.kt)("inlineCode",{parentName:"li"},"V")," after height ",(0,a.kt)("inlineCode",{parentName:"li"},"Hi")),(0,a.kt)("li",{parentName:"ol"},"evidence of the equivocation by validator ",(0,a.kt)("inlineCode",{parentName:"li"},"V")," is received"),(0,a.kt)("li",{parentName:"ol"},"the tokens of delegator ",(0,a.kt)("inlineCode",{parentName:"li"},"D")," are slashed")),(0,a.kt)("p",null,"In the above scenario, delegator ",(0,a.kt)("inlineCode",{parentName:"p"},"D")," is slashed, even though ",(0,a.kt)("inlineCode",{parentName:"p"},"D"),"'s voting power did not contribute to the infraction. "),(0,a.kt)("h4",{id:"old-evidence"},"Old evidence"),(0,a.kt)("p",null,"In the single-chain case, old evidence (e.g., from 3 years ago) is ignored. This is achieved through\n",(0,a.kt)("a",{parentName:"p",href:"https://docs.cometbft.com/v0.37/spec/consensus/evidence"},"CometBFT")," that ignores old evidence based on the parameters ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeNumBlocks")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeDuration")," (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.37.0/evidence/pool.go#271"},"here"),").\nAdditionally, note that when the evidence is sent by CometBFT to the application, the evidence is rechecked in the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L54"},"evidence module")," of Cosmos SDK and if it is old, the evidence is ignored.\nIn Cosmos Hub, the ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeNumBlocks")," is set to 1000000 (i.e., ~70 days if we assume we need ~6 sec per block) and ",(0,a.kt)("inlineCode",{parentName:"p"},"MaxAgeDuration")," is set to 172800000000000 ns (i.e., 2 days). Because of this check, we can easily exclude old evidence."),(0,a.kt)("h3",{id:"slashing-for-equivocation-on-the-consumer"},"Slashing for equivocation on the consumer"),(0,a.kt)("p",null,"In the single-chain case, slashing requires both the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and the voting ",(0,a.kt)("inlineCode",{parentName:"p"},"power"),".\nIn order to slash on the provider for an equivocation on a consumer, we need to have both the provider's ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and voting ",(0,a.kt)("inlineCode",{parentName:"p"},"power"),".\nNote that the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," on the consumer chain must be mapped to a height on the provider chain.\nUnless we have a way to find the corresponding ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," on the provider chain, we cannot slash for equivocation on the consumer in the same way as we would slash in the single-chain case."),(0,a.kt)("p",null,"The challenge of figuring out the corresponding ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"power")," values on the provider chain is due to the following trust assumption:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"We trust the consensus layer and validator set of the consumer chains, ",(0,a.kt)("em",{parentName:"li"},"but we do not trust the application layer"),".")),(0,a.kt)("p",null,"As a result, we cannot trust anything that stems from the ",(0,a.kt)("em",{parentName:"p"},"application state")," of a consumer chain."),(0,a.kt)("p",null,"Note that when a relayer or a user sends evidence through a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232"},"MsgSubmitConsumerDoubleVoting")," message, the provider gets access to ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cometbft/cometbft/blob/v0.37.0/types/evidence.go#L35"},"DuplicateVoteEvidence"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-protobuf"},'type DuplicateVoteEvidence struct {\n VoteA *Vote `json:"vote_a"`\n VoteB *Vote `json:"vote_b"`\n\n // abci specific information\n TotalVotingPower int64\n ValidatorPower int64\n Timestamp time.Time\n}\n')),(0,a.kt)("p",null,'The "abci specific information" fields cannot be trusted because they are not signed. Therefore,\nwe can use neither ',(0,a.kt)("inlineCode",{parentName:"p"},"ValidatorPower")," for slashing on the provider chain, nor the ",(0,a.kt)("inlineCode",{parentName:"p"},"Timestamp")," to check the evidence age. We can get the ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," from the votes, but this ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," corresponds to the infraction height on the consumer and ",(0,a.kt)("strong",{parentName:"p"},"not")," on the provider chain.\nSimilarly, when a relayer or a user sends evidence through a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/826"},"MsgSubmitConsumerMisbehaviour")," message, the provider gets access to ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc-go/blob/v7.3.0/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79"},"Misbehaviour")," that we cannot use to extract the infraction height, power, or the time on the provider chain."),(0,a.kt)("h2",{id:"proposed-solution"},"Proposed solution"),(0,a.kt)("p",null,"As a first iteration, we propose the following approach. At the moment the provider receives evidence of equivocation on a consumer:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"slash all the undelegations and redelegations using ",(0,a.kt)("inlineCode",{parentName:"li"},"slashFactor"),";"),(0,a.kt)("li",{parentName:"ol"},"slash all delegations using as voting ",(0,a.kt)("inlineCode",{parentName:"li"},"power")," the sum of the voting power of the misbehaving validator and the power of all the ongoing undelegations and redelegations.")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Evidence expiration:")," Additionally, because we cannot infer the actual time of the evidence (i.e., the timestamp of the evidence cannot be trusted), we do not consider ",(0,a.kt)("em",{parentName:"p"},"evidence expiration")," and hence old evidence is never ignored (e.g., the provider would act on 3 year-old evidence of equivocation on a consumer).\nAdditionally, we do not need to store equivocation evidence to avoid slashing a validator more than once, because we ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L94"},"do not slash")," tombstoned validators and we ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L138"},"tombstone")," a validator when slashed."),(0,a.kt)("p",null,"We do not act on evidence that was signed by a validator ",(0,a.kt)("a",{parentName:"p",href:"https://tutorials.cosmos.network/tutorials/9-path-to-prod/3-keys.html#what-validator-keys"},"consensus key")," that is ",(0,a.kt)("em",{parentName:"p"},"pruned")," when we receive the evidence. We prune a validator's consensus key if the validator has assigned a new consumer key (using ",(0,a.kt)("inlineCode",{parentName:"p"},"MsgAssignConsumerKey"),") and an unbonding period on the consumer chain has elapsed (see ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-001-key-assignment.md"},"key assignment ADR"),"). Note that the provider chain is informed that the unbonding period has elapsed on the consumer when the provider receives a ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCMaturedPacket")," and because of this, if the consumer delays the sending of a ",(0,a.kt)("inlineCode",{parentName:"p"},"VSCMaturedPacket"),", we would delay the pruning of the key as well."),(0,a.kt)("h3",{id:"implementation"},"Implementation"),(0,a.kt)("p",null,"The following logic needs to be added to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/1232"},"HandleConsumerDoubleVoting")," and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/interchain-security/pull/826"},"HandleConsumerMisbehaviour")," methods:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-go"},"undelegationsInTokens := sdk.NewInt(0)\nfor _, v := range k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validatorAddress) {\n for _, entry := range v.Entries {\n if entry.IsMature(now) && !entry.OnHold() {\n // undelegation no longer eligible for slashing, skip it\n continue\n }\n undelegationsInTokens = undelegationsInTokens.Add(entry.InitialBalance)\n }\n}\n\nredelegationsInTokens := sdk.NewInt(0)\nfor _, v := range k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validatorAddress) {\n for _, entry := range v.Entries {\n if entry.IsMature(now) && !entry.OnHold() {\n // redelegation no longer eligible for slashing, skip it\n continue\n }\n redelegationsInTokens = redelegationsInTokens.Add(entry.InitialBalance)\n }\n}\n\ninfractionHeight := 0\nundelegationsAndRedelegationsInPower = sdk.TokensToConsensusPower(undelegationsInTokens.Add(redelegationsInTokens))\ntotalPower := validator's voting power + undelegationsAndRedelegationsInPower\nslashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)\n\nk.stakingKeeper.Slash(ctx, validatorConsAddress, infractionHeight, totalPower, slashFraction, DoubleSign)\n")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Infraction height:")," We provide a zero ",(0,a.kt)("inlineCode",{parentName:"p"},"infractionHeight")," to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L33"},"Slash")," method in order to slash all ongoing undelegations and redelegations (see checks in ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L92"},"Slash"),", ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L195"},"SlashUnbondingDelegation"),", and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L249"},"SlashRedelegation"),")."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Power:")," We pass the sum of the voting power of the misbehaving validator when the evidence was received (i.e., at evidence height) and the power of all the ongoing undelegations and redelegations.\nIf we assume that the ",(0,a.kt)("inlineCode",{parentName:"p"},"slashFactor")," is ",(0,a.kt)("inlineCode",{parentName:"p"},"5%"),", then the voting power we pass is ",(0,a.kt)("inlineCode",{parentName:"p"},"power + totalPower(undelegations) + totalPower(redelegations)"),".\nHence, when the ",(0,a.kt)("inlineCode",{parentName:"p"},"Slash")," method slashes all the undelegations and redelegations it would end up with ",(0,a.kt)("inlineCode",{parentName:"p"},"0.05 * power + 0.05 * totalPower(undelegations) + 0.05 * totalPower(redelegations) - 0.05 * totalPower(undelegations) - 0.05 * totalPower(redelegations) = 0.05 * power")," and hence it would slash ",(0,a.kt)("inlineCode",{parentName:"p"},"5%")," of the validator's power when the evidence is received."),(0,a.kt)("h3",{id:"positive"},"Positive"),(0,a.kt)("p",null,"With the proposed approach we can quickly implement slashing functionality on the provider chain for consumer chain equivocations.\nThis approach does not need to change the staking module and therefore does not change in any way how slashing is performed today for a single chain."),(0,a.kt)("h3",{id:"negative"},"Negative"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"We ",(0,a.kt)("em",{parentName:"li"},"definitely")," slash more when it comes to undelegations and redelegations because we slash for all of them without considering an ",(0,a.kt)("inlineCode",{parentName:"li"},"infractionHeight"),"."),(0,a.kt)("li",{parentName:"ul"},"We ",(0,a.kt)("em",{parentName:"li"},"potentially")," slash more than what we would have slashed if we knew the voting ",(0,a.kt)("inlineCode",{parentName:"li"},"power")," at the corresponding ",(0,a.kt)("inlineCode",{parentName:"li"},"infractionHeight")," in the provider chain."),(0,a.kt)("li",{parentName:"ul"},"We slash on old evidence of equivocation on a consumer.")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md"},"ADR 005: Cryptographic verification of equivocation evidence")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/cosmos/interchain-security/issues/732"},"EPIC tracking cryptographic equivocation feature")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://forum.cosmos.network/t/cryptographic-equivocation-slashing-design/11400"},"Cosmos Hub Forum discussion on cryptographic equivocation slashing"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/ffd4165d.dcb45328.js b/legacy/assets/js/ffd4165d.dcb45328.js new file mode 100644 index 0000000000..5015069756 --- /dev/null +++ b/legacy/assets/js/ffd4165d.dcb45328.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5022],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>v});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,r=function(e,t){if(null==e)return{};var n,o,r={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=o.createContext({}),l=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},d=function(e){var t=l(e.components);return o.createElement(c.Provider,{value:t},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,v=u["".concat(c,".").concat(h)]||u[h]||p[h]||i;return n?o.createElement(v,a(a({ref:t},d),{},{components:n})):o.createElement(v,a({ref:t},d))}));function v(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:r,a[1]=s;for(var l=2;l<i;l++)a[l]=n[l];return o.createElement.apply(null,a)}return o.createElement.apply(null,n)}h.displayName="MDXCreateElement"},6194:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var o=n(7462),r=(n(7294),n(3905));const i={sidebar_position:1},a="Overview",s={unversionedId:"introduction/overview",id:"version-v3.1.0/introduction/overview",title:"Overview",description:"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.",source:"@site/versioned_docs/version-v3.1.0/introduction/overview.md",sourceDirName:"introduction",slug:"/introduction/overview",permalink:"/interchain-security/legacy/v3.1.0/introduction/overview",draft:!1,tags:[],version:"v3.1.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Interchain Security Docs",permalink:"/interchain-security/legacy/v3.1.0/"},next:{title:"Terminology",permalink:"/interchain-security/legacy/v3.1.0/introduction/terminology"}},c={},l=[{value:"Why Replicated Security?",id:"why-replicated-security",level:2},{value:"Core protocol",id:"core-protocol",level:2},{value:"Downtime Slashing",id:"downtime-slashing",level:3},{value:"Equivocation (Double Sign) Slashing",id:"equivocation-double-sign-slashing",level:3},{value:"Tokenomics and Rewards",id:"tokenomics-and-rewards",level:3}],d={toc:l},u="wrapper";function p(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"overview"},"Overview"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another."),(0,r.kt)("br",null),'Replicated security allows anyone to launch a "consumer" blockchain using the same validator set as the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit the full security and decentralization of the provider.'),(0,r.kt)("h2",{id:"why-replicated-security"},"Why Replicated Security?"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Full provider security. At launch, consumer chains are secured by the full validator set and market cap of the provider chain."),(0,r.kt)("li",{parentName:"ul"},"Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum."),(0,r.kt)("li",{parentName:"ul"},"Projects keep majority of gas fees. Depending on configuration, these fees either go to the project\u2019s community DAO, or can be used in the protocol in other ways."),(0,r.kt)("li",{parentName:"ul"},"No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. A governance vote will take place for a chain to get adopted by the provider validators which will encourage participation and signal strong buy-in into the project's long-term success."),(0,r.kt)("li",{parentName:"ul"},"Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set.")),(0,r.kt)("h2",{id:"core-protocol"},"Core protocol"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Protocol specification is available as ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md"},"ICS-028")," in the IBC repository.")),(0,r.kt)("p",null,"Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer."),(0,r.kt)("p",null,"To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider."),(0,r.kt)("h3",{id:"downtime-slashing"},"Downtime Slashing"),(0,r.kt)("p",null,"If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period."),(0,r.kt)("h3",{id:"equivocation-double-sign-slashing"},"Equivocation (Double Sign) Slashing"),(0,r.kt)("p",null,"Evidence of equivocation must be submitted to provider governance and be voted on. This behavior is an extra safeguard before a validator is slashed, and may be replaced by a more automated system in the future."),(0,r.kt)("h3",{id:"tokenomics-and-rewards"},"Tokenomics and Rewards"),(0,r.kt)("p",null,"Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/legacy/assets/js/main.206ddac4.js b/legacy/assets/js/main.206ddac4.js new file mode 100644 index 0000000000..d6056eb905 --- /dev/null +++ b/legacy/assets/js/main.206ddac4.js @@ -0,0 +1,2 @@ +/*! For license information please see main.206ddac4.js.LICENSE.txt */ +(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[179],{723:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(7294),a=n(7462),i=n(8356),o=n.n(i),s=n(6887);const c={"00147ff4":[()=>n.e(2110).then(n.bind(n,6547)),"@site/docs/frequently-asked-questions.md",6547],"01ff7a4e":[()=>n.e(8219).then(n.bind(n,9912)),"@site/versioned_docs/version-v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop.md",9912],"0251db3a":[()=>n.e(4220).then(n.bind(n,5173)),"@site/versioned_docs/version-v3.3.0/consumer-development/onboarding.md",5173],"02951439":[()=>n.e(3734).then(n.bind(n,3368)),"@site/versioned_docs/version-v3.3.0/introduction/technical-specification.md",3368],"04f38623":[()=>n.e(8956).then(n.bind(n,8708)),"@site/versioned_docs/version-v2.0.0/consumer-development/onboarding.md",8708],"05354274":[()=>n.e(1614).then(n.bind(n,3564)),"@site/versioned_docs/version-v2.0.0/index.mdx",3564],"0613ea9d":[()=>n.e(495).then(n.bind(n,1645)),"@site/versioned_docs/version-v3.3.0/adrs/adr-010-standalone-changeover.md",1645],"07a13505":[()=>n.e(5964).then(n.t.bind(n,302,19)),"~docs/default/version-v-2-0-0-metadata-prop-d1a.json",302],"07d76e7d":[()=>n.e(2189).then(n.bind(n,1221)),"@site/docs/features/key-assignment.md",1221],"07e666cb":[()=>n.e(9783).then(n.bind(n,8833)),"@site/versioned_docs/version-v2.4.0-lsm/consumer-development/app-integration.md",8833],"08757149":[()=>n.e(3913).then(n.bind(n,7746)),"@site/versioned_docs/version-v3.1.0/adrs/adr-009-soft-opt-out.md",7746],"0b7cd1ab":[()=>n.e(6755).then(n.bind(n,2668)),"@site/versioned_docs/version-v3.2.0/consumer-development/changeover-procedure.md",2668],"0c7ba0cc":[()=>n.e(4077).then(n.bind(n,513)),"@site/versioned_docs/version-v3.2.0/consumer-development/onboarding.md",513],"0cb1d302":[()=>n.e(1085).then(n.bind(n,340)),"@site/docs/validators/joining-neutron.md",340],"10e700ac":[()=>n.e(3493).then(n.bind(n,7192)),"@site/versioned_docs/version-v3.3.1-lsm/consumer-development/consumer-chain-governance.md",7192],"11e17b14":[()=>n.e(6398).then(n.bind(n,8800)),"@site/versioned_docs/version-v2.0.0/consumer-development/consumer-chain-upgrade-procedure.md",8800],"14ce44a3":[()=>n.e(9759).then(n.bind(n,7119)),"@site/versioned_docs/version-v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-prop.md",7119],"1560cd4f":[()=>n.e(3858).then(n.bind(n,3319)),"@site/versioned_docs/version-v2.0.0/adrs/adr-001-key-assignment.md",3319],17896441:[()=>Promise.all([n.e(532),n.e(7918)]).then(n.bind(n,3431)),"@theme/DocItem",3431],"1833c00d":[()=>n.e(542).then(n.bind(n,4682)),"@site/versioned_docs/version-v3.3.0/adrs/adr-002-throttle.md",4682],"1a009efd":[()=>n.e(324).then(n.bind(n,3610)),"@site/versioned_docs/version-v3.1.0/introduction/technical-specification.md",3610],"1a276578":[()=>n.e(2087).then(n.bind(n,2806)),"@site/versioned_docs/version-v2.0.0/frequently-asked-questions.md",2806],"1bcdc660":[()=>n.e(2148).then(n.bind(n,2282)),"@site/versioned_docs/version-v3.1.0/features/key-assignment.md",2282],"1bdc04ff":[()=>n.e(8685).then(n.bind(n,7108)),"@site/versioned_docs/version-v2.4.0-lsm/features/proposals.md",7108],"1be78505":[()=>Promise.all([n.e(532),n.e(9514)]).then(n.bind(n,9963)),"@theme/DocPage",9963],"1ca03be8":[()=>n.e(1043).then(n.bind(n,5055)),"@site/versioned_docs/version-v2.4.0-lsm/introduction/overview.md",5055],"1d3f4228":[()=>n.e(863).then(n.bind(n,3881)),"@site/versioned_docs/version-v2.4.0-lsm/adrs/adr-template.md",3881],"1ec51b74":[()=>n.e(8779).then(n.bind(n,9762)),"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-009-soft-opt-out.md",9762],"1f0eef20":[()=>n.e(4895).then(n.bind(n,6313)),"@site/versioned_docs/version-v3.2.0/adrs/adr-003-equivocation-gov-proposal.md",6313],"1f170e32":[()=>n.e(847).then(n.bind(n,9206)),"@site/versioned_docs/version-v3.3.1-lsm/validators/changeover-procedure.md",9206],20543744:[()=>n.e(2002).then(n.bind(n,3115)),"@site/versioned_docs/version-v3.3.0/adrs/adr-013-equivocation-slashing.md",3115],"220c87fe":[()=>n.e(5627).then(n.bind(n,4616)),"@site/versioned_docs/version-v3.3.1-lsm/features/proposals.md",4616],"22c24bfe":[()=>n.e(2813).then(n.bind(n,1658)),"@site/versioned_docs/version-v3.3.0/introduction/overview.md",1658],"25dc14a6":[()=>n.e(7646).then(n.bind(n,3315)),"@site/versioned_docs/version-v2.4.0-lsm/features/slashing.md",3315],"27d4dd38":[()=>n.e(7209).then(n.bind(n,4396)),"@site/versioned_docs/version-v3.3.1-lsm/introduction/technical-specification.md",4396],"29f8b3e7":[()=>n.e(3986).then(n.bind(n,9896)),"@site/versioned_docs/version-v2.4.0-lsm/validators/withdraw_rewards.md",9896],"2b87464d":[()=>n.e(4868).then(n.bind(n,2175)),"@site/versioned_docs/version-v3.3.1-lsm/introduction/overview.md",2175],"2c7ea566":[()=>n.e(9124).then(n.bind(n,9374)),"@site/versioned_docs/version-v3.3.1-lsm/introduction/params.md",9374],"2ce37f2a":[()=>n.e(2979).then(n.bind(n,5094)),"@site/versioned_docs/version-v3.3.0/validators/overview.md",5094],"2cf1b2f2":[()=>n.e(9242).then(n.bind(n,8429)),"@site/versioned_docs/version-v3.3.0/consumer-development/changeover-procedure.md",8429],"2d2c570d":[()=>n.e(4520).then(n.bind(n,2348)),"@site/versioned_docs/version-v3.3.1-lsm/validators/withdraw_rewards.md",2348],"2ddaef92":[()=>n.e(2454).then(n.bind(n,8282)),"@site/versioned_docs/version-v3.2.0/adrs/adr-010-standalone-changeover.md",8282],"2e2fcf7b":[()=>n.e(918).then(n.bind(n,3372)),"@site/versioned_docs/version-v3.2.0/adrs/adr-012-separate-releasing.md",3372],"2ee035c9":[()=>n.e(9029).then(n.bind(n,900)),"@site/versioned_docs/version-v2.4.0-lsm/introduction/terminology.md",900],"2eef71dd":[()=>n.e(5464).then(n.bind(n,6914)),"@site/versioned_docs/version-v3.1.0/validators/joining-testnet.md",6914],"306f1d5d":[()=>n.e(8130).then(n.bind(n,6944)),"@site/versioned_docs/version-v3.3.0/validators/joining-testnet.md",6944],"32783f50":[()=>n.e(2361).then(n.t.bind(n,3769,19)),"/Users/msalopek/informal/interchain-security/docs/.docusaurus/docusaurus-plugin-content-docs/default/plugin-route-context-module-100.json",3769],"3299f073":[()=>n.e(8756).then(n.bind(n,5142)),"@site/versioned_docs/version-v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposal.md",5142],"358d35ce":[()=>n.e(4343).then(n.bind(n,235)),"@site/versioned_docs/version-v3.3.1-lsm/features/key-assignment.md",235],"3672b5b7":[()=>n.e(320).then(n.bind(n,6239)),"@site/docs/introduction/params.md",6239],"3739a4c2":[()=>n.e(8935).then(n.bind(n,9187)),"@site/versioned_docs/version-v3.2.0/adrs/adr-002-throttle.md",9187],37744218:[()=>n.e(7116).then(n.bind(n,4251)),"@site/versioned_docs/version-v3.3.1-lsm/validators/joining-neutron.md",4251],"3a65a150":[()=>n.e(2181).then(n.bind(n,8014)),"@site/versioned_docs/version-v3.1.0/frequently-asked-questions.md",8014],"3be89897":[()=>n.e(8763).then(n.bind(n,1597)),"@site/versioned_docs/version-v3.3.0/validators/joining-neutron.md",1597],"3d02a384":[()=>n.e(2584).then(n.bind(n,4718)),"@site/versioned_docs/version-v3.2.0/adrs/adr-013-equivocation-slashing.md",4718],"3e7b8ec9":[()=>n.e(766).then(n.bind(n,8049)),"@site/versioned_docs/version-v2.0.0/consumer-development/consumer-chain-governance.md",8049],40105847:[()=>n.e(5721).then(n.bind(n,2781)),"@site/versioned_docs/version-v3.3.1-lsm/consumer-development/app-integration.md",2781],"4106f1c5":[()=>n.e(842).then(n.bind(n,2137)),"@site/docs/features/slashing.md",2137],"4255538f":[()=>n.e(1535).then(n.bind(n,1235)),"@site/versioned_docs/version-v3.3.1-lsm/features/reward-distribution.md",1235],"425bba28":[()=>n.e(1118).then(n.bind(n,2393)),"@site/docs/consumer-development/consumer-genesis-transformation.md",2393],"432d4f39":[()=>n.e(6239).then(n.bind(n,1005)),"@site/versioned_docs/version-v3.3.0/introduction/params.md",1005],"437cf289":[()=>n.e(1289).then(n.bind(n,9814)),"@site/versioned_docs/version-v3.3.0/adrs/adr-011-improving-test-confidence.md",9814],"44efc911":[()=>n.e(872).then(n.bind(n,5336)),"@site/versioned_docs/version-v3.1.0/adrs/adr-001-key-assignment.md",5336],"455b0b19":[()=>n.e(492).then(n.bind(n,3277)),"@site/versioned_docs/version-v3.2.0/adrs/intro.md",3277],"45f2a265":[()=>n.e(5864).then(n.bind(n,2350)),"@site/versioned_docs/version-v3.3.0/consumer-development/consumer-genesis-transformation.md",2350],"46057b98":[()=>n.e(3159).then(n.bind(n,704)),"@site/docs/adrs/adr-003-equivocation-gov-proposal.md",704],"46dddd35":[()=>n.e(5474).then(n.bind(n,9639)),"@site/versioned_docs/version-v3.2.0/consumer-development/app-integration.md",9639],"4b0243dd":[()=>n.e(1136).then(n.bind(n,4)),"@site/versioned_docs/version-v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verification.md",4],"4bec4d8c":[()=>n.e(8124).then(n.bind(n,8879)),"@site/versioned_docs/version-v3.2.0/consumer-development/offboarding.md",8879],"4c058ddf":[()=>n.e(333).then(n.bind(n,6978)),"@site/versioned_docs/version-v3.1.0/consumer-development/app-integration.md",6978],"4c7d82ee":[()=>n.e(7649).then(n.bind(n,1089)),"@site/docs/adrs/adr-005-cryptographic-equivocation-verification.md",1089],"4c855390":[()=>n.e(375).then(n.bind(n,3614)),"@site/versioned_docs/version-v2.0.0/introduction/technical-specification.md",3614],"4cc37eaf":[()=>n.e(4322).then(n.bind(n,9117)),"@site/versioned_docs/version-v2.4.0-lsm/validators/joining-testnet.md",9117],"4edc808e":[()=>n.e(4173).then(n.bind(n,1788)),"@site/docs/index.mdx",1788],"4f50acdf":[()=>n.e(9815).then(n.bind(n,177)),"@site/docs/validators/joining-testnet.md",177],"50036eb1":[()=>n.e(7249).then(n.bind(n,2003)),"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-008-throttle-retries.md",2003],"545e4084":[()=>n.e(4457).then(n.bind(n,5993)),"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-013-equivocation-slashing.md",5993],"54e4400b":[()=>n.e(2344).then(n.bind(n,6713)),"@site/docs/adrs/adr-001-key-assignment.md",6713],56185081:[()=>n.e(8087).then(n.bind(n,3476)),"@site/versioned_docs/version-v3.2.0/validators/overview.md",3476],"568ca951":[()=>n.e(6438).then(n.bind(n,781)),"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-010-standalone-changeover.md",781],57203821:[()=>n.e(8646).then(n.bind(n,5942)),"@site/versioned_docs/version-v3.2.0/adrs/adr-011-improving-test-confidence.md",5942],"578fb1aa":[()=>n.e(2323).then(n.bind(n,5790)),"@site/docs/features/reward-distribution.md",5790],"57c82761":[()=>n.e(3422).then(n.bind(n,8383)),"@site/versioned_docs/version-v3.1.0/consumer-development/onboarding.md",8383],"5f35bbec":[()=>n.e(6322).then(n.bind(n,117)),"@site/versioned_docs/version-v2.0.0/introduction/terminology.md",117],"5f3b723a":[()=>n.e(1585).then(n.bind(n,3263)),"@site/versioned_docs/version-v3.3.1-lsm/adrs/intro.md",3263],"5fdaaf8d":[()=>n.e(5685).then(n.bind(n,6896)),"@site/versioned_docs/version-v3.2.0/validators/withdraw_rewards.md",6896],"609d3cd8":[()=>n.e(4675).then(n.bind(n,4635)),"@site/versioned_docs/version-v3.3.1-lsm/consumer-development/onboarding.md",4635],"62a5ef54":[()=>n.e(6501).then(n.bind(n,5242)),"@site/versioned_docs/version-v3.2.0/introduction/params.md",5242],"6441912e":[()=>n.e(1849).then(n.bind(n,3170)),"@site/versioned_docs/version-v2.0.0/adrs/adr-003-equivocation-gov-proposal.md",3170],"65076e0d":[()=>n.e(2589).then(n.bind(n,5603)),"@site/versioned_docs/version-v2.4.0-lsm/consumer-development/consumer-chain-governance.md",5603],"665374cc":[()=>n.e(2384).then(n.bind(n,6741)),"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-005-cryptographic-equivocation-verification.md",6741],"6700d82f":[()=>n.e(8055).then(n.bind(n,1813)),"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-012-separate-releasing.md",1813],"67f96001":[()=>n.e(6938).then(n.bind(n,7874)),"@site/versioned_docs/version-v3.1.0/adrs/adr-template.md",7874],"68191a78":[()=>n.e(4438).then(n.bind(n,7277)),"@site/docs/adrs/adr-011-improving-test-confidence.md",7277],"681cd12f":[()=>n.e(7443).then(n.bind(n,8013)),"@site/versioned_docs/version-v3.3.0/adrs/adr-005-cryptographic-equivocation-verification.md",8013],"6a7358b5":[()=>n.e(9743).then(n.bind(n,3356)),"@site/versioned_docs/version-v2.0.0/introduction/params.md",3356],"6c7cd03d":[()=>n.e(379).then(n.t.bind(n,2780,19)),"~docs/default/version-v-2-4-0-lsm-metadata-prop-787.json",2780],"6f71328c":[()=>n.e(8560).then(n.bind(n,9108)),"@site/docs/adrs/adr-013-equivocation-slashing.md",9108],"70938a03":[()=>n.e(5457).then(n.bind(n,8818)),"@site/docs/consumer-development/changeover-procedure.md",8818],"75331c0b":[()=>n.e(2745).then(n.bind(n,9305)),"@site/versioned_docs/version-v3.3.0/adrs/adr-012-separate-releasing.md",9305],"758625d4":[()=>n.e(321).then(n.bind(n,4142)),"@site/docs/validators/withdraw_rewards.md",4142],"7616f23a":[()=>n.e(2247).then(n.bind(n,770)),"@site/docs/introduction/overview.md",770],"7670b92c":[()=>n.e(9552).then(n.bind(n,3413)),"@site/versioned_docs/version-v3.2.0/features/proposals.md",3413],"774a0fba":[()=>n.e(7335).then(n.bind(n,6004)),"@site/versioned_docs/version-v3.3.0/features/slashing.md",6004],"775e2592":[()=>n.e(7375).then(n.bind(n,6428)),"@site/docs/adrs/adr-008-throttle-retries.md",6428],"7a380eb1":[()=>n.e(524).then(n.bind(n,8983)),"@site/versioned_docs/version-v2.4.0-lsm/adrs/intro.md",8983],"7b7e6708":[()=>n.e(414).then(n.bind(n,1186)),"@site/versioned_docs/version-v3.3.1-lsm/validators/joining-testnet.md",1186],"7c1fc285":[()=>n.e(4645).then(n.bind(n,8131)),"@site/versioned_docs/version-v2.0.0/consumer-development/app-integration.md",8131],"7cd5f60b":[()=>n.e(5357).then(n.bind(n,2632)),"@site/versioned_docs/version-v3.3.0/features/reward-distribution.md",2632],"811ce3c2":[()=>n.e(9701).then(n.bind(n,4740)),"@site/versioned_docs/version-v2.0.0/features/key-assignment.md",4740],81762141:[()=>n.e(1409).then(n.bind(n,7125)),"@site/versioned_docs/version-v2.0.0/features/proposals.md",7125],"834888be":[()=>n.e(5831).then(n.bind(n,270)),"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-template.md",270],"84bd924c":[()=>n.e(2777).then(n.bind(n,329)),"@site/versioned_docs/version-v3.1.0/introduction/terminology.md",329],"8565b213":[()=>n.e(1962).then(n.bind(n,7068)),"@site/versioned_docs/version-v2.4.0-lsm/frequently-asked-questions.md",7068],"863c9ec3":[()=>n.e(2068).then(n.bind(n,2248)),"@site/versioned_docs/version-v3.2.0/features/slashing.md",2248],"875b184f":[()=>n.e(8281).then(n.bind(n,7648)),"@site/versioned_docs/version-v3.1.0/validators/overview.md",7648],"8782d4a8":[()=>n.e(5101).then(n.bind(n,2189)),"@site/versioned_docs/version-v3.3.1-lsm/consumer-development/changeover-procedure.md",2189],"89638eb3":[()=>n.e(818).then(n.bind(n,5882)),"@site/versioned_docs/version-v3.3.1-lsm/validators/joining-stride.md",5882],"8e91dc0c":[()=>n.e(2098).then(n.bind(n,8081)),"@site/versioned_docs/version-v3.3.0/features/proposals.md",8081],"8fb9dc62":[()=>n.e(6960).then(n.bind(n,4184)),"@site/versioned_docs/version-v2.0.0/validators/withdraw_rewards.md",4184],"903c2771":[()=>n.e(6054).then(n.bind(n,8896)),"@site/docs/adrs/adr-009-soft-opt-out.md",8896],"90a8ce65":[()=>n.e(2749).then(n.bind(n,3794)),"@site/versioned_docs/version-v3.3.0/adrs/adr-003-equivocation-gov-proposal.md",3794],"91cc339f":[()=>n.e(1298).then(n.bind(n,2732)),"@site/versioned_docs/version-v3.2.0/adrs/adr-template.md",2732],"935f2afb":[()=>n.e(53).then(n.t.bind(n,1109,19)),"~docs/default/version-current-metadata-prop-751.json",1109],"95875ea0":[()=>n.e(3813).then(n.bind(n,1670)),"@site/docs/consumer-development/onboarding.md",1670],"972fb3fd":[()=>n.e(6725).then(n.bind(n,3979)),"@site/versioned_docs/version-v3.2.0/features/key-assignment.md",3979],"97c83118":[()=>n.e(3938).then(n.bind(n,7142)),"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-002-throttle.md",7142],"98c1c075":[()=>n.e(2082).then(n.bind(n,4858)),"@site/versioned_docs/version-v3.3.0/consumer-development/app-integration.md",4858],"9b050cce":[()=>n.e(692).then(n.t.bind(n,6932,19)),"~docs/default/version-v-3-1-0-metadata-prop-f5c.json",6932],"9b3ea85c":[()=>n.e(4676).then(n.bind(n,2768)),"@site/versioned_docs/version-v2.0.0/validators/joining-testnet.md",2768],"9c1db290":[()=>n.e(7372).then(n.bind(n,3886)),"@site/versioned_docs/version-v3.3.0/consumer-development/consumer-chain-governance.md",3886],"9fe5be76":[()=>n.e(4391).then(n.bind(n,7182)),"@site/versioned_docs/version-v3.3.0/adrs/intro.md",7182],"9fecc647":[()=>n.e(8194).then(n.bind(n,689)),"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-011-improving-test-confidence.md",689],a2707102:[()=>n.e(457).then(n.bind(n,1663)),"@site/docs/adrs/intro.md",1663],a31f1e88:[()=>n.e(6255).then(n.bind(n,8958)),"@site/versioned_docs/version-v3.2.0/validators/joining-stride.md",8958],a486c914:[()=>n.e(7988).then(n.bind(n,5131)),"@site/versioned_docs/version-v3.3.1-lsm/features/slashing.md",5131],a8d2c030:[()=>n.e(137).then(n.bind(n,8540)),"@site/versioned_docs/version-v3.3.1-lsm/introduction/terminology.md",8540],a9646977:[()=>n.e(608).then(n.bind(n,1234)),"@site/versioned_docs/version-v3.3.0/index.mdx",1234],ae63551b:[()=>n.e(5056).then(n.bind(n,1990)),"@site/docs/validators/joining-stride.md",1990],aede9d74:[()=>n.e(1087).then(n.bind(n,2040)),"@site/versioned_docs/version-v3.1.0/introduction/params.md",2040],afe2e479:[()=>n.e(6108).then(n.bind(n,9646)),"@site/versioned_docs/version-v3.1.0/consumer-development/offboarding.md",9646],b06966f1:[()=>n.e(5011).then(n.bind(n,9432)),"@site/versioned_docs/version-v3.3.0/adrs/adr-template.md",9432],b1bce14b:[()=>n.e(7762).then(n.bind(n,9428)),"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-001-key-assignment.md",9428],b1ce16c0:[()=>n.e(7652).then(n.bind(n,8110)),"@site/versioned_docs/version-v2.0.0/adrs/adr-template.md",8110],b2cefb99:[()=>n.e(3943).then(n.bind(n,3349)),"@site/versioned_docs/version-v3.3.1-lsm/index.mdx",3349],b2effb50:[()=>n.e(5626).then(n.t.bind(n,943,19)),"~docs/default/version-v-3-2-0-metadata-prop-4e3.json",943],b4bb90a1:[()=>n.e(8990).then(n.bind(n,4599)),"@site/versioned_docs/version-v3.1.0/consumer-development/consumer-chain-upgrade-procedure.md",4599],b7347dde:[()=>n.e(2784).then(n.bind(n,5456)),"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-003-equivocation-gov-proposal.md",5456],b74a2173:[()=>n.e(2845).then(n.bind(n,2628)),"@site/versioned_docs/version-v2.4.0-lsm/validators/overview.md",2628],b9eeacc5:[()=>n.e(7567).then(n.bind(n,4961)),"@site/versioned_docs/version-v2.0.0/adrs/intro.md",4961],bb11f0e8:[()=>n.e(2293).then(n.bind(n,6431)),"@site/versioned_docs/version-v3.1.0/validators/withdraw_rewards.md",6431],bb7b1385:[()=>n.e(8186).then(n.bind(n,7449)),"@site/versioned_docs/version-v3.2.0/adrs/adr-001-key-assignment.md",7449],bbea31d2:[()=>n.e(109).then(n.bind(n,1382)),"@site/docs/adrs/adr-002-throttle.md",1382],bc17315d:[()=>n.e(1534).then(n.bind(n,6008)),"@site/versioned_docs/version-v2.4.0-lsm/consumer-development/consumer-chain-upgrade-procedure.md",6008],bc700a7c:[()=>n.e(5202).then(n.bind(n,9439)),"@site/versioned_docs/version-v3.1.0/adrs/adr-008-throttle-retries.md",9439],bc8b8418:[()=>n.e(4704).then(n.bind(n,1322)),"@site/docs/introduction/terminology.md",1322],c2cfb320:[()=>n.e(1429).then(n.bind(n,6096)),"@site/docs/validators/changeover-procedure.md",6096],c2da6a7e:[()=>n.e(155).then(n.bind(n,9562)),"@site/versioned_docs/version-v3.1.0/consumer-development/consumer-chain-governance.md",9562],c37f2705:[()=>n.e(4695).then(n.bind(n,6705)),"@site/docs/adrs/adr-template.md",6705],c566c0a4:[()=>n.e(8976).then(n.bind(n,449)),"@site/versioned_docs/version-v3.2.0/adrs/adr-008-throttle-retries.md",449],c57e97ca:[()=>n.e(5731).then(n.bind(n,9177)),"@site/versioned_docs/version-v2.4.0-lsm/introduction/params.md",9177],c5de07d7:[()=>n.e(74).then(n.bind(n,6584)),"@site/versioned_docs/version-v3.2.0/frequently-asked-questions.md",6584],c880b3c7:[()=>n.e(1564).then(n.bind(n,2610)),"@site/versioned_docs/version-v3.3.0/introduction/terminology.md",2610],c99bfd69:[()=>n.e(3631).then(n.bind(n,5137)),"@site/versioned_docs/version-v3.1.0/features/proposals.md",5137],c9ae8e5c:[()=>n.e(7428).then(n.bind(n,4482)),"@site/versioned_docs/version-v3.2.0/validators/joining-neutron.md",4482],ccd1c519:[()=>n.e(4115).then(n.bind(n,9610)),"@site/versioned_docs/version-v3.2.0/introduction/overview.md",9610],cdc1959e:[()=>n.e(6986).then(n.bind(n,2875)),"@site/versioned_docs/version-v3.3.1-lsm/frequently-asked-questions.md",2875],ceabb0b9:[()=>n.e(6703).then(n.bind(n,9585)),"@site/versioned_docs/version-v3.3.1-lsm/adrs/adr-007-pause-unbonding-on-eqv-prop.md",9585],cf411473:[()=>n.e(3153).then(n.bind(n,2021)),"@site/docs/introduction/technical-specification.md",2021],d0d0ba0d:[()=>n.e(8772).then(n.bind(n,6843)),"@site/docs/adrs/adr-010-standalone-changeover.md",6843],d1daeca6:[()=>n.e(3845).then(n.bind(n,9265)),"@site/docs/features/proposals.md",9265],d21f9ede:[()=>n.e(4932).then(n.bind(n,3035)),"@site/docs/adrs/adr-012-separate-releasing.md",3035],d262fdd7:[()=>n.e(3842).then(n.bind(n,5461)),"@site/versioned_docs/version-v3.1.0/features/slashing.md",5461],d411b146:[()=>n.e(1081).then(n.bind(n,2086)),"@site/versioned_docs/version-v2.0.0/features/slashing.md",2086],d4f67fc8:[()=>n.e(9980).then(n.bind(n,2153)),"@site/versioned_docs/version-v2.4.0-lsm/introduction/technical-specification.md",2153],d63ae50e:[()=>n.e(6318).then(n.bind(n,2045)),"@site/versioned_docs/version-v2.4.0-lsm/features/reward-distribution.md",2045],d67a6454:[()=>n.e(4738).then(n.bind(n,5266)),"@site/versioned_docs/version-v2.0.0/adrs/adr-002-throttle.md",5266],d73929d1:[()=>n.e(8795).then(n.bind(n,5403)),"@site/versioned_docs/version-v3.1.0/adrs/intro.md",5403],d784d738:[()=>n.e(7333).then(n.bind(n,9774)),"@site/docs/consumer-development/app-integration.md",9774],d88536eb:[()=>n.e(8330).then(n.bind(n,5732)),"@site/versioned_docs/version-v2.4.0-lsm/consumer-development/onboarding.md",5732],d925e878:[()=>n.e(6550).then(n.bind(n,1558)),"@site/versioned_docs/version-v3.3.0/consumer-development/offboarding.md",1558],d9aa5843:[()=>n.e(2715).then(n.bind(n,4541)),"@site/versioned_docs/version-v3.3.0/frequently-asked-questions.md",4541],db091dad:[()=>n.e(4360).then(n.bind(n,624)),"@site/versioned_docs/version-v2.0.0/consumer-development/offboarding.md",624],dc875b45:[()=>n.e(6894).then(n.bind(n,1350)),"@site/versioned_docs/version-v3.3.0/adrs/adr-008-throttle-retries.md",1350],dc9efaba:[()=>n.e(1324).then(n.bind(n,5224)),"@site/docs/consumer-development/offboarding.md",5224],dca56be7:[()=>n.e(3612).then(n.bind(n,5109)),"@site/versioned_docs/version-v3.3.1-lsm/validators/overview.md",5109],dca8d7c6:[()=>n.e(947).then(n.bind(n,8795)),"@site/versioned_docs/version-v2.4.0-lsm/adrs/adr-002-throttle.md",8795],dd2dc399:[()=>n.e(8973).then(n.bind(n,9683)),"@site/versioned_docs/version-v3.2.0/adrs/adr-005-cryptographic-equivocation-verification.md",9683],ded36896:[()=>n.e(7429).then(n.bind(n,9969)),"@site/docs/adrs/adr-007-pause-unbonding-on-eqv-prop.md",9969],dee569d7:[()=>n.e(1878).then(n.bind(n,6087)),"@site/versioned_docs/version-v3.2.0/validators/joining-testnet.md",6087],df2bbb5c:[()=>n.e(9832).then(n.bind(n,8543)),"@site/versioned_docs/version-v3.3.0/validators/changeover-procedure.md",8543],df89b832:[()=>n.e(5059).then(n.bind(n,6619)),"@site/versioned_docs/version-v3.3.0/adrs/adr-001-key-assignment.md",6619],e1611597:[()=>n.e(9300).then(n.bind(n,7033)),"@site/versioned_docs/version-v2.4.0-lsm/index.mdx",7033],e181537f:[()=>n.e(5680).then(n.bind(n,159)),"@site/versioned_docs/version-v3.3.0/adrs/adr-009-soft-opt-out.md",159],e23b6b4c:[()=>n.e(5349).then(n.bind(n,5516)),"@site/versioned_docs/version-v2.0.0/validators/overview.md",5516],e3e9e529:[()=>n.e(3302).then(n.t.bind(n,369,19)),"~docs/default/version-v-3-3-0-metadata-prop-c91.json",369],e6400f0f:[()=>n.e(1064).then(n.bind(n,9925)),"@site/versioned_docs/version-v3.3.0/validators/joining-stride.md",9925],e9d00230:[()=>n.e(4158).then(n.bind(n,5796)),"@site/versioned_docs/version-v3.2.0/adrs/adr-009-soft-opt-out.md",5796],eb02ef83:[()=>n.e(1657).then(n.bind(n,5304)),"@site/versioned_docs/version-v3.1.0/adrs/adr-002-throttle.md",5304],ebdc1949:[()=>n.e(915).then(n.bind(n,5256)),"@site/versioned_docs/version-v3.1.0/adrs/adr-003-equivocation-gov-proposal.md",5256],ed4bc87d:[()=>n.e(3932).then(n.bind(n,8757)),"@site/versioned_docs/version-v3.2.0/features/reward-distribution.md",8757],ee5432e5:[()=>n.e(2876).then(n.bind(n,2087)),"@site/versioned_docs/version-v3.2.0/introduction/terminology.md",2087],ee6b1b56:[()=>n.e(141).then(n.bind(n,2226)),"@site/versioned_docs/version-v3.1.0/index.mdx",2226],f0becab0:[()=>n.e(222).then(n.bind(n,7414)),"@site/versioned_docs/version-v3.2.0/index.mdx",7414],f143d156:[()=>n.e(7511).then(n.bind(n,3062)),"@site/versioned_docs/version-v3.2.0/validators/changeover-procedure.md",3062],f249e987:[()=>n.e(9117).then(n.bind(n,4071)),"@site/versioned_docs/version-v2.0.0/features/reward-distribution.md",4071],f37bbee8:[()=>n.e(3739).then(n.bind(n,310)),"@site/versioned_docs/version-v3.2.0/consumer-development/consumer-chain-governance.md",310],f4495aae:[()=>n.e(5045).then(n.bind(n,3896)),"@site/versioned_docs/version-v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-prop.md",3896],f496e447:[()=>n.e(544).then(n.bind(n,3898)),"@site/versioned_docs/version-v3.2.0/introduction/technical-specification.md",3898],f4ce0483:[()=>n.e(468).then(n.bind(n,2625)),"@site/versioned_docs/version-v3.3.1-lsm/consumer-development/consumer-genesis-transformation.md",2625],f5589540:[()=>n.e(6499).then(n.bind(n,4906)),"@site/docs/consumer-development/consumer-chain-governance.md",4906],f5746d50:[()=>n.e(8313).then(n.bind(n,7519)),"@site/versioned_docs/version-v3.3.0/features/key-assignment.md",7519],f6addb2b:[()=>n.e(35).then(n.bind(n,7805)),"@site/docs/validators/overview.md",7805],f7a87f6d:[()=>n.e(2117).then(n.t.bind(n,5693,19)),"~docs/default/version-v-3-3-1-lsm-metadata-prop-37f.json",5693],f8317958:[()=>n.e(8930).then(n.bind(n,971)),"@site/versioned_docs/version-v2.4.0-lsm/features/key-assignment.md",971],fbda1364:[()=>n.e(5868).then(n.bind(n,7792)),"@site/versioned_docs/version-v3.1.0/features/reward-distribution.md",7792],fc1c61d3:[()=>n.e(4150).then(n.bind(n,567)),"@site/versioned_docs/version-v2.4.0-lsm/adrs/adr-001-key-assignment.md",567],fcd25e9d:[()=>n.e(9474).then(n.bind(n,419)),"@site/versioned_docs/version-v3.3.1-lsm/consumer-development/offboarding.md",419],fe5d7ad2:[()=>n.e(5863).then(n.bind(n,8636)),"@site/versioned_docs/version-v2.0.0/introduction/overview.md",8636],fee5bc5e:[()=>n.e(8661).then(n.bind(n,3773)),"@site/versioned_docs/version-v3.3.0/validators/withdraw_rewards.md",3773],ff39e481:[()=>n.e(6181).then(n.bind(n,6659)),"@site/versioned_docs/version-v2.4.0-lsm/consumer-development/offboarding.md",6659],ff887390:[()=>n.e(146).then(n.bind(n,3160)),"@site/versioned_docs/version-v2.4.0-lsm/adrs/adr-013-equivocation-slashing.md",3160],ffd4165d:[()=>n.e(5022).then(n.bind(n,6194)),"@site/versioned_docs/version-v3.1.0/introduction/overview.md",6194]};function l(e){let{error:t,retry:n,pastDelay:a}=e;return t?r.createElement("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"}},r.createElement("p",null,String(t)),r.createElement("div",null,r.createElement("button",{type:"button",onClick:n},"Retry"))):a?r.createElement("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"}},r.createElement("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb"},r.createElement("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2"},r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"8"},r.createElement("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"}))))):null}var u=n(9670),d=n(226);function p(e,t){if("*"===e)return o()({loading:l,loader:()=>n.e(4972).then(n.bind(n,4972)),modules:["@theme/NotFound"],webpack:()=>[4972],render(e,t){const n=e.default;return r.createElement(d.z,{value:{plugin:{name:"native",id:"default"}}},r.createElement(n,t))}});const i=s[`${e}-${t}`],p={},f=[],m=[],h=(0,u.Z)(i);return Object.entries(h).forEach((e=>{let[t,n]=e;const r=c[n];r&&(p[t]=r[0],f.push(r[1]),m.push(r[2]))})),o().Map({loading:l,loader:p,modules:f,webpack:()=>m,render(t,n){const o=JSON.parse(JSON.stringify(i));Object.entries(t).forEach((t=>{let[n,r]=t;const a=r.default;if(!a)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof a&&"function"!=typeof a||Object.keys(r).filter((e=>"default"!==e)).forEach((e=>{a[e]=r[e]}));let i=o;const s=n.split(".");s.slice(0,-1).forEach((e=>{i=i[e]})),i[s[s.length-1]]=a}));const s=o.__comp;delete o.__comp;const c=o.__context;return delete o.__context,r.createElement(d.z,{value:c},r.createElement(s,(0,a.Z)({},o,n)))}})}const f=[{path:"/interchain-security/legacy/v2.0.0",component:p("/interchain-security/legacy/v2.0.0","1ff"),routes:[{path:"/interchain-security/legacy/v2.0.0",component:p("/interchain-security/legacy/v2.0.0","623"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/adrs/adr-001-key-assignment",component:p("/interchain-security/legacy/v2.0.0/adrs/adr-001-key-assignment","941"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/adrs/adr-002-throttle",component:p("/interchain-security/legacy/v2.0.0/adrs/adr-002-throttle","91d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/adrs/adr-003-equivocation-gov-proposal",component:p("/interchain-security/legacy/v2.0.0/adrs/adr-003-equivocation-gov-proposal","f38"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/adrs/adr-template",component:p("/interchain-security/legacy/v2.0.0/adrs/adr-template","089"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/adrs/intro",component:p("/interchain-security/legacy/v2.0.0/adrs/intro","583"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/consumer-development/app-integration",component:p("/interchain-security/legacy/v2.0.0/consumer-development/app-integration","5b5"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/consumer-development/consumer-chain-governance",component:p("/interchain-security/legacy/v2.0.0/consumer-development/consumer-chain-governance","5d8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/consumer-development/consumer-chain-upgrade-procedure",component:p("/interchain-security/legacy/v2.0.0/consumer-development/consumer-chain-upgrade-procedure","a22"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/consumer-development/offboarding",component:p("/interchain-security/legacy/v2.0.0/consumer-development/offboarding","b91"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/consumer-development/onboarding",component:p("/interchain-security/legacy/v2.0.0/consumer-development/onboarding","986"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/faq",component:p("/interchain-security/legacy/v2.0.0/faq","be2"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/features/key-assignment",component:p("/interchain-security/legacy/v2.0.0/features/key-assignment","188"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/features/proposals",component:p("/interchain-security/legacy/v2.0.0/features/proposals","61c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/features/reward-distribution",component:p("/interchain-security/legacy/v2.0.0/features/reward-distribution","957"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/features/slashing",component:p("/interchain-security/legacy/v2.0.0/features/slashing","cfe"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/introduction/overview",component:p("/interchain-security/legacy/v2.0.0/introduction/overview","a87"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/introduction/params",component:p("/interchain-security/legacy/v2.0.0/introduction/params","30e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/introduction/technical-specification",component:p("/interchain-security/legacy/v2.0.0/introduction/technical-specification","413"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/introduction/terminology",component:p("/interchain-security/legacy/v2.0.0/introduction/terminology","3cf"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/validators/joining-testnet",component:p("/interchain-security/legacy/v2.0.0/validators/joining-testnet","2d2"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/validators/overview",component:p("/interchain-security/legacy/v2.0.0/validators/overview","c31"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.0.0/validators/withdraw_rewards",component:p("/interchain-security/legacy/v2.0.0/validators/withdraw_rewards","eff"),exact:!0,sidebar:"tutorialSidebar"}]},{path:"/interchain-security/legacy/v2.4.0-lsm",component:p("/interchain-security/legacy/v2.4.0-lsm","1b8"),routes:[{path:"/interchain-security/legacy/v2.4.0-lsm",component:p("/interchain-security/legacy/v2.4.0-lsm","9bc"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-001-key-assignment",component:p("/interchain-security/legacy/v2.4.0-lsm/adrs/adr-001-key-assignment","c87"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-002-throttle",component:p("/interchain-security/legacy/v2.4.0-lsm/adrs/adr-002-throttle","c8b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposal",component:p("/interchain-security/legacy/v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposal","dcc"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verification",component:p("/interchain-security/legacy/v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verification","be7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-013-equivocation-slashing",component:p("/interchain-security/legacy/v2.4.0-lsm/adrs/adr-013-equivocation-slashing","411"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-template",component:p("/interchain-security/legacy/v2.4.0-lsm/adrs/adr-template","03e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/adrs/intro",component:p("/interchain-security/legacy/v2.4.0-lsm/adrs/intro","58f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/app-integration",component:p("/interchain-security/legacy/v2.4.0-lsm/consumer-development/app-integration","af1"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/consumer-chain-governance",component:p("/interchain-security/legacy/v2.4.0-lsm/consumer-development/consumer-chain-governance","be1"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/consumer-chain-upgrade-procedure",component:p("/interchain-security/legacy/v2.4.0-lsm/consumer-development/consumer-chain-upgrade-procedure","925"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/offboarding",component:p("/interchain-security/legacy/v2.4.0-lsm/consumer-development/offboarding","052"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/consumer-development/onboarding",component:p("/interchain-security/legacy/v2.4.0-lsm/consumer-development/onboarding","ff4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/faq",component:p("/interchain-security/legacy/v2.4.0-lsm/faq","9e7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/features/key-assignment",component:p("/interchain-security/legacy/v2.4.0-lsm/features/key-assignment","f8a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/features/proposals",component:p("/interchain-security/legacy/v2.4.0-lsm/features/proposals","7c0"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/features/reward-distribution",component:p("/interchain-security/legacy/v2.4.0-lsm/features/reward-distribution","05f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/features/slashing",component:p("/interchain-security/legacy/v2.4.0-lsm/features/slashing","855"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/introduction/overview",component:p("/interchain-security/legacy/v2.4.0-lsm/introduction/overview","6ed"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/introduction/params",component:p("/interchain-security/legacy/v2.4.0-lsm/introduction/params","e14"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/introduction/technical-specification",component:p("/interchain-security/legacy/v2.4.0-lsm/introduction/technical-specification","2a0"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/introduction/terminology",component:p("/interchain-security/legacy/v2.4.0-lsm/introduction/terminology","e9b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/validators/joining-testnet",component:p("/interchain-security/legacy/v2.4.0-lsm/validators/joining-testnet","70b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/validators/overview",component:p("/interchain-security/legacy/v2.4.0-lsm/validators/overview","c17"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v2.4.0-lsm/validators/withdraw_rewards",component:p("/interchain-security/legacy/v2.4.0-lsm/validators/withdraw_rewards","e41"),exact:!0,sidebar:"tutorialSidebar"}]},{path:"/interchain-security/legacy/v3.1.0",component:p("/interchain-security/legacy/v3.1.0","e82"),routes:[{path:"/interchain-security/legacy/v3.1.0",component:p("/interchain-security/legacy/v3.1.0","905"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/adrs/adr-001-key-assignment",component:p("/interchain-security/legacy/v3.1.0/adrs/adr-001-key-assignment","138"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/adrs/adr-002-throttle",component:p("/interchain-security/legacy/v3.1.0/adrs/adr-002-throttle","391"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/adrs/adr-003-equivocation-gov-proposal",component:p("/interchain-security/legacy/v3.1.0/adrs/adr-003-equivocation-gov-proposal","593"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-prop",component:p("/interchain-security/legacy/v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-prop","3af"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/adrs/adr-008-throttle-retries",component:p("/interchain-security/legacy/v3.1.0/adrs/adr-008-throttle-retries","029"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/adrs/adr-009-soft-opt-out",component:p("/interchain-security/legacy/v3.1.0/adrs/adr-009-soft-opt-out","65e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/adrs/adr-template",component:p("/interchain-security/legacy/v3.1.0/adrs/adr-template","d1f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/adrs/intro",component:p("/interchain-security/legacy/v3.1.0/adrs/intro","727"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/consumer-development/app-integration",component:p("/interchain-security/legacy/v3.1.0/consumer-development/app-integration","c88"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/consumer-development/consumer-chain-governance",component:p("/interchain-security/legacy/v3.1.0/consumer-development/consumer-chain-governance","cad"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/consumer-development/consumer-chain-upgrade-procedure",component:p("/interchain-security/legacy/v3.1.0/consumer-development/consumer-chain-upgrade-procedure","064"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/consumer-development/offboarding",component:p("/interchain-security/legacy/v3.1.0/consumer-development/offboarding","d07"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/consumer-development/onboarding",component:p("/interchain-security/legacy/v3.1.0/consumer-development/onboarding","b9c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/faq",component:p("/interchain-security/legacy/v3.1.0/faq","659"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/features/key-assignment",component:p("/interchain-security/legacy/v3.1.0/features/key-assignment","003"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/features/proposals",component:p("/interchain-security/legacy/v3.1.0/features/proposals","ee4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/features/reward-distribution",component:p("/interchain-security/legacy/v3.1.0/features/reward-distribution","34c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/features/slashing",component:p("/interchain-security/legacy/v3.1.0/features/slashing","320"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/introduction/overview",component:p("/interchain-security/legacy/v3.1.0/introduction/overview","b7f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/introduction/params",component:p("/interchain-security/legacy/v3.1.0/introduction/params","bb2"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/introduction/technical-specification",component:p("/interchain-security/legacy/v3.1.0/introduction/technical-specification","311"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/introduction/terminology",component:p("/interchain-security/legacy/v3.1.0/introduction/terminology","ed9"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/validators/joining-testnet",component:p("/interchain-security/legacy/v3.1.0/validators/joining-testnet","b27"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/validators/overview",component:p("/interchain-security/legacy/v3.1.0/validators/overview","900"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.1.0/validators/withdraw_rewards",component:p("/interchain-security/legacy/v3.1.0/validators/withdraw_rewards","12e"),exact:!0,sidebar:"tutorialSidebar"}]},{path:"/interchain-security/legacy/v3.2.0",component:p("/interchain-security/legacy/v3.2.0","c46"),routes:[{path:"/interchain-security/legacy/v3.2.0",component:p("/interchain-security/legacy/v3.2.0","640"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/adrs/adr-001-key-assignment",component:p("/interchain-security/legacy/v3.2.0/adrs/adr-001-key-assignment","464"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/adrs/adr-002-throttle",component:p("/interchain-security/legacy/v3.2.0/adrs/adr-002-throttle","0cb"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/adrs/adr-003-equivocation-gov-proposal",component:p("/interchain-security/legacy/v3.2.0/adrs/adr-003-equivocation-gov-proposal","512"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/adrs/adr-005-cryptographic-equivocation-verification",component:p("/interchain-security/legacy/v3.2.0/adrs/adr-005-cryptographic-equivocation-verification","f41"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop",component:p("/interchain-security/legacy/v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop","51d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/adrs/adr-008-throttle-retries",component:p("/interchain-security/legacy/v3.2.0/adrs/adr-008-throttle-retries","885"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/adrs/adr-009-soft-opt-out",component:p("/interchain-security/legacy/v3.2.0/adrs/adr-009-soft-opt-out","38a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/adrs/adr-010-standalone-changeover",component:p("/interchain-security/legacy/v3.2.0/adrs/adr-010-standalone-changeover","a5e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/adrs/adr-011-improving-test-confidence",component:p("/interchain-security/legacy/v3.2.0/adrs/adr-011-improving-test-confidence","257"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/adrs/adr-012-separate-releasing",component:p("/interchain-security/legacy/v3.2.0/adrs/adr-012-separate-releasing","5cc"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/adrs/adr-013-equivocation-slashing",component:p("/interchain-security/legacy/v3.2.0/adrs/adr-013-equivocation-slashing","dd5"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/adrs/adr-template",component:p("/interchain-security/legacy/v3.2.0/adrs/adr-template","5d8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/adrs/intro",component:p("/interchain-security/legacy/v3.2.0/adrs/intro","bad"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/consumer-development/app-integration",component:p("/interchain-security/legacy/v3.2.0/consumer-development/app-integration","b98"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/consumer-development/changeover-procedure",component:p("/interchain-security/legacy/v3.2.0/consumer-development/changeover-procedure","82c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/consumer-development/consumer-chain-governance",component:p("/interchain-security/legacy/v3.2.0/consumer-development/consumer-chain-governance","fb8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/consumer-development/offboarding",component:p("/interchain-security/legacy/v3.2.0/consumer-development/offboarding","5cc"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/consumer-development/onboarding",component:p("/interchain-security/legacy/v3.2.0/consumer-development/onboarding","930"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/faq",component:p("/interchain-security/legacy/v3.2.0/faq","d72"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/features/key-assignment",component:p("/interchain-security/legacy/v3.2.0/features/key-assignment","e02"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/features/proposals",component:p("/interchain-security/legacy/v3.2.0/features/proposals","3d6"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/features/reward-distribution",component:p("/interchain-security/legacy/v3.2.0/features/reward-distribution","827"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/features/slashing",component:p("/interchain-security/legacy/v3.2.0/features/slashing","452"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/introduction/overview",component:p("/interchain-security/legacy/v3.2.0/introduction/overview","18d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/introduction/params",component:p("/interchain-security/legacy/v3.2.0/introduction/params","5d1"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/introduction/technical-specification",component:p("/interchain-security/legacy/v3.2.0/introduction/technical-specification","e88"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/introduction/terminology",component:p("/interchain-security/legacy/v3.2.0/introduction/terminology","b1d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/validators/changeover-procedure",component:p("/interchain-security/legacy/v3.2.0/validators/changeover-procedure","749"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/validators/joining-neutron",component:p("/interchain-security/legacy/v3.2.0/validators/joining-neutron","17a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/validators/joining-stride",component:p("/interchain-security/legacy/v3.2.0/validators/joining-stride","f3e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/validators/joining-testnet",component:p("/interchain-security/legacy/v3.2.0/validators/joining-testnet","333"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/validators/overview",component:p("/interchain-security/legacy/v3.2.0/validators/overview","2bb"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.2.0/validators/withdraw_rewards",component:p("/interchain-security/legacy/v3.2.0/validators/withdraw_rewards","d5a"),exact:!0,sidebar:"tutorialSidebar"}]},{path:"/interchain-security/legacy/v3.3.0",component:p("/interchain-security/legacy/v3.3.0","9cf"),routes:[{path:"/interchain-security/legacy/v3.3.0",component:p("/interchain-security/legacy/v3.3.0","f70"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/adrs/adr-001-key-assignment",component:p("/interchain-security/legacy/v3.3.0/adrs/adr-001-key-assignment","48c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/adrs/adr-002-throttle",component:p("/interchain-security/legacy/v3.3.0/adrs/adr-002-throttle","d72"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/adrs/adr-003-equivocation-gov-proposal",component:p("/interchain-security/legacy/v3.3.0/adrs/adr-003-equivocation-gov-proposal","f17"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/adrs/adr-005-cryptographic-equivocation-verification",component:p("/interchain-security/legacy/v3.3.0/adrs/adr-005-cryptographic-equivocation-verification","f75"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-prop",component:p("/interchain-security/legacy/v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-prop","6bd"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/adrs/adr-008-throttle-retries",component:p("/interchain-security/legacy/v3.3.0/adrs/adr-008-throttle-retries","a7f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/adrs/adr-009-soft-opt-out",component:p("/interchain-security/legacy/v3.3.0/adrs/adr-009-soft-opt-out","ab2"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/adrs/adr-010-standalone-changeover",component:p("/interchain-security/legacy/v3.3.0/adrs/adr-010-standalone-changeover","236"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/adrs/adr-011-improving-test-confidence",component:p("/interchain-security/legacy/v3.3.0/adrs/adr-011-improving-test-confidence","102"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/adrs/adr-012-separate-releasing",component:p("/interchain-security/legacy/v3.3.0/adrs/adr-012-separate-releasing","ee8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/adrs/adr-013-equivocation-slashing",component:p("/interchain-security/legacy/v3.3.0/adrs/adr-013-equivocation-slashing","f7e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/adrs/adr-template",component:p("/interchain-security/legacy/v3.3.0/adrs/adr-template","5f0"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/adrs/intro",component:p("/interchain-security/legacy/v3.3.0/adrs/intro","496"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/consumer-development/app-integration",component:p("/interchain-security/legacy/v3.3.0/consumer-development/app-integration","fb3"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/consumer-development/changeover-procedure",component:p("/interchain-security/legacy/v3.3.0/consumer-development/changeover-procedure","8d0"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/consumer-development/consumer-chain-governance",component:p("/interchain-security/legacy/v3.3.0/consumer-development/consumer-chain-governance","ee6"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/consumer-development/consumer-genesis-transformation",component:p("/interchain-security/legacy/v3.3.0/consumer-development/consumer-genesis-transformation","5e3"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/consumer-development/offboarding",component:p("/interchain-security/legacy/v3.3.0/consumer-development/offboarding","be8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/consumer-development/onboarding",component:p("/interchain-security/legacy/v3.3.0/consumer-development/onboarding","28d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/faq",component:p("/interchain-security/legacy/v3.3.0/faq","282"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/features/key-assignment",component:p("/interchain-security/legacy/v3.3.0/features/key-assignment","272"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/features/proposals",component:p("/interchain-security/legacy/v3.3.0/features/proposals","013"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/features/reward-distribution",component:p("/interchain-security/legacy/v3.3.0/features/reward-distribution","019"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/features/slashing",component:p("/interchain-security/legacy/v3.3.0/features/slashing","10c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/introduction/overview",component:p("/interchain-security/legacy/v3.3.0/introduction/overview","496"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/introduction/params",component:p("/interchain-security/legacy/v3.3.0/introduction/params","eb9"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/introduction/technical-specification",component:p("/interchain-security/legacy/v3.3.0/introduction/technical-specification","280"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/introduction/terminology",component:p("/interchain-security/legacy/v3.3.0/introduction/terminology","a84"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/validators/changeover-procedure",component:p("/interchain-security/legacy/v3.3.0/validators/changeover-procedure","77f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/validators/joining-neutron",component:p("/interchain-security/legacy/v3.3.0/validators/joining-neutron","24b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/validators/joining-stride",component:p("/interchain-security/legacy/v3.3.0/validators/joining-stride","8cc"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/validators/joining-testnet",component:p("/interchain-security/legacy/v3.3.0/validators/joining-testnet","e9f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/validators/overview",component:p("/interchain-security/legacy/v3.3.0/validators/overview","8ee"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/v3.3.0/validators/withdraw_rewards",component:p("/interchain-security/legacy/v3.3.0/validators/withdraw_rewards","099"),exact:!0,sidebar:"tutorialSidebar"}]},{path:"/interchain-security/legacy/",component:p("/interchain-security/legacy/","d62"),routes:[{path:"/interchain-security/legacy/",component:p("/interchain-security/legacy/","58a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-001-key-assignment",component:p("/interchain-security/legacy/adrs/adr-001-key-assignment","732"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-002-throttle",component:p("/interchain-security/legacy/adrs/adr-002-throttle","f62"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposal",component:p("/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposal","152"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification",component:p("/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification","562"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop",component:p("/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop","3a0"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-008-throttle-retries",component:p("/interchain-security/legacy/adrs/adr-008-throttle-retries","680"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-009-soft-opt-out",component:p("/interchain-security/legacy/adrs/adr-009-soft-opt-out","03f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-010-standalone-changeover",component:p("/interchain-security/legacy/adrs/adr-010-standalone-changeover","db5"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-011-improving-test-confidence",component:p("/interchain-security/legacy/adrs/adr-011-improving-test-confidence","291"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-012-separate-releasing",component:p("/interchain-security/legacy/adrs/adr-012-separate-releasing","f11"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-013-equivocation-slashing",component:p("/interchain-security/legacy/adrs/adr-013-equivocation-slashing","f27"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-template",component:p("/interchain-security/legacy/adrs/adr-template","cb2"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/intro",component:p("/interchain-security/legacy/adrs/intro","5f0"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/consumer-development/app-integration",component:p("/interchain-security/legacy/consumer-development/app-integration","48d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/consumer-development/changeover-procedure",component:p("/interchain-security/legacy/consumer-development/changeover-procedure","396"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/consumer-development/consumer-chain-governance",component:p("/interchain-security/legacy/consumer-development/consumer-chain-governance","781"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/consumer-development/consumer-genesis-transformation",component:p("/interchain-security/legacy/consumer-development/consumer-genesis-transformation","33c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/consumer-development/offboarding",component:p("/interchain-security/legacy/consumer-development/offboarding","9fa"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/consumer-development/onboarding",component:p("/interchain-security/legacy/consumer-development/onboarding","cba"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/faq",component:p("/interchain-security/legacy/faq","5c6"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/features/key-assignment",component:p("/interchain-security/legacy/features/key-assignment","b63"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/features/proposals",component:p("/interchain-security/legacy/features/proposals","723"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/features/reward-distribution",component:p("/interchain-security/legacy/features/reward-distribution","c52"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/features/slashing",component:p("/interchain-security/legacy/features/slashing","f1b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/introduction/overview",component:p("/interchain-security/legacy/introduction/overview","266"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/introduction/params",component:p("/interchain-security/legacy/introduction/params","f1d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/introduction/technical-specification",component:p("/interchain-security/legacy/introduction/technical-specification","7d6"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/introduction/terminology",component:p("/interchain-security/legacy/introduction/terminology","c3d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/validators/changeover-procedure",component:p("/interchain-security/legacy/validators/changeover-procedure","b84"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/validators/joining-neutron",component:p("/interchain-security/legacy/validators/joining-neutron","748"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/validators/joining-stride",component:p("/interchain-security/legacy/validators/joining-stride","1b1"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/validators/joining-testnet",component:p("/interchain-security/legacy/validators/joining-testnet","fed"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/validators/overview",component:p("/interchain-security/legacy/validators/overview","f2e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/validators/withdraw_rewards",component:p("/interchain-security/legacy/validators/withdraw_rewards","ee9"),exact:!0,sidebar:"tutorialSidebar"}]},{path:"/interchain-security/legacy/",component:p("/interchain-security/legacy/","e1e"),routes:[{path:"/interchain-security/legacy/",component:p("/interchain-security/legacy/","5c8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-001-key-assignment",component:p("/interchain-security/legacy/adrs/adr-001-key-assignment","37f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-002-throttle",component:p("/interchain-security/legacy/adrs/adr-002-throttle","07f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposal",component:p("/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposal","5c0"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification",component:p("/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification","f98"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop",component:p("/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop","9b1"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-008-throttle-retries",component:p("/interchain-security/legacy/adrs/adr-008-throttle-retries","82c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-009-soft-opt-out",component:p("/interchain-security/legacy/adrs/adr-009-soft-opt-out","89d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-010-standalone-changeover",component:p("/interchain-security/legacy/adrs/adr-010-standalone-changeover","2a8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-011-improving-test-confidence",component:p("/interchain-security/legacy/adrs/adr-011-improving-test-confidence","281"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-012-separate-releasing",component:p("/interchain-security/legacy/adrs/adr-012-separate-releasing","e45"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-013-equivocation-slashing",component:p("/interchain-security/legacy/adrs/adr-013-equivocation-slashing","66d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/adr-template",component:p("/interchain-security/legacy/adrs/adr-template","cfe"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/adrs/intro",component:p("/interchain-security/legacy/adrs/intro","6dd"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/consumer-development/app-integration",component:p("/interchain-security/legacy/consumer-development/app-integration","07c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/consumer-development/changeover-procedure",component:p("/interchain-security/legacy/consumer-development/changeover-procedure","cbe"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/consumer-development/consumer-chain-governance",component:p("/interchain-security/legacy/consumer-development/consumer-chain-governance","de2"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/consumer-development/consumer-genesis-transformation",component:p("/interchain-security/legacy/consumer-development/consumer-genesis-transformation","585"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/consumer-development/offboarding",component:p("/interchain-security/legacy/consumer-development/offboarding","60b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/consumer-development/onboarding",component:p("/interchain-security/legacy/consumer-development/onboarding","1b2"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/faq",component:p("/interchain-security/legacy/faq","401"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/features/key-assignment",component:p("/interchain-security/legacy/features/key-assignment","17f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/features/proposals",component:p("/interchain-security/legacy/features/proposals","fc4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/features/reward-distribution",component:p("/interchain-security/legacy/features/reward-distribution","6fe"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/features/slashing",component:p("/interchain-security/legacy/features/slashing","534"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/introduction/overview",component:p("/interchain-security/legacy/introduction/overview","32a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/introduction/params",component:p("/interchain-security/legacy/introduction/params","022"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/introduction/technical-specification",component:p("/interchain-security/legacy/introduction/technical-specification","82e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/introduction/terminology",component:p("/interchain-security/legacy/introduction/terminology","e3d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/validators/changeover-procedure",component:p("/interchain-security/legacy/validators/changeover-procedure","a77"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/validators/joining-neutron",component:p("/interchain-security/legacy/validators/joining-neutron","2bd"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/validators/joining-stride",component:p("/interchain-security/legacy/validators/joining-stride","bba"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/validators/joining-testnet",component:p("/interchain-security/legacy/validators/joining-testnet","8dc"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/validators/overview",component:p("/interchain-security/legacy/validators/overview","fbc"),exact:!0,sidebar:"tutorialSidebar"},{path:"/interchain-security/legacy/validators/withdraw_rewards",component:p("/interchain-security/legacy/validators/withdraw_rewards","b4f"),exact:!0,sidebar:"tutorialSidebar"}]},{path:"*",component:p("*")}]},8934:(e,t,n)=>{"use strict";n.d(t,{_:()=>a,t:()=>i});var r=n(7294);const a=r.createContext(!1);function i(e){let{children:t}=e;const[n,i]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{i(!0)}),[]),r.createElement(a.Provider,{value:n},t)}},9383:(e,t,n)=>{"use strict";var r=n(7294),a=n(3935),i=n(3727),o=n(405),s=n(412);const c=[n(2497),n(3310),n(8320),n(2295)];var l=n(723),u=n(6550),d=n(8790);function p(e){let{children:t}=e;return r.createElement(r.Fragment,null,t)}var f=n(7462),m=n(5742),h=n(2263),g=n(4996),v=n(6668),y=n(1944),b=n(4711),w=n(9727),_=n(3320),S=n(197);function k(){const{i18n:{defaultLocale:e,localeConfigs:t}}=(0,h.Z)(),n=(0,b.l)();return r.createElement(m.Z,null,Object.entries(t).map((e=>{let[t,{htmlLang:a}]=e;return r.createElement("link",{key:t,rel:"alternate",href:n.createUrl({locale:t,fullyQualified:!0}),hrefLang:a})})),r.createElement("link",{rel:"alternate",href:n.createUrl({locale:e,fullyQualified:!0}),hrefLang:"x-default"}))}function E(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,h.Z)(),a=function(){const{siteConfig:{url:e}}=(0,h.Z)(),{pathname:t}=(0,u.TH)();return e+(0,g.Z)(t)}(),i=t?`${n}${t}`:a;return r.createElement(m.Z,null,r.createElement("meta",{property:"og:url",content:i}),r.createElement("link",{rel:"canonical",href:i}))}function x(){const{i18n:{currentLocale:e}}=(0,h.Z)(),{metadata:t,image:n}=(0,v.L)();return r.createElement(r.Fragment,null,r.createElement(m.Z,null,r.createElement("meta",{name:"twitter:card",content:"summary_large_image"}),r.createElement("body",{className:w.h})),n&&r.createElement(y.d,{image:n}),r.createElement(E,null),r.createElement(k,null),r.createElement(S.Z,{tag:_.HX,locale:e}),r.createElement(m.Z,null,t.map(((e,t)=>r.createElement("meta",(0,f.Z)({key:t},e))))))}const C=new Map;function T(e){if(C.has(e.pathname))return{...e,pathname:C.get(e.pathname)};if((0,d.f)(l.Z,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return C.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return C.set(e.pathname,t),{...e,pathname:t}}var L=n(8934),A=n(8940);function N(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r<t;r++)n[r-1]=arguments[r];const a=c.map((t=>{const r=t.default?.[e]??t[e];return r?.(...n)}));return()=>a.forEach((e=>e?.()))}const O=function(e){let{children:t,location:n,previousLocation:a}=e;return(0,r.useLayoutEffect)((()=>{a!==n&&(!function(e){let{location:t,previousLocation:n}=e;if(!n)return;const r=t.pathname===n.pathname,a=t.hash===n.hash,i=t.search===n.search;if(r&&a&&!i)return;const{hash:o}=t;if(o){const e=decodeURIComponent(o.substring(1)),t=document.getElementById(e);t?.scrollIntoView()}else window.scrollTo(0,0)}({location:n,previousLocation:a}),N("onRouteDidUpdate",{previousLocation:a,location:n}))}),[a,n]),t};function P(e){const t=Array.from(new Set([e,decodeURI(e)])).map((e=>(0,d.f)(l.Z,e))).flat();return Promise.all(t.map((e=>e.route.component.preload?.())))}class I extends r.Component{constructor(e){super(e),this.previousLocation=void 0,this.routeUpdateCleanupCb=void 0,this.previousLocation=null,this.routeUpdateCleanupCb=s.Z.canUseDOM?N("onRouteUpdate",{previousLocation:null,location:this.props.location}):()=>{},this.state={nextRouteHasLoaded:!0}}shouldComponentUpdate(e,t){if(e.location===this.props.location)return t.nextRouteHasLoaded;const n=e.location;return this.previousLocation=this.props.location,this.setState({nextRouteHasLoaded:!1}),this.routeUpdateCleanupCb=N("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),P(n.pathname).then((()=>{this.routeUpdateCleanupCb(),this.setState({nextRouteHasLoaded:!0})})).catch((e=>{console.warn(e),window.location.reload()})),!1}render(){const{children:e,location:t}=this.props;return r.createElement(O,{previousLocation:this.previousLocation,location:t},r.createElement(u.AW,{location:t,render:()=>e}))}}const R=I,M="__docusaurus-base-url-issue-banner-container",D="__docusaurus-base-url-issue-banner",F="__docusaurus-base-url-issue-banner-suggestion-container",B="__DOCUSAURUS_INSERT_BASEURL_BANNER";function j(e){return`\nwindow['${B}'] = true;\n\ndocument.addEventListener('DOMContentLoaded', maybeInsertBanner);\n\nfunction maybeInsertBanner() {\n var shouldInsert = window['${B}'];\n shouldInsert && insertBanner();\n}\n\nfunction insertBanner() {\n var bannerContainer = document.getElementById('${M}');\n if (!bannerContainer) {\n return;\n }\n var bannerHtml = ${JSON.stringify(function(e){return`\n<div id="${D}" style="border: thick solid red; background-color: rgb(255, 230, 179); margin: 20px; padding: 20px; font-size: 20px;">\n <p style="font-weight: bold; font-size: 30px;">Your Docusaurus site did not load properly.</p>\n <p>A very common reason is a wrong site <a href="https://docusaurus.io/docs/docusaurus.config.js/#baseUrl" style="font-weight: bold;">baseUrl configuration</a>.</p>\n <p>Current configured baseUrl = <span style="font-weight: bold; color: red;">${e}</span> ${"/"===e?" (default value)":""}</p>\n <p>We suggest trying baseUrl = <span id="${F}" style="font-weight: bold; color: green;"></span></p>\n</div>\n`}(e)).replace(/</g,"\\<")};\n bannerContainer.innerHTML = bannerHtml;\n var suggestionContainer = document.getElementById('${F}');\n var actualHomePagePath = window.location.pathname;\n var suggestedBaseUrl = actualHomePagePath.substr(-1) === '/'\n ? actualHomePagePath\n : actualHomePagePath + '/';\n suggestionContainer.innerHTML = suggestedBaseUrl;\n}\n`}function $(){const{siteConfig:{baseUrl:e}}=(0,h.Z)();return(0,r.useLayoutEffect)((()=>{window[B]=!1}),[]),r.createElement(r.Fragment,null,!s.Z.canUseDOM&&r.createElement(m.Z,null,r.createElement("script",null,j(e))),r.createElement("div",{id:M}))}function z(){const{siteConfig:{baseUrl:e,baseUrlIssueBanner:t}}=(0,h.Z)(),{pathname:n}=(0,u.TH)();return t&&n===e?r.createElement($,null):null}function U(){const{siteConfig:{favicon:e,title:t,noIndex:n},i18n:{currentLocale:a,localeConfigs:i}}=(0,h.Z)(),o=(0,g.Z)(e),{htmlLang:s,direction:c}=i[a];return r.createElement(m.Z,null,r.createElement("html",{lang:s,dir:c}),r.createElement("title",null,t),r.createElement("meta",{property:"og:title",content:t}),r.createElement("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0"}),n&&r.createElement("meta",{name:"robots",content:"noindex, nofollow"}),e&&r.createElement("link",{rel:"icon",href:o}))}var q=n(4763);function Z(){const e=(0,d.H)(l.Z),t=(0,u.TH)();return r.createElement(q.Z,null,r.createElement(A.M,null,r.createElement(L.t,null,r.createElement(p,null,r.createElement(U,null),r.createElement(x,null),r.createElement(z,null),r.createElement(R,{location:T(t)},e)))))}var H=n(6887);const V=function(e){try{return document.createElement("link").relList.supports(e)}catch{return!1}}("prefetch")?function(e){return new Promise(((t,n)=>{if("undefined"==typeof document)return void n();const r=document.createElement("link");r.setAttribute("rel","prefetch"),r.setAttribute("href",e),r.onload=()=>t(),r.onerror=()=>n();const a=document.getElementsByTagName("head")[0]??document.getElementsByName("script")[0]?.parentNode;a?.appendChild(r)}))}:function(e){return new Promise(((t,n)=>{const r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=()=>{200===r.status?t():n()},r.send(null)}))};var W=n(9670);const G=new Set,Y=new Set,K=()=>navigator.connection?.effectiveType.includes("2g")||navigator.connection?.saveData,X={prefetch(e){if(!(e=>!K()&&!Y.has(e)&&!G.has(e))(e))return!1;G.add(e);const t=(0,d.f)(l.Z,e).flatMap((e=>{return t=e.route.path,Object.entries(H).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,W.Z)(t))}));var t}));return Promise.all(t.map((e=>{const t=n.gca(e);return t&&!t.includes("undefined")?V(t).catch((()=>{})):Promise.resolve()})))},preload:e=>!!(e=>!K()&&!Y.has(e))(e)&&(Y.add(e),P(e))},Q=Object.freeze(X);if(s.Z.canUseDOM){window.docusaurus=Q;const e=a.hydrate;P(window.location.pathname).then((()=>{e(r.createElement(o.B6,null,r.createElement(i.VK,null,r.createElement(Z,null))),document.getElementById("__docusaurus"))}))}},8940:(e,t,n)=>{"use strict";n.d(t,{_:()=>u,M:()=>d});var r=n(7294),a=n(6809);const i=JSON.parse('{"docusaurus-plugin-content-docs":{"default":{"path":"/interchain-security/legacy/","versions":[{"name":"current","label":"Next","isLast":false,"path":"/interchain-security/legacy/","mainDocId":"index","docs":[{"id":"adrs/adr-001-key-assignment","path":"/interchain-security/legacy/adrs/adr-001-key-assignment","sidebar":"tutorialSidebar"},{"id":"adrs/adr-002-throttle","path":"/interchain-security/legacy/adrs/adr-002-throttle","sidebar":"tutorialSidebar"},{"id":"adrs/adr-003-equivocation-gov-proposal","path":"/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposal","sidebar":"tutorialSidebar"},{"id":"adrs/adr-005-cryptographic-equivocation-verification","path":"/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification","sidebar":"tutorialSidebar"},{"id":"adrs/adr-007-pause-unbonding-on-eqv-prop","path":"/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop","sidebar":"tutorialSidebar"},{"id":"adrs/adr-008-throttle-retries","path":"/interchain-security/legacy/adrs/adr-008-throttle-retries","sidebar":"tutorialSidebar"},{"id":"adrs/adr-009-soft-opt-out","path":"/interchain-security/legacy/adrs/adr-009-soft-opt-out","sidebar":"tutorialSidebar"},{"id":"adrs/adr-010-standalone-changeover","path":"/interchain-security/legacy/adrs/adr-010-standalone-changeover","sidebar":"tutorialSidebar"},{"id":"adrs/adr-011-improving-test-confidence","path":"/interchain-security/legacy/adrs/adr-011-improving-test-confidence","sidebar":"tutorialSidebar"},{"id":"adrs/adr-012-separate-releasing","path":"/interchain-security/legacy/adrs/adr-012-separate-releasing","sidebar":"tutorialSidebar"},{"id":"adrs/adr-013-equivocation-slashing","path":"/interchain-security/legacy/adrs/adr-013-equivocation-slashing","sidebar":"tutorialSidebar"},{"id":"adrs/adr-template","path":"/interchain-security/legacy/adrs/adr-template","sidebar":"tutorialSidebar"},{"id":"adrs/intro","path":"/interchain-security/legacy/adrs/intro","sidebar":"tutorialSidebar"},{"id":"consumer-development/app-integration","path":"/interchain-security/legacy/consumer-development/app-integration","sidebar":"tutorialSidebar"},{"id":"consumer-development/changeover-procedure","path":"/interchain-security/legacy/consumer-development/changeover-procedure","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-chain-governance","path":"/interchain-security/legacy/consumer-development/consumer-chain-governance","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-genesis-transformation","path":"/interchain-security/legacy/consumer-development/consumer-genesis-transformation","sidebar":"tutorialSidebar"},{"id":"consumer-development/offboarding","path":"/interchain-security/legacy/consumer-development/offboarding","sidebar":"tutorialSidebar"},{"id":"consumer-development/onboarding","path":"/interchain-security/legacy/consumer-development/onboarding","sidebar":"tutorialSidebar"},{"id":"features/key-assignment","path":"/interchain-security/legacy/features/key-assignment","sidebar":"tutorialSidebar"},{"id":"features/proposals","path":"/interchain-security/legacy/features/proposals","sidebar":"tutorialSidebar"},{"id":"features/reward-distribution","path":"/interchain-security/legacy/features/reward-distribution","sidebar":"tutorialSidebar"},{"id":"features/slashing","path":"/interchain-security/legacy/features/slashing","sidebar":"tutorialSidebar"},{"id":"frequently-asked-questions","path":"/interchain-security/legacy/faq","sidebar":"tutorialSidebar"},{"id":"index","path":"/interchain-security/legacy/","sidebar":"tutorialSidebar"},{"id":"introduction/overview","path":"/interchain-security/legacy/introduction/overview","sidebar":"tutorialSidebar"},{"id":"introduction/params","path":"/interchain-security/legacy/introduction/params","sidebar":"tutorialSidebar"},{"id":"introduction/technical-specification","path":"/interchain-security/legacy/introduction/technical-specification","sidebar":"tutorialSidebar"},{"id":"introduction/terminology","path":"/interchain-security/legacy/introduction/terminology","sidebar":"tutorialSidebar"},{"id":"validators/changeover-procedure","path":"/interchain-security/legacy/validators/changeover-procedure","sidebar":"tutorialSidebar"},{"id":"validators/joining-neutron","path":"/interchain-security/legacy/validators/joining-neutron","sidebar":"tutorialSidebar"},{"id":"validators/joining-stride","path":"/interchain-security/legacy/validators/joining-stride","sidebar":"tutorialSidebar"},{"id":"validators/joining-testnet","path":"/interchain-security/legacy/validators/joining-testnet","sidebar":"tutorialSidebar"},{"id":"validators/overview","path":"/interchain-security/legacy/validators/overview","sidebar":"tutorialSidebar"},{"id":"validators/withdraw_rewards","path":"/interchain-security/legacy/validators/withdraw_rewards","sidebar":"tutorialSidebar"}],"draftIds":[],"sidebars":{"tutorialSidebar":{"link":{"path":"/interchain-security/legacy/","label":"index"}}}},{"name":"v3.3.1-lsm","label":"v3.3.1-lsm","isLast":true,"path":"/interchain-security/legacy/","mainDocId":"index","docs":[{"id":"adrs/adr-001-key-assignment","path":"/interchain-security/legacy/adrs/adr-001-key-assignment","sidebar":"tutorialSidebar"},{"id":"adrs/adr-002-throttle","path":"/interchain-security/legacy/adrs/adr-002-throttle","sidebar":"tutorialSidebar"},{"id":"adrs/adr-003-equivocation-gov-proposal","path":"/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposal","sidebar":"tutorialSidebar"},{"id":"adrs/adr-005-cryptographic-equivocation-verification","path":"/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification","sidebar":"tutorialSidebar"},{"id":"adrs/adr-007-pause-unbonding-on-eqv-prop","path":"/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop","sidebar":"tutorialSidebar"},{"id":"adrs/adr-008-throttle-retries","path":"/interchain-security/legacy/adrs/adr-008-throttle-retries","sidebar":"tutorialSidebar"},{"id":"adrs/adr-009-soft-opt-out","path":"/interchain-security/legacy/adrs/adr-009-soft-opt-out","sidebar":"tutorialSidebar"},{"id":"adrs/adr-010-standalone-changeover","path":"/interchain-security/legacy/adrs/adr-010-standalone-changeover","sidebar":"tutorialSidebar"},{"id":"adrs/adr-011-improving-test-confidence","path":"/interchain-security/legacy/adrs/adr-011-improving-test-confidence","sidebar":"tutorialSidebar"},{"id":"adrs/adr-012-separate-releasing","path":"/interchain-security/legacy/adrs/adr-012-separate-releasing","sidebar":"tutorialSidebar"},{"id":"adrs/adr-013-equivocation-slashing","path":"/interchain-security/legacy/adrs/adr-013-equivocation-slashing","sidebar":"tutorialSidebar"},{"id":"adrs/adr-template","path":"/interchain-security/legacy/adrs/adr-template","sidebar":"tutorialSidebar"},{"id":"adrs/intro","path":"/interchain-security/legacy/adrs/intro","sidebar":"tutorialSidebar"},{"id":"consumer-development/app-integration","path":"/interchain-security/legacy/consumer-development/app-integration","sidebar":"tutorialSidebar"},{"id":"consumer-development/changeover-procedure","path":"/interchain-security/legacy/consumer-development/changeover-procedure","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-chain-governance","path":"/interchain-security/legacy/consumer-development/consumer-chain-governance","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-genesis-transformation","path":"/interchain-security/legacy/consumer-development/consumer-genesis-transformation","sidebar":"tutorialSidebar"},{"id":"consumer-development/offboarding","path":"/interchain-security/legacy/consumer-development/offboarding","sidebar":"tutorialSidebar"},{"id":"consumer-development/onboarding","path":"/interchain-security/legacy/consumer-development/onboarding","sidebar":"tutorialSidebar"},{"id":"features/key-assignment","path":"/interchain-security/legacy/features/key-assignment","sidebar":"tutorialSidebar"},{"id":"features/proposals","path":"/interchain-security/legacy/features/proposals","sidebar":"tutorialSidebar"},{"id":"features/reward-distribution","path":"/interchain-security/legacy/features/reward-distribution","sidebar":"tutorialSidebar"},{"id":"features/slashing","path":"/interchain-security/legacy/features/slashing","sidebar":"tutorialSidebar"},{"id":"frequently-asked-questions","path":"/interchain-security/legacy/faq","sidebar":"tutorialSidebar"},{"id":"index","path":"/interchain-security/legacy/","sidebar":"tutorialSidebar"},{"id":"introduction/overview","path":"/interchain-security/legacy/introduction/overview","sidebar":"tutorialSidebar"},{"id":"introduction/params","path":"/interchain-security/legacy/introduction/params","sidebar":"tutorialSidebar"},{"id":"introduction/technical-specification","path":"/interchain-security/legacy/introduction/technical-specification","sidebar":"tutorialSidebar"},{"id":"introduction/terminology","path":"/interchain-security/legacy/introduction/terminology","sidebar":"tutorialSidebar"},{"id":"validators/changeover-procedure","path":"/interchain-security/legacy/validators/changeover-procedure","sidebar":"tutorialSidebar"},{"id":"validators/joining-neutron","path":"/interchain-security/legacy/validators/joining-neutron","sidebar":"tutorialSidebar"},{"id":"validators/joining-stride","path":"/interchain-security/legacy/validators/joining-stride","sidebar":"tutorialSidebar"},{"id":"validators/joining-testnet","path":"/interchain-security/legacy/validators/joining-testnet","sidebar":"tutorialSidebar"},{"id":"validators/overview","path":"/interchain-security/legacy/validators/overview","sidebar":"tutorialSidebar"},{"id":"validators/withdraw_rewards","path":"/interchain-security/legacy/validators/withdraw_rewards","sidebar":"tutorialSidebar"}],"draftIds":[],"sidebars":{"tutorialSidebar":{"link":{"path":"/interchain-security/legacy/","label":"version-v3.3.1-lsm/index"}}}},{"name":"v3.3.0","label":"v3.3.0","isLast":false,"path":"/interchain-security/legacy/v3.3.0","mainDocId":"index","docs":[{"id":"adrs/adr-001-key-assignment","path":"/interchain-security/legacy/v3.3.0/adrs/adr-001-key-assignment","sidebar":"tutorialSidebar"},{"id":"adrs/adr-002-throttle","path":"/interchain-security/legacy/v3.3.0/adrs/adr-002-throttle","sidebar":"tutorialSidebar"},{"id":"adrs/adr-003-equivocation-gov-proposal","path":"/interchain-security/legacy/v3.3.0/adrs/adr-003-equivocation-gov-proposal","sidebar":"tutorialSidebar"},{"id":"adrs/adr-005-cryptographic-equivocation-verification","path":"/interchain-security/legacy/v3.3.0/adrs/adr-005-cryptographic-equivocation-verification","sidebar":"tutorialSidebar"},{"id":"adrs/adr-007-pause-unbonding-on-eqv-prop","path":"/interchain-security/legacy/v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-prop","sidebar":"tutorialSidebar"},{"id":"adrs/adr-008-throttle-retries","path":"/interchain-security/legacy/v3.3.0/adrs/adr-008-throttle-retries","sidebar":"tutorialSidebar"},{"id":"adrs/adr-009-soft-opt-out","path":"/interchain-security/legacy/v3.3.0/adrs/adr-009-soft-opt-out","sidebar":"tutorialSidebar"},{"id":"adrs/adr-010-standalone-changeover","path":"/interchain-security/legacy/v3.3.0/adrs/adr-010-standalone-changeover","sidebar":"tutorialSidebar"},{"id":"adrs/adr-011-improving-test-confidence","path":"/interchain-security/legacy/v3.3.0/adrs/adr-011-improving-test-confidence","sidebar":"tutorialSidebar"},{"id":"adrs/adr-012-separate-releasing","path":"/interchain-security/legacy/v3.3.0/adrs/adr-012-separate-releasing","sidebar":"tutorialSidebar"},{"id":"adrs/adr-013-equivocation-slashing","path":"/interchain-security/legacy/v3.3.0/adrs/adr-013-equivocation-slashing","sidebar":"tutorialSidebar"},{"id":"adrs/adr-template","path":"/interchain-security/legacy/v3.3.0/adrs/adr-template","sidebar":"tutorialSidebar"},{"id":"adrs/intro","path":"/interchain-security/legacy/v3.3.0/adrs/intro","sidebar":"tutorialSidebar"},{"id":"consumer-development/app-integration","path":"/interchain-security/legacy/v3.3.0/consumer-development/app-integration","sidebar":"tutorialSidebar"},{"id":"consumer-development/changeover-procedure","path":"/interchain-security/legacy/v3.3.0/consumer-development/changeover-procedure","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-chain-governance","path":"/interchain-security/legacy/v3.3.0/consumer-development/consumer-chain-governance","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-genesis-transformation","path":"/interchain-security/legacy/v3.3.0/consumer-development/consumer-genesis-transformation","sidebar":"tutorialSidebar"},{"id":"consumer-development/offboarding","path":"/interchain-security/legacy/v3.3.0/consumer-development/offboarding","sidebar":"tutorialSidebar"},{"id":"consumer-development/onboarding","path":"/interchain-security/legacy/v3.3.0/consumer-development/onboarding","sidebar":"tutorialSidebar"},{"id":"features/key-assignment","path":"/interchain-security/legacy/v3.3.0/features/key-assignment","sidebar":"tutorialSidebar"},{"id":"features/proposals","path":"/interchain-security/legacy/v3.3.0/features/proposals","sidebar":"tutorialSidebar"},{"id":"features/reward-distribution","path":"/interchain-security/legacy/v3.3.0/features/reward-distribution","sidebar":"tutorialSidebar"},{"id":"features/slashing","path":"/interchain-security/legacy/v3.3.0/features/slashing","sidebar":"tutorialSidebar"},{"id":"frequently-asked-questions","path":"/interchain-security/legacy/v3.3.0/faq","sidebar":"tutorialSidebar"},{"id":"index","path":"/interchain-security/legacy/v3.3.0/","sidebar":"tutorialSidebar"},{"id":"introduction/overview","path":"/interchain-security/legacy/v3.3.0/introduction/overview","sidebar":"tutorialSidebar"},{"id":"introduction/params","path":"/interchain-security/legacy/v3.3.0/introduction/params","sidebar":"tutorialSidebar"},{"id":"introduction/technical-specification","path":"/interchain-security/legacy/v3.3.0/introduction/technical-specification","sidebar":"tutorialSidebar"},{"id":"introduction/terminology","path":"/interchain-security/legacy/v3.3.0/introduction/terminology","sidebar":"tutorialSidebar"},{"id":"validators/changeover-procedure","path":"/interchain-security/legacy/v3.3.0/validators/changeover-procedure","sidebar":"tutorialSidebar"},{"id":"validators/joining-neutron","path":"/interchain-security/legacy/v3.3.0/validators/joining-neutron","sidebar":"tutorialSidebar"},{"id":"validators/joining-stride","path":"/interchain-security/legacy/v3.3.0/validators/joining-stride","sidebar":"tutorialSidebar"},{"id":"validators/joining-testnet","path":"/interchain-security/legacy/v3.3.0/validators/joining-testnet","sidebar":"tutorialSidebar"},{"id":"validators/overview","path":"/interchain-security/legacy/v3.3.0/validators/overview","sidebar":"tutorialSidebar"},{"id":"validators/withdraw_rewards","path":"/interchain-security/legacy/v3.3.0/validators/withdraw_rewards","sidebar":"tutorialSidebar"}],"draftIds":[],"sidebars":{"tutorialSidebar":{"link":{"path":"/interchain-security/legacy/v3.3.0/","label":"version-v3.3.0/index"}}}},{"name":"v3.2.0","label":"v3.2.0","isLast":false,"path":"/interchain-security/legacy/v3.2.0","mainDocId":"index","docs":[{"id":"adrs/adr-001-key-assignment","path":"/interchain-security/legacy/v3.2.0/adrs/adr-001-key-assignment","sidebar":"tutorialSidebar"},{"id":"adrs/adr-002-throttle","path":"/interchain-security/legacy/v3.2.0/adrs/adr-002-throttle","sidebar":"tutorialSidebar"},{"id":"adrs/adr-003-equivocation-gov-proposal","path":"/interchain-security/legacy/v3.2.0/adrs/adr-003-equivocation-gov-proposal","sidebar":"tutorialSidebar"},{"id":"adrs/adr-005-cryptographic-equivocation-verification","path":"/interchain-security/legacy/v3.2.0/adrs/adr-005-cryptographic-equivocation-verification","sidebar":"tutorialSidebar"},{"id":"adrs/adr-007-pause-unbonding-on-eqv-prop","path":"/interchain-security/legacy/v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop","sidebar":"tutorialSidebar"},{"id":"adrs/adr-008-throttle-retries","path":"/interchain-security/legacy/v3.2.0/adrs/adr-008-throttle-retries","sidebar":"tutorialSidebar"},{"id":"adrs/adr-009-soft-opt-out","path":"/interchain-security/legacy/v3.2.0/adrs/adr-009-soft-opt-out","sidebar":"tutorialSidebar"},{"id":"adrs/adr-010-standalone-changeover","path":"/interchain-security/legacy/v3.2.0/adrs/adr-010-standalone-changeover","sidebar":"tutorialSidebar"},{"id":"adrs/adr-011-improving-test-confidence","path":"/interchain-security/legacy/v3.2.0/adrs/adr-011-improving-test-confidence","sidebar":"tutorialSidebar"},{"id":"adrs/adr-012-separate-releasing","path":"/interchain-security/legacy/v3.2.0/adrs/adr-012-separate-releasing","sidebar":"tutorialSidebar"},{"id":"adrs/adr-013-equivocation-slashing","path":"/interchain-security/legacy/v3.2.0/adrs/adr-013-equivocation-slashing","sidebar":"tutorialSidebar"},{"id":"adrs/adr-template","path":"/interchain-security/legacy/v3.2.0/adrs/adr-template","sidebar":"tutorialSidebar"},{"id":"adrs/intro","path":"/interchain-security/legacy/v3.2.0/adrs/intro","sidebar":"tutorialSidebar"},{"id":"consumer-development/app-integration","path":"/interchain-security/legacy/v3.2.0/consumer-development/app-integration","sidebar":"tutorialSidebar"},{"id":"consumer-development/changeover-procedure","path":"/interchain-security/legacy/v3.2.0/consumer-development/changeover-procedure","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-chain-governance","path":"/interchain-security/legacy/v3.2.0/consumer-development/consumer-chain-governance","sidebar":"tutorialSidebar"},{"id":"consumer-development/offboarding","path":"/interchain-security/legacy/v3.2.0/consumer-development/offboarding","sidebar":"tutorialSidebar"},{"id":"consumer-development/onboarding","path":"/interchain-security/legacy/v3.2.0/consumer-development/onboarding","sidebar":"tutorialSidebar"},{"id":"features/key-assignment","path":"/interchain-security/legacy/v3.2.0/features/key-assignment","sidebar":"tutorialSidebar"},{"id":"features/proposals","path":"/interchain-security/legacy/v3.2.0/features/proposals","sidebar":"tutorialSidebar"},{"id":"features/reward-distribution","path":"/interchain-security/legacy/v3.2.0/features/reward-distribution","sidebar":"tutorialSidebar"},{"id":"features/slashing","path":"/interchain-security/legacy/v3.2.0/features/slashing","sidebar":"tutorialSidebar"},{"id":"frequently-asked-questions","path":"/interchain-security/legacy/v3.2.0/faq","sidebar":"tutorialSidebar"},{"id":"index","path":"/interchain-security/legacy/v3.2.0/","sidebar":"tutorialSidebar"},{"id":"introduction/overview","path":"/interchain-security/legacy/v3.2.0/introduction/overview","sidebar":"tutorialSidebar"},{"id":"introduction/params","path":"/interchain-security/legacy/v3.2.0/introduction/params","sidebar":"tutorialSidebar"},{"id":"introduction/technical-specification","path":"/interchain-security/legacy/v3.2.0/introduction/technical-specification","sidebar":"tutorialSidebar"},{"id":"introduction/terminology","path":"/interchain-security/legacy/v3.2.0/introduction/terminology","sidebar":"tutorialSidebar"},{"id":"validators/changeover-procedure","path":"/interchain-security/legacy/v3.2.0/validators/changeover-procedure","sidebar":"tutorialSidebar"},{"id":"validators/joining-neutron","path":"/interchain-security/legacy/v3.2.0/validators/joining-neutron","sidebar":"tutorialSidebar"},{"id":"validators/joining-stride","path":"/interchain-security/legacy/v3.2.0/validators/joining-stride","sidebar":"tutorialSidebar"},{"id":"validators/joining-testnet","path":"/interchain-security/legacy/v3.2.0/validators/joining-testnet","sidebar":"tutorialSidebar"},{"id":"validators/overview","path":"/interchain-security/legacy/v3.2.0/validators/overview","sidebar":"tutorialSidebar"},{"id":"validators/withdraw_rewards","path":"/interchain-security/legacy/v3.2.0/validators/withdraw_rewards","sidebar":"tutorialSidebar"}],"draftIds":[],"sidebars":{"tutorialSidebar":{"link":{"path":"/interchain-security/legacy/v3.2.0/","label":"version-v3.2.0/index"}}}},{"name":"v3.1.0","label":"v3.1.0","isLast":false,"path":"/interchain-security/legacy/v3.1.0","mainDocId":"index","docs":[{"id":"adrs/adr-001-key-assignment","path":"/interchain-security/legacy/v3.1.0/adrs/adr-001-key-assignment","sidebar":"tutorialSidebar"},{"id":"adrs/adr-002-throttle","path":"/interchain-security/legacy/v3.1.0/adrs/adr-002-throttle","sidebar":"tutorialSidebar"},{"id":"adrs/adr-003-equivocation-gov-proposal","path":"/interchain-security/legacy/v3.1.0/adrs/adr-003-equivocation-gov-proposal","sidebar":"tutorialSidebar"},{"id":"adrs/adr-007-pause-unbonding-on-eqv-prop","path":"/interchain-security/legacy/v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-prop","sidebar":"tutorialSidebar"},{"id":"adrs/adr-008-throttle-retries","path":"/interchain-security/legacy/v3.1.0/adrs/adr-008-throttle-retries","sidebar":"tutorialSidebar"},{"id":"adrs/adr-009-soft-opt-out","path":"/interchain-security/legacy/v3.1.0/adrs/adr-009-soft-opt-out","sidebar":"tutorialSidebar"},{"id":"adrs/adr-template","path":"/interchain-security/legacy/v3.1.0/adrs/adr-template","sidebar":"tutorialSidebar"},{"id":"adrs/intro","path":"/interchain-security/legacy/v3.1.0/adrs/intro","sidebar":"tutorialSidebar"},{"id":"consumer-development/app-integration","path":"/interchain-security/legacy/v3.1.0/consumer-development/app-integration","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-chain-governance","path":"/interchain-security/legacy/v3.1.0/consumer-development/consumer-chain-governance","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-chain-upgrade-procedure","path":"/interchain-security/legacy/v3.1.0/consumer-development/consumer-chain-upgrade-procedure","sidebar":"tutorialSidebar"},{"id":"consumer-development/offboarding","path":"/interchain-security/legacy/v3.1.0/consumer-development/offboarding","sidebar":"tutorialSidebar"},{"id":"consumer-development/onboarding","path":"/interchain-security/legacy/v3.1.0/consumer-development/onboarding","sidebar":"tutorialSidebar"},{"id":"features/key-assignment","path":"/interchain-security/legacy/v3.1.0/features/key-assignment","sidebar":"tutorialSidebar"},{"id":"features/proposals","path":"/interchain-security/legacy/v3.1.0/features/proposals","sidebar":"tutorialSidebar"},{"id":"features/reward-distribution","path":"/interchain-security/legacy/v3.1.0/features/reward-distribution","sidebar":"tutorialSidebar"},{"id":"features/slashing","path":"/interchain-security/legacy/v3.1.0/features/slashing","sidebar":"tutorialSidebar"},{"id":"frequently-asked-questions","path":"/interchain-security/legacy/v3.1.0/faq","sidebar":"tutorialSidebar"},{"id":"index","path":"/interchain-security/legacy/v3.1.0/","sidebar":"tutorialSidebar"},{"id":"introduction/overview","path":"/interchain-security/legacy/v3.1.0/introduction/overview","sidebar":"tutorialSidebar"},{"id":"introduction/params","path":"/interchain-security/legacy/v3.1.0/introduction/params","sidebar":"tutorialSidebar"},{"id":"introduction/technical-specification","path":"/interchain-security/legacy/v3.1.0/introduction/technical-specification","sidebar":"tutorialSidebar"},{"id":"introduction/terminology","path":"/interchain-security/legacy/v3.1.0/introduction/terminology","sidebar":"tutorialSidebar"},{"id":"validators/joining-testnet","path":"/interchain-security/legacy/v3.1.0/validators/joining-testnet","sidebar":"tutorialSidebar"},{"id":"validators/overview","path":"/interchain-security/legacy/v3.1.0/validators/overview","sidebar":"tutorialSidebar"},{"id":"validators/withdraw_rewards","path":"/interchain-security/legacy/v3.1.0/validators/withdraw_rewards","sidebar":"tutorialSidebar"}],"draftIds":[],"sidebars":{"tutorialSidebar":{"link":{"path":"/interchain-security/legacy/v3.1.0/","label":"version-v3.1.0/index"}}}},{"name":"v2.4.0-lsm","label":"v2.4.0-lsm","isLast":false,"path":"/interchain-security/legacy/v2.4.0-lsm","mainDocId":"index","docs":[{"id":"adrs/adr-001-key-assignment","path":"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-001-key-assignment","sidebar":"tutorialSidebar"},{"id":"adrs/adr-002-throttle","path":"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-002-throttle","sidebar":"tutorialSidebar"},{"id":"adrs/adr-003-equivocation-gov-proposal","path":"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposal","sidebar":"tutorialSidebar"},{"id":"adrs/adr-005-cryptographic-equivocation-verification","path":"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verification","sidebar":"tutorialSidebar"},{"id":"adrs/adr-013-equivocation-slashing","path":"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-013-equivocation-slashing","sidebar":"tutorialSidebar"},{"id":"adrs/adr-template","path":"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-template","sidebar":"tutorialSidebar"},{"id":"adrs/intro","path":"/interchain-security/legacy/v2.4.0-lsm/adrs/intro","sidebar":"tutorialSidebar"},{"id":"consumer-development/app-integration","path":"/interchain-security/legacy/v2.4.0-lsm/consumer-development/app-integration","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-chain-governance","path":"/interchain-security/legacy/v2.4.0-lsm/consumer-development/consumer-chain-governance","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-chain-upgrade-procedure","path":"/interchain-security/legacy/v2.4.0-lsm/consumer-development/consumer-chain-upgrade-procedure","sidebar":"tutorialSidebar"},{"id":"consumer-development/offboarding","path":"/interchain-security/legacy/v2.4.0-lsm/consumer-development/offboarding","sidebar":"tutorialSidebar"},{"id":"consumer-development/onboarding","path":"/interchain-security/legacy/v2.4.0-lsm/consumer-development/onboarding","sidebar":"tutorialSidebar"},{"id":"features/key-assignment","path":"/interchain-security/legacy/v2.4.0-lsm/features/key-assignment","sidebar":"tutorialSidebar"},{"id":"features/proposals","path":"/interchain-security/legacy/v2.4.0-lsm/features/proposals","sidebar":"tutorialSidebar"},{"id":"features/reward-distribution","path":"/interchain-security/legacy/v2.4.0-lsm/features/reward-distribution","sidebar":"tutorialSidebar"},{"id":"features/slashing","path":"/interchain-security/legacy/v2.4.0-lsm/features/slashing","sidebar":"tutorialSidebar"},{"id":"frequently-asked-questions","path":"/interchain-security/legacy/v2.4.0-lsm/faq","sidebar":"tutorialSidebar"},{"id":"index","path":"/interchain-security/legacy/v2.4.0-lsm/","sidebar":"tutorialSidebar"},{"id":"introduction/overview","path":"/interchain-security/legacy/v2.4.0-lsm/introduction/overview","sidebar":"tutorialSidebar"},{"id":"introduction/params","path":"/interchain-security/legacy/v2.4.0-lsm/introduction/params","sidebar":"tutorialSidebar"},{"id":"introduction/technical-specification","path":"/interchain-security/legacy/v2.4.0-lsm/introduction/technical-specification","sidebar":"tutorialSidebar"},{"id":"introduction/terminology","path":"/interchain-security/legacy/v2.4.0-lsm/introduction/terminology","sidebar":"tutorialSidebar"},{"id":"validators/joining-testnet","path":"/interchain-security/legacy/v2.4.0-lsm/validators/joining-testnet","sidebar":"tutorialSidebar"},{"id":"validators/overview","path":"/interchain-security/legacy/v2.4.0-lsm/validators/overview","sidebar":"tutorialSidebar"},{"id":"validators/withdraw_rewards","path":"/interchain-security/legacy/v2.4.0-lsm/validators/withdraw_rewards","sidebar":"tutorialSidebar"}],"draftIds":[],"sidebars":{"tutorialSidebar":{"link":{"path":"/interchain-security/legacy/v2.4.0-lsm/","label":"version-v2.4.0-lsm/index"}}}},{"name":"v2.0.0","label":"v2.0.0","isLast":false,"path":"/interchain-security/legacy/v2.0.0","mainDocId":"index","docs":[{"id":"adrs/adr-001-key-assignment","path":"/interchain-security/legacy/v2.0.0/adrs/adr-001-key-assignment","sidebar":"tutorialSidebar"},{"id":"adrs/adr-002-throttle","path":"/interchain-security/legacy/v2.0.0/adrs/adr-002-throttle","sidebar":"tutorialSidebar"},{"id":"adrs/adr-003-equivocation-gov-proposal","path":"/interchain-security/legacy/v2.0.0/adrs/adr-003-equivocation-gov-proposal","sidebar":"tutorialSidebar"},{"id":"adrs/adr-template","path":"/interchain-security/legacy/v2.0.0/adrs/adr-template","sidebar":"tutorialSidebar"},{"id":"adrs/intro","path":"/interchain-security/legacy/v2.0.0/adrs/intro","sidebar":"tutorialSidebar"},{"id":"consumer-development/app-integration","path":"/interchain-security/legacy/v2.0.0/consumer-development/app-integration","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-chain-governance","path":"/interchain-security/legacy/v2.0.0/consumer-development/consumer-chain-governance","sidebar":"tutorialSidebar"},{"id":"consumer-development/consumer-chain-upgrade-procedure","path":"/interchain-security/legacy/v2.0.0/consumer-development/consumer-chain-upgrade-procedure","sidebar":"tutorialSidebar"},{"id":"consumer-development/offboarding","path":"/interchain-security/legacy/v2.0.0/consumer-development/offboarding","sidebar":"tutorialSidebar"},{"id":"consumer-development/onboarding","path":"/interchain-security/legacy/v2.0.0/consumer-development/onboarding","sidebar":"tutorialSidebar"},{"id":"features/key-assignment","path":"/interchain-security/legacy/v2.0.0/features/key-assignment","sidebar":"tutorialSidebar"},{"id":"features/proposals","path":"/interchain-security/legacy/v2.0.0/features/proposals","sidebar":"tutorialSidebar"},{"id":"features/reward-distribution","path":"/interchain-security/legacy/v2.0.0/features/reward-distribution","sidebar":"tutorialSidebar"},{"id":"features/slashing","path":"/interchain-security/legacy/v2.0.0/features/slashing","sidebar":"tutorialSidebar"},{"id":"frequently-asked-questions","path":"/interchain-security/legacy/v2.0.0/faq","sidebar":"tutorialSidebar"},{"id":"index","path":"/interchain-security/legacy/v2.0.0/","sidebar":"tutorialSidebar"},{"id":"introduction/overview","path":"/interchain-security/legacy/v2.0.0/introduction/overview","sidebar":"tutorialSidebar"},{"id":"introduction/params","path":"/interchain-security/legacy/v2.0.0/introduction/params","sidebar":"tutorialSidebar"},{"id":"introduction/technical-specification","path":"/interchain-security/legacy/v2.0.0/introduction/technical-specification","sidebar":"tutorialSidebar"},{"id":"introduction/terminology","path":"/interchain-security/legacy/v2.0.0/introduction/terminology","sidebar":"tutorialSidebar"},{"id":"validators/joining-testnet","path":"/interchain-security/legacy/v2.0.0/validators/joining-testnet","sidebar":"tutorialSidebar"},{"id":"validators/overview","path":"/interchain-security/legacy/v2.0.0/validators/overview","sidebar":"tutorialSidebar"},{"id":"validators/withdraw_rewards","path":"/interchain-security/legacy/v2.0.0/validators/withdraw_rewards","sidebar":"tutorialSidebar"}],"draftIds":[],"sidebars":{"tutorialSidebar":{"link":{"path":"/interchain-security/legacy/v2.0.0/","label":"version-v2.0.0/index"}}}}],"breadcrumbs":true}}}'),o=JSON.parse('{"defaultLocale":"en","locales":["en"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"}}}');var s=n(7529);const c=JSON.parse('{"docusaurusVersion":"2.4.1","siteVersion":"0.0.0","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"2.4.1"},"docusaurus-plugin-content-blog":{"type":"package","name":"@docusaurus/plugin-content-blog","version":"2.4.1"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"2.4.1"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"2.4.1"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"2.4.1"},"docusaurus-tailwindcss":{"type":"local"},"docusaurus-plugin-client-redirects":{"type":"package","name":"@docusaurus/plugin-client-redirects","version":"2.4.1"},"docusaurus-theme-github-codeblock":{"type":"package","name":"@you54f/theme-github-codeblock","version":"0.1.1"}}}'),l={siteConfig:a.Z,siteMetadata:c,globalData:i,i18n:o,codeTranslations:s},u=r.createContext(l);function d(e){let{children:t}=e;return r.createElement(u.Provider,{value:l},t)}},4763:(e,t,n)=>{"use strict";n.d(t,{Z:()=>p});var r=n(7294),a=n(412),i=n(5742),o=n(8780),s=n(7961);function c(e){let{error:t,tryAgain:n}=e;return r.createElement("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"flex-start",minHeight:"100vh",width:"100%",maxWidth:"80ch",fontSize:"20px",margin:"0 auto",padding:"1rem"}},r.createElement("h1",{style:{fontSize:"3rem"}},"This page crashed"),r.createElement("button",{type:"button",onClick:n,style:{margin:"1rem 0",fontSize:"2rem",cursor:"pointer",borderRadius:20,padding:"1rem"}},"Try again"),r.createElement(l,{error:t}))}function l(e){let{error:t}=e;const n=(0,o.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return r.createElement("p",{style:{whiteSpace:"pre-wrap"}},n)}function u(e){let{error:t,tryAgain:n}=e;return r.createElement(p,{fallback:()=>r.createElement(c,{error:t,tryAgain:n})},r.createElement(i.Z,null,r.createElement("title",null,"Page Error")),r.createElement(s.Z,null,r.createElement(c,{error:t,tryAgain:n})))}const d=e=>r.createElement(u,e);class p extends r.Component{constructor(e){super(e),this.state={error:null}}componentDidCatch(e){a.Z.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){const e={error:t,tryAgain:()=>this.setState({error:null})};return(this.props.fallback??d)(e)}return e??null}}},412:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,a={canUseDOM:r,canUseEventListeners:r&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:r&&"IntersectionObserver"in window,canUseViewport:r&&"screen"in window}},5742:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=n(7294),a=n(405);function i(e){return r.createElement(a.ql,e)}},9960:(e,t,n)=>{"use strict";n.d(t,{Z:()=>h});var r=n(7462),a=n(7294),i=n(3727),o=n(8780),s=n(2263),c=n(3919),l=n(412);const u=a.createContext({collectLink:()=>{}}),d=()=>(0,a.useContext)(u);var p=n(4996);const f=e=>e.startsWith("/");function m(e,t){let{isNavLink:n,to:u,href:m,activeClassName:h,isActive:g,"data-noBrokenLinkCheck":v,autoAddBaseUrl:y=!0,...b}=e;const{siteConfig:{trailingSlash:w,baseUrl:_}}=(0,s.Z)(),{withBaseUrl:S}=(0,p.C)(),k=d(),E=(0,a.useRef)(null);(0,a.useImperativeHandle)(t,(()=>E.current));const x=u||m;const C=(0,c.Z)(x),T=x?.replace("pathname://","");let L=void 0!==T?(A=T,y&&f(A)?S(A):A):void 0;var A;L&&C&&(L=(0,o.applyTrailingSlash)(L,{trailingSlash:w,baseUrl:_}));const N=(0,a.useRef)(!1),O=n?i.OL:i.rU,P=l.Z.canUseIntersectionObserver,I=(0,a.useRef)(),R=()=>{N.current||null==L||(window.docusaurus.preload(L),N.current=!0)};(0,a.useEffect)((()=>(!P&&C&&null!=L&&window.docusaurus.prefetch(L),()=>{P&&I.current&&I.current.disconnect()})),[I,L,P,C]);const M=L?.startsWith("#")??!1,D=!L||!C||M;return D||v||k.collectLink(L),D?a.createElement("a",(0,r.Z)({ref:E,href:L},x&&!C&&{target:"_blank",rel:"noopener noreferrer"},b)):a.createElement(O,(0,r.Z)({},b,{onMouseEnter:R,onTouchStart:R,innerRef:e=>{E.current=e,P&&e&&C&&(I.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(I.current.unobserve(e),I.current.disconnect(),null!=L&&window.docusaurus.prefetch(L))}))})),I.current.observe(e))},to:L},n&&{isActive:g,activeClassName:h}))}const h=a.forwardRef(m)},1875:(e,t,n)=>{"use strict";n.d(t,{Z:()=>r});const r=()=>null},5999:(e,t,n)=>{"use strict";n.d(t,{Z:()=>c,I:()=>s});var r=n(7294);function a(e,t){const n=e.split(/(\{\w+\})/).map(((e,n)=>{if(n%2==1){const n=t?.[e.slice(1,-1)];if(void 0!==n)return n}return e}));return n.some((e=>(0,r.isValidElement)(e)))?n.map(((e,t)=>(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e)).filter((e=>""!==e)):n.join("")}var i=n(7529);function o(e){let{id:t,message:n}=e;if(void 0===t&&void 0===n)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return i[t??n]??n??t}function s(e,t){let{message:n,id:r}=e;return a(o({message:n,id:r}),t)}function c(e){let{children:t,id:n,values:i}=e;if(t&&"string"!=typeof t)throw console.warn("Illegal <Translate> children",t),new Error("The Docusaurus <Translate> component only accept simple string values");const s=o({message:t,id:n});return r.createElement(r.Fragment,null,a(s,i))}},9935:(e,t,n)=>{"use strict";n.d(t,{m:()=>r});const r="default"},3919:(e,t,n)=>{"use strict";function r(e){return/^(?:\w*:|\/\/)/.test(e)}function a(e){return void 0!==e&&!r(e)}n.d(t,{Z:()=>a,b:()=>r})},4996:(e,t,n)=>{"use strict";n.d(t,{C:()=>o,Z:()=>s});var r=n(7294),a=n(2263),i=n(3919);function o(){const{siteConfig:{baseUrl:e,url:t}}=(0,a.Z)(),n=(0,r.useCallback)(((n,r)=>function(e,t,n,r){let{forcePrependBaseUrl:a=!1,absolute:o=!1}=void 0===r?{}:r;if(!n||n.startsWith("#")||(0,i.b)(n))return n;if(a)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;const s=n.startsWith(t)?n:t+n.replace(/^\//,"");return o?e+s:s}(t,e,n,r)),[t,e]);return{withBaseUrl:n}}function s(e,t){void 0===t&&(t={});const{withBaseUrl:n}=o();return n(e,t)}},2263:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=n(7294),a=n(8940);function i(){return(0,r.useContext)(a._)}},2389:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=n(7294),a=n(8934);function i(){return(0,r.useContext)(a._)}},9670:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r=e=>"object"==typeof e&&!!e&&Object.keys(e).length>0;function a(e){const t=".",n={};return function e(a,i){Object.entries(a).forEach((a=>{let[o,s]=a;const c=i?`${i}${t}${o}`:o;r(s)?e(s,c):n[c]=s}))}(e),n}},226:(e,t,n)=>{"use strict";n.d(t,{_:()=>a,z:()=>i});var r=n(7294);const a=r.createContext(null);function i(e){let{children:t,value:n}=e;const i=r.useContext(a),o=(0,r.useMemo)((()=>function(e){let{parent:t,value:n}=e;if(!t){if(!n)throw new Error("Unexpected: no Docusaurus route context found");if(!("plugin"in n))throw new Error("Unexpected: Docusaurus topmost route context has no `plugin` attribute");return n}const r={...t.data,...n?.data};return{plugin:t.plugin,data:r}}({parent:i,value:n})),[i,n]);return r.createElement(a.Provider,{value:o},t)}},143:(e,t,n)=>{"use strict";n.d(t,{Iw:()=>h,gA:()=>p,_r:()=>u,Jo:()=>g,zh:()=>d,yW:()=>m,gB:()=>f});var r=n(6550),a=n(2263),i=n(9935);function o(e,t){void 0===t&&(t={});const n=function(){const{globalData:e}=(0,a.Z)();return e}()[e];if(!n&&t.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin.`);return n}const s=e=>e.versions.find((e=>e.isLast));function c(e,t){const n=function(e,t){const n=s(e);return[...e.versions.filter((e=>e!==n)),n].find((e=>!!(0,r.LX)(t,{path:e.path,exact:!1,strict:!1})))}(e,t),a=n?.docs.find((e=>!!(0,r.LX)(t,{path:e.path,exact:!0,strict:!1})));return{activeVersion:n,activeDoc:a,alternateDocVersions:a?function(t){const n={};return e.versions.forEach((e=>{e.docs.forEach((r=>{r.id===t&&(n[e.name]=r)}))})),n}(a.id):{}}}const l={},u=()=>o("docusaurus-plugin-content-docs")??l,d=e=>function(e,t,n){void 0===t&&(t=i.m),void 0===n&&(n={});const r=o(e),a=r?.[t];if(!a&&n.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin with id "${t}".`);return a}("docusaurus-plugin-content-docs",e,{failfast:!0});function p(e){void 0===e&&(e={});const t=u(),{pathname:n}=(0,r.TH)();return function(e,t,n){void 0===n&&(n={});const a=Object.entries(e).sort(((e,t)=>t[1].path.localeCompare(e[1].path))).find((e=>{let[,n]=e;return!!(0,r.LX)(t,{path:n.path,exact:!1,strict:!1})})),i=a?{pluginId:a[0],pluginData:a[1]}:void 0;if(!i&&n.failfast)throw new Error(`Can't find active docs plugin for "${t}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(e).map((e=>e.path)).join(", ")}`);return i}(t,n,e)}function f(e){return d(e).versions}function m(e){const t=d(e);return s(t)}function h(e){const t=d(e),{pathname:n}=(0,r.TH)();return c(t,n)}function g(e){const t=d(e),{pathname:n}=(0,r.TH)();return function(e,t){const n=s(e);return{latestDocSuggestion:c(e,t).alternateDocVersions[n.name],latestVersionSuggestion:n}}(t,n)}},8320:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>i});var r=n(4865),a=n.n(r);a().configure({showSpinner:!1});const i={onRouteUpdate(e){let{location:t,previousLocation:n}=e;if(n&&t.pathname!==n.pathname){const e=window.setTimeout((()=>{a().start()}),200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){a().done()}}},3310:(e,t,n)=>{"use strict";n.r(t);var r=n(7410),a=n(6809);!function(e){const{themeConfig:{prism:t}}=a.Z,{additionalLanguages:r}=t;globalThis.Prism=e,r.forEach((e=>{n(692)(`./prism-${e}`)})),delete globalThis.Prism}(r.Z)},9471:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=n(7294);const a={iconExternalLink:"iconExternalLink_nPIU"};function i(e){let{width:t=13.5,height:n=13.5}=e;return r.createElement("svg",{width:t,height:n,"aria-hidden":"true",viewBox:"0 0 24 24",className:a.iconExternalLink},r.createElement("path",{fill:"currentColor",d:"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"}))}},7961:(e,t,n)=>{"use strict";n.d(t,{Z:()=>pt});var r=n(7294),a=n(6010),i=n(4763),o=n(1944),s=n(7462),c=n(6550),l=n(5999),u=n(5936);const d="__docusaurus_skipToContent_fallback";function p(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function f(){const e=(0,r.useRef)(null),{action:t}=(0,c.k6)(),n=(0,r.useCallback)((e=>{e.preventDefault();const t=document.querySelector("main:first-of-type")??document.getElementById(d);t&&p(t)}),[]);return(0,u.S)((n=>{let{location:r}=n;e.current&&!r.hash&&"PUSH"===t&&p(e.current)})),{containerRef:e,onClick:n}}const m=(0,l.I)({id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation",message:"Skip to main content"});function h(e){const t=e.children??m,{containerRef:n,onClick:a}=f();return r.createElement("div",{ref:n,role:"region","aria-label":m},r.createElement("a",(0,s.Z)({},e,{href:`#${d}`,onClick:a}),t))}var g=n(5281),v=n(9727);const y={skipToContent:"skipToContent_fXgn"};function b(){return r.createElement(h,{className:y.skipToContent})}var w=n(6668),_=n(9689);function S(e){let{width:t=21,height:n=21,color:a="currentColor",strokeWidth:i=1.2,className:o,...c}=e;return r.createElement("svg",(0,s.Z)({viewBox:"0 0 15 15",width:t,height:n},c),r.createElement("g",{stroke:a,strokeWidth:i},r.createElement("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})))}const k={closeButton:"closeButton_CVFx"};function E(e){return r.createElement("button",(0,s.Z)({type:"button","aria-label":(0,l.I)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"})},e,{className:(0,a.Z)("clean-btn close",k.closeButton,e.className)}),r.createElement(S,{width:14,height:14,strokeWidth:3.1}))}const x={content:"content_knG7"};function C(e){const{announcementBar:t}=(0,w.L)(),{content:n}=t;return r.createElement("div",(0,s.Z)({},e,{className:(0,a.Z)(x.content,e.className),dangerouslySetInnerHTML:{__html:n}}))}const T={announcementBar:"announcementBar_mb4j",announcementBarPlaceholder:"announcementBarPlaceholder_vyr4",announcementBarClose:"announcementBarClose_gvF7",announcementBarContent:"announcementBarContent_xLdY"};function L(){const{announcementBar:e}=(0,w.L)(),{isActive:t,close:n}=(0,_.nT)();if(!t)return null;const{backgroundColor:a,textColor:i,isCloseable:o}=e;return r.createElement("div",{className:T.announcementBar,style:{backgroundColor:a,color:i},role:"banner"},o&&r.createElement("div",{className:T.announcementBarPlaceholder}),r.createElement(C,{className:T.announcementBarContent}),o&&r.createElement(E,{onClick:n,className:T.announcementBarClose}))}var A=n(2961),N=n(2466);var O=n(902),P=n(3102);const I=r.createContext(null);function R(e){let{children:t}=e;const n=function(){const e=(0,A.e)(),t=(0,P.HY)(),[n,a]=(0,r.useState)(!1),i=null!==t.component,o=(0,O.D9)(i);return(0,r.useEffect)((()=>{i&&!o&&a(!0)}),[i,o]),(0,r.useEffect)((()=>{i?e.shown||a(!0):a(!1)}),[e.shown,i]),(0,r.useMemo)((()=>[n,a]),[n])}();return r.createElement(I.Provider,{value:n},t)}function M(e){if(e.component){const t=e.component;return r.createElement(t,e.props)}}function D(){const e=(0,r.useContext)(I);if(!e)throw new O.i6("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,a=(0,r.useCallback)((()=>n(!1)),[n]),i=(0,P.HY)();return(0,r.useMemo)((()=>({shown:t,hide:a,content:M(i)})),[a,i,t])}function F(e){let{header:t,primaryMenu:n,secondaryMenu:i}=e;const{shown:o}=D();return r.createElement("div",{className:"navbar-sidebar"},t,r.createElement("div",{className:(0,a.Z)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":o})},r.createElement("div",{className:"navbar-sidebar__item menu"},n),r.createElement("div",{className:"navbar-sidebar__item menu"},i)))}var B=n(2949),j=n(2389);function $(e){return r.createElement("svg",(0,s.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"}))}function z(e){return r.createElement("svg",(0,s.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"}))}const U={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function q(e){let{className:t,buttonClassName:n,value:i,onChange:o}=e;const s=(0,j.Z)(),c=(0,l.I)({message:"Switch between dark and light mode (currently {mode})",id:"theme.colorToggle.ariaLabel",description:"The ARIA label for the navbar color mode toggle"},{mode:"dark"===i?(0,l.I)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,l.I)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return r.createElement("div",{className:(0,a.Z)(U.toggle,t)},r.createElement("button",{className:(0,a.Z)("clean-btn",U.toggleButton,!s&&U.toggleButtonDisabled,n),type:"button",onClick:()=>o("dark"===i?"light":"dark"),disabled:!s,title:c,"aria-label":c,"aria-live":"polite"},r.createElement($,{className:(0,a.Z)(U.toggleIcon,U.lightToggleIcon)}),r.createElement(z,{className:(0,a.Z)(U.toggleIcon,U.darkToggleIcon)})))}const Z=r.memo(q),H={darkNavbarColorModeToggle:"darkNavbarColorModeToggle_X3D1"};function V(e){let{className:t}=e;const n=(0,w.L)().navbar.style,a=(0,w.L)().colorMode.disableSwitch,{colorMode:i,setColorMode:o}=(0,B.I)();return a?null:r.createElement(Z,{className:t,buttonClassName:"dark"===n?H.darkNavbarColorModeToggle:void 0,value:i,onChange:o})}var W=n(1327);function G(){return r.createElement(W.Z,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function Y(){const e=(0,A.e)();return r.createElement("button",{type:"button","aria-label":(0,l.I)({id:"theme.docs.sidebar.closeSidebarButtonAriaLabel",message:"Close navigation bar",description:"The ARIA label for close button of mobile sidebar"}),className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle()},r.createElement(S,{color:"var(--ifm-color-emphasis-600)"}))}function K(){return r.createElement("div",{className:"navbar-sidebar__brand"},r.createElement(G,null),r.createElement(V,{className:"margin-right--md"}),r.createElement(Y,null))}var X=n(9960),Q=n(4996),J=n(3919);function ee(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}var te=n(9471);function ne(e){let{activeBasePath:t,activeBaseRegex:n,to:a,href:i,label:o,html:c,isDropdownLink:l,prependBaseUrlToHref:u,...d}=e;const p=(0,Q.Z)(a),f=(0,Q.Z)(t),m=(0,Q.Z)(i,{forcePrependBaseUrl:!0}),h=o&&i&&!(0,J.Z)(i),g=c?{dangerouslySetInnerHTML:{__html:c}}:{children:r.createElement(r.Fragment,null,o,h&&r.createElement(te.Z,l&&{width:12,height:12}))};return i?r.createElement(X.Z,(0,s.Z)({href:u?m:i},d,g)):r.createElement(X.Z,(0,s.Z)({to:p,isNavLink:!0},(t||n)&&{isActive:(e,t)=>n?ee(n,t.pathname):t.pathname.startsWith(f)},d,g))}function re(e){let{className:t,isDropdownItem:n=!1,...i}=e;const o=r.createElement(ne,(0,s.Z)({className:(0,a.Z)(n?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:n},i));return n?r.createElement("li",null,o):o}function ae(e){let{className:t,isDropdownItem:n,...i}=e;return r.createElement("li",{className:"menu__list-item"},r.createElement(ne,(0,s.Z)({className:(0,a.Z)("menu__link",t)},i)))}function ie(e){let{mobile:t=!1,position:n,...a}=e;const i=t?ae:re;return r.createElement(i,(0,s.Z)({},a,{activeClassName:a.activeClassName??(t?"menu__link--active":"navbar__link--active")}))}var oe=n(6043),se=n(8596),ce=n(2263);function le(e,t){return e.some((e=>function(e,t){return!!(0,se.Mg)(e.to,t)||!!ee(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function ue(e){let{items:t,position:n,className:i,onClick:o,...c}=e;const l=(0,r.useRef)(null),[u,d]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{const e=e=>{l.current&&!l.current.contains(e.target)&&d(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),document.addEventListener("focusin",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e),document.removeEventListener("focusin",e)}}),[l]),r.createElement("div",{ref:l,className:(0,a.Z)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":u})},r.createElement(ne,(0,s.Z)({"aria-haspopup":"true","aria-expanded":u,role:"button",href:c.to?void 0:"#",className:(0,a.Z)("navbar__link",i)},c,{onClick:c.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),d(!u))}}),c.children??c.label),r.createElement("ul",{className:"dropdown__menu"},t.map(((e,t)=>r.createElement(xe,(0,s.Z)({isDropdownItem:!0,activeClassName:"dropdown__link--active"},e,{key:t}))))))}function de(e){let{items:t,className:n,position:i,onClick:o,...l}=e;const u=function(){const{siteConfig:{baseUrl:e}}=(0,ce.Z)(),{pathname:t}=(0,c.TH)();return t.replace(e,"/")}(),d=le(t,u),{collapsed:p,toggleCollapsed:f,setCollapsed:m}=(0,oe.u)({initialState:()=>!d});return(0,r.useEffect)((()=>{d&&m(!d)}),[u,d,m]),r.createElement("li",{className:(0,a.Z)("menu__list-item",{"menu__list-item--collapsed":p})},r.createElement(ne,(0,s.Z)({role:"button",className:(0,a.Z)("menu__link menu__link--sublist menu__link--sublist-caret",n)},l,{onClick:e=>{e.preventDefault(),f()}}),l.children??l.label),r.createElement(oe.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:p},t.map(((e,t)=>r.createElement(xe,(0,s.Z)({mobile:!0,isDropdownItem:!0,onClick:o,activeClassName:"menu__link--active"},e,{key:t}))))))}function pe(e){let{mobile:t=!1,...n}=e;const a=t?de:ue;return r.createElement(a,n)}var fe=n(4711);function me(e){let{width:t=20,height:n=20,...a}=e;return r.createElement("svg",(0,s.Z)({viewBox:"0 0 24 24",width:t,height:n,"aria-hidden":!0},a),r.createElement("path",{fill:"currentColor",d:"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"}))}const he={iconLanguage:"iconLanguage_nlXk"};var ge=n(1875);const ve={searchBox:"searchBox_ZlJk"};function ye(e){let{children:t,className:n}=e;return r.createElement("div",{className:(0,a.Z)(n,ve.searchBox)},t)}var be=n(143),we=n(2802);const _e=e=>e.docs.find((t=>t.id===e.mainDocId));var Se=n(373);const ke=e=>e.docs.find((t=>t.id===e.mainDocId));const Ee={default:ie,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:a,...i}=e;const{i18n:{currentLocale:o,locales:u,localeConfigs:d}}=(0,ce.Z)(),p=(0,fe.l)(),{search:f,hash:m}=(0,c.TH)(),h=[...n,...u.map((e=>{const n=`${`pathname://${p.createUrl({locale:e,fullyQualified:!1})}`}${f}${m}`;return{label:d[e].label,lang:d[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===o?t?"menu__link--active":"dropdown__link--active":""}})),...a],g=t?(0,l.I)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):d[o].label;return r.createElement(pe,(0,s.Z)({},i,{mobile:t,label:r.createElement(r.Fragment,null,r.createElement(me,{className:he.iconLanguage}),g),items:h}))},search:function(e){let{mobile:t,className:n}=e;return t?null:r.createElement(ye,{className:n},r.createElement(ge.Z,null))},dropdown:pe,html:function(e){let{value:t,className:n,mobile:i=!1,isDropdownItem:o=!1}=e;const s=o?"li":"div";return r.createElement(s,{className:(0,a.Z)({navbar__item:!i&&!o,"menu__list-item":i},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){let{docId:t,label:n,docsPluginId:a,...i}=e;const{activeDoc:o}=(0,be.Iw)(a),c=(0,we.vY)(t,a);return null===c?null:r.createElement(ie,(0,s.Z)({exact:!0},i,{isActive:()=>o?.path===c.path||!!o?.sidebar&&o.sidebar===c.sidebar,label:n??c.id,to:c.path}))},docSidebar:function(e){let{sidebarId:t,label:n,docsPluginId:a,...i}=e;const{activeDoc:o}=(0,be.Iw)(a),c=(0,we.oz)(t,a).link;if(!c)throw new Error(`DocSidebarNavbarItem: Sidebar with ID "${t}" doesn't have anything to be linked to.`);return r.createElement(ie,(0,s.Z)({exact:!0},i,{isActive:()=>o?.sidebar===t,label:n??c.label,to:c.path}))},docsVersion:function(e){let{label:t,to:n,docsPluginId:a,...i}=e;const o=(0,we.lO)(a)[0],c=t??o.label,l=n??_e(o).path;return r.createElement(ie,(0,s.Z)({},i,{label:c,to:l}))},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:a,dropdownItemsBefore:i,dropdownItemsAfter:o,...u}=e;const{search:d,hash:p}=(0,c.TH)(),f=(0,be.Iw)(n),m=(0,be.gB)(n),{savePreferredVersionName:h}=(0,Se.J)(n),g=[...i,...m.map((e=>{const t=f.alternateDocVersions[e.name]??ke(e);return{label:e.label,to:`${t.path}${d}${p}`,isActive:()=>e===f.activeVersion,onClick:()=>h(e.name)}})),...o],v=(0,we.lO)(n)[0],y=t&&g.length>1?(0,l.I)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):v.label,b=t&&g.length>1?void 0:ke(v).path;return g.length<=1?r.createElement(ie,(0,s.Z)({},u,{mobile:t,label:y,to:b,isActive:a?()=>!1:void 0})):r.createElement(pe,(0,s.Z)({},u,{mobile:t,label:y,to:b,items:g,isActive:a?()=>!1:void 0}))}};function xe(e){let{type:t,...n}=e;const a=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),i=Ee[a];if(!i)throw new Error(`No NavbarItem component found for type "${t}".`);return r.createElement(i,n)}function Ce(){const e=(0,A.e)(),t=(0,w.L)().navbar.items;return r.createElement("ul",{className:"menu__list"},t.map(((t,n)=>r.createElement(xe,(0,s.Z)({mobile:!0},t,{onClick:()=>e.toggle(),key:n})))))}function Te(e){return r.createElement("button",(0,s.Z)({},e,{type:"button",className:"clean-btn navbar-sidebar__back"}),r.createElement(l.Z,{id:"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel",description:"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)"},"\u2190 Back to main menu"))}function Le(){const e=0===(0,w.L)().navbar.items.length,t=D();return r.createElement(r.Fragment,null,!e&&r.createElement(Te,{onClick:()=>t.hide()}),t.content)}function Ae(){const e=(0,A.e)();var t;return void 0===(t=e.shown)&&(t=!0),(0,r.useEffect)((()=>(document.body.style.overflow=t?"hidden":"visible",()=>{document.body.style.overflow="visible"})),[t]),e.shouldRender?r.createElement(F,{header:r.createElement(K,null),primaryMenu:r.createElement(Ce,null),secondaryMenu:r.createElement(Le,null)}):null}const Ne={navbarHideable:"navbarHideable_m1mJ",navbarHidden:"navbarHidden_jGov"};function Oe(e){return r.createElement("div",(0,s.Z)({role:"presentation"},e,{className:(0,a.Z)("navbar-sidebar__backdrop",e.className)}))}function Pe(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:i}}=(0,w.L)(),o=(0,A.e)(),{navbarRef:s,isNavbarVisible:c}=function(e){const[t,n]=(0,r.useState)(e),a=(0,r.useRef)(!1),i=(0,r.useRef)(0),o=(0,r.useCallback)((e=>{null!==e&&(i.current=e.getBoundingClientRect().height)}),[]);return(0,N.RF)(((t,r)=>{let{scrollY:o}=t;if(!e)return;if(o<i.current)return void n(!0);if(a.current)return void(a.current=!1);const s=r?.scrollY,c=document.documentElement.scrollHeight-i.current,l=window.innerHeight;s&&o>=s?n(!1):o+l<c&&n(!0)})),(0,u.S)((t=>{if(!e)return;const r=t.location.hash;if(r?document.getElementById(r.substring(1)):void 0)return a.current=!0,void n(!1);n(!0)})),{navbarRef:o,isNavbarVisible:t}}(n);return r.createElement("nav",{ref:s,"aria-label":(0,l.I)({id:"theme.NavBar.navAriaLabel",message:"Main",description:"The ARIA label for the main navigation"}),className:(0,a.Z)("navbar","navbar--fixed-top",n&&[Ne.navbarHideable,!c&&Ne.navbarHidden],{"navbar--dark":"dark"===i,"navbar--primary":"primary"===i,"navbar-sidebar--show":o.shown})},t,r.createElement(Oe,{onClick:o.toggle}),r.createElement(Ae,null))}var Ie=n(8780);const Re={errorBoundaryError:"errorBoundaryError_a6uf"};function Me(e){return r.createElement("button",(0,s.Z)({type:"button"},e),r.createElement(l.Z,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again rendering when the React error boundary captures an error"},"Try again"))}function De(e){let{error:t}=e;const n=(0,Ie.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return r.createElement("p",{className:Re.errorBoundaryError},n)}class Fe extends r.Component{componentDidCatch(e,t){throw this.props.onError(e,t)}render(){return this.props.children}}const Be="right";function je(e){let{width:t=30,height:n=30,className:a,...i}=e;return r.createElement("svg",(0,s.Z)({className:a,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true"},i),r.createElement("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"}))}function $e(){const{toggle:e,shown:t}=(0,A.e)();return r.createElement("button",{onClick:e,"aria-label":(0,l.I)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button"},r.createElement(je,null))}const ze={colorModeToggle:"colorModeToggle_DEke"};function Ue(e){let{items:t}=e;return r.createElement(r.Fragment,null,t.map(((e,t)=>r.createElement(Fe,{key:t,onError:t=>new Error(`A theme navbar item failed to render.\nPlease double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:\n${JSON.stringify(e,null,2)}`,{cause:t})},r.createElement(xe,e)))))}function qe(e){let{left:t,right:n}=e;return r.createElement("div",{className:"navbar__inner"},r.createElement("div",{className:"navbar__items"},t),r.createElement("div",{className:"navbar__items navbar__items--right"},n))}function Ze(){const e=(0,A.e)(),t=(0,w.L)().navbar.items,[n,a]=function(e){function t(e){return"left"===(e.position??Be)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),i=t.find((e=>"search"===e.type));return r.createElement(qe,{left:r.createElement(r.Fragment,null,!e.disabled&&r.createElement($e,null),r.createElement(G,null),r.createElement(Ue,{items:n})),right:r.createElement(r.Fragment,null,r.createElement(Ue,{items:a}),r.createElement(V,{className:ze.colorModeToggle}),!i&&r.createElement(ye,null,r.createElement(ge.Z,null)))})}function He(){return r.createElement(Pe,null,r.createElement(Ze,null))}function Ve(e){let{item:t}=e;const{to:n,href:a,label:i,prependBaseUrlToHref:o,...c}=t,l=(0,Q.Z)(n),u=(0,Q.Z)(a,{forcePrependBaseUrl:!0});return r.createElement(X.Z,(0,s.Z)({className:"footer__link-item"},a?{href:o?u:a}:{to:l},c),i,a&&!(0,J.Z)(a)&&r.createElement(te.Z,null))}function We(e){let{item:t}=e;return t.html?r.createElement("li",{className:"footer__item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement("li",{key:t.href??t.to,className:"footer__item"},r.createElement(Ve,{item:t}))}function Ge(e){let{column:t}=e;return r.createElement("div",{className:"col footer__col"},r.createElement("div",{className:"footer__title"},t.title),r.createElement("ul",{className:"footer__items clean-list"},t.items.map(((e,t)=>r.createElement(We,{key:t,item:e})))))}function Ye(e){let{columns:t}=e;return r.createElement("div",{className:"row footer__links"},t.map(((e,t)=>r.createElement(Ge,{key:t,column:e}))))}function Ke(){return r.createElement("span",{className:"footer__link-separator"},"\xb7")}function Xe(e){let{item:t}=e;return t.html?r.createElement("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement(Ve,{item:t})}function Qe(e){let{links:t}=e;return r.createElement("div",{className:"footer__links text--center"},r.createElement("div",{className:"footer__links"},t.map(((e,n)=>r.createElement(r.Fragment,{key:n},r.createElement(Xe,{item:e}),t.length!==n+1&&r.createElement(Ke,null))))))}function Je(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?r.createElement(Ye,{columns:t}):r.createElement(Qe,{links:t})}var et=n(941);const tt={footerLogoLink:"footerLogoLink_BH7S"};function nt(e){let{logo:t}=e;const{withBaseUrl:n}=(0,Q.C)(),i={light:n(t.src),dark:n(t.srcDark??t.src)};return r.createElement(et.Z,{className:(0,a.Z)("footer__logo",t.className),alt:t.alt,sources:i,width:t.width,height:t.height,style:t.style})}function rt(e){let{logo:t}=e;return t.href?r.createElement(X.Z,{href:t.href,className:tt.footerLogoLink,target:t.target},r.createElement(nt,{logo:t})):r.createElement(nt,{logo:t})}function at(e){let{copyright:t}=e;return r.createElement("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function it(e){let{style:t,links:n,logo:i,copyright:o}=e;return r.createElement("footer",{className:(0,a.Z)("footer",{"footer--dark":"dark"===t})},r.createElement("div",{className:"container container-fluid"},n,(i||o)&&r.createElement("div",{className:"footer__bottom text--center"},i&&r.createElement("div",{className:"margin-bottom--sm"},i),o)))}function ot(){const{footer:e}=(0,w.L)();if(!e)return null;const{copyright:t,links:n,logo:a,style:i}=e;return r.createElement(it,{style:i,links:n&&n.length>0&&r.createElement(Je,{links:n}),logo:a&&r.createElement(rt,{logo:a}),copyright:t&&r.createElement(at,{copyright:t})})}const st=r.memo(ot),ct=(0,O.Qc)([B.S,_.pl,N.OC,Se.L5,o.VC,function(e){let{children:t}=e;return r.createElement(P.n2,null,r.createElement(A.M,null,r.createElement(R,null,t)))}]);function lt(e){let{children:t}=e;return r.createElement(ct,null,t)}function ut(e){let{error:t,tryAgain:n}=e;return r.createElement("main",{className:"container margin-vert--xl"},r.createElement("div",{className:"row"},r.createElement("div",{className:"col col--6 col--offset-3"},r.createElement("h1",{className:"hero__title"},r.createElement(l.Z,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed"},"This page crashed.")),r.createElement("div",{className:"margin-vert--lg"},r.createElement(Me,{onClick:n,className:"button button--primary shadow--lw"})),r.createElement("hr",null),r.createElement("div",{className:"margin-vert--md"},r.createElement(De,{error:t})))))}const dt={mainWrapper:"mainWrapper_z2l0"};function pt(e){const{children:t,noFooter:n,wrapperClassName:s,title:c,description:l}=e;return(0,v.t)(),r.createElement(lt,null,r.createElement(o.d,{title:c,description:l}),r.createElement(b,null),r.createElement(L,null),r.createElement(He,null),r.createElement("div",{id:d,className:(0,a.Z)(g.k.wrapper.main,dt.mainWrapper,s)},r.createElement(i.Z,{fallback:e=>r.createElement(ut,e)},t)),!n&&r.createElement(st,null))}},1327:(e,t,n)=>{"use strict";n.d(t,{Z:()=>d});var r=n(7462),a=n(7294),i=n(9960),o=n(4996),s=n(2263),c=n(6668),l=n(941);function u(e){let{logo:t,alt:n,imageClassName:r}=e;const i={light:(0,o.Z)(t.src),dark:(0,o.Z)(t.srcDark||t.src)},s=a.createElement(l.Z,{className:t.className,sources:i,height:t.height,width:t.width,alt:n,style:t.style});return r?a.createElement("div",{className:r},s):s}function d(e){const{siteConfig:{title:t}}=(0,s.Z)(),{navbar:{title:n,logo:l}}=(0,c.L)(),{imageClassName:d,titleClassName:p,...f}=e,m=(0,o.Z)(l?.href||"/"),h=n?"":t,g=l?.alt??h;return a.createElement(i.Z,(0,r.Z)({to:m},f,l?.target&&{target:l.target}),l&&a.createElement(u,{logo:l,alt:g,imageClassName:d}),null!=n&&a.createElement("b",{className:p},n))}},197:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=n(7294),a=n(5742);function i(e){let{locale:t,version:n,tag:i}=e;const o=t;return r.createElement(a.Z,null,t&&r.createElement("meta",{name:"docusaurus_locale",content:t}),n&&r.createElement("meta",{name:"docusaurus_version",content:n}),i&&r.createElement("meta",{name:"docusaurus_tag",content:i}),o&&r.createElement("meta",{name:"docsearch:language",content:o}),n&&r.createElement("meta",{name:"docsearch:version",content:n}),i&&r.createElement("meta",{name:"docsearch:docusaurus_tag",content:i}))}},941:(e,t,n)=>{"use strict";n.d(t,{Z:()=>l});var r=n(7462),a=n(7294),i=n(6010),o=n(2389),s=n(2949);const c={themedImage:"themedImage_ToTc","themedImage--light":"themedImage--light_HNdA","themedImage--dark":"themedImage--dark_i4oU"};function l(e){const t=(0,o.Z)(),{colorMode:n}=(0,s.I)(),{sources:l,className:u,alt:d,...p}=e,f=t?"dark"===n?["dark"]:["light"]:["light","dark"];return a.createElement(a.Fragment,null,f.map((e=>a.createElement("img",(0,r.Z)({key:e,src:l[e],alt:d,className:(0,i.Z)(c.themedImage,c[`themedImage--${e}`],u)},p)))))}},6043:(e,t,n)=>{"use strict";n.d(t,{u:()=>c,z:()=>g});var r=n(7462),a=n(7294),i=n(412),o=n(1442);const s="ease-in-out";function c(e){let{initialState:t}=e;const[n,r]=(0,a.useState)(t??!1),i=(0,a.useCallback)((()=>{r((e=>!e))}),[]);return{collapsed:n,setCollapsed:r,toggleCollapsed:i}}const l={display:"none",overflow:"hidden",height:"0px"},u={display:"block",overflow:"visible",height:"auto"};function d(e,t){const n=t?l:u;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function p(e){let{collapsibleRef:t,collapsed:n,animation:r}=e;const i=(0,a.useRef)(!1);(0,a.useEffect)((()=>{const e=t.current;function a(){const t=e.scrollHeight,n=r?.duration??function(e){if((0,o.n)())return 1;const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(t);return{transition:`height ${n}ms ${r?.easing??s}`,height:`${t}px`}}function c(){const t=a();e.style.transition=t.transition,e.style.height=t.height}if(!i.current)return d(e,n),void(i.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(c(),requestAnimationFrame((()=>{e.style.height=l.height,e.style.overflow=l.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{c()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,r])}function f(e){if(!i.Z.canUseDOM)return e?l:u}function m(e){let{as:t="div",collapsed:n,children:r,animation:i,onCollapseTransitionEnd:o,className:s,disableSSRStyle:c}=e;const l=(0,a.useRef)(null);return p({collapsibleRef:l,collapsed:n,animation:i}),a.createElement(t,{ref:l,style:c?void 0:f(n),onTransitionEnd:e=>{"height"===e.propertyName&&(d(l.current,n),o?.(n))},className:s},r)}function h(e){let{collapsed:t,...n}=e;const[i,o]=(0,a.useState)(!t),[s,c]=(0,a.useState)(t);return(0,a.useLayoutEffect)((()=>{t||o(!0)}),[t]),(0,a.useLayoutEffect)((()=>{i&&c(t)}),[i,t]),i?a.createElement(m,(0,r.Z)({},n,{collapsed:s})):null}function g(e){let{lazy:t,...n}=e;const r=t?h:m;return a.createElement(r,n)}},9689:(e,t,n)=>{"use strict";n.d(t,{nT:()=>m,pl:()=>f});var r=n(7294),a=n(2389),i=n(12),o=n(902),s=n(6668);const c=(0,i.WA)("docusaurus.announcement.dismiss"),l=(0,i.WA)("docusaurus.announcement.id"),u=()=>"true"===c.get(),d=e=>c.set(String(e)),p=r.createContext(null);function f(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,s.L)(),t=(0,a.Z)(),[n,i]=(0,r.useState)((()=>!!t&&u()));(0,r.useEffect)((()=>{i(u())}),[]);const o=(0,r.useCallback)((()=>{d(!0),i(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=l.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;l.set(t),r&&d(!1),!r&&u()||i(!1)}),[e]),(0,r.useMemo)((()=>({isActive:!!e&&!n,close:o})),[e,n,o])}();return r.createElement(p.Provider,{value:n},t)}function m(){const e=(0,r.useContext)(p);if(!e)throw new o.i6("AnnouncementBarProvider");return e}},2949:(e,t,n)=>{"use strict";n.d(t,{I:()=>g,S:()=>h});var r=n(7294),a=n(412),i=n(902),o=n(12),s=n(6668);const c=r.createContext(void 0),l="theme",u=(0,o.WA)(l),d={light:"light",dark:"dark"},p=e=>e===d.dark?d.dark:d.light,f=e=>a.Z.canUseDOM?p(document.documentElement.getAttribute("data-theme")):p(e),m=e=>{u.set(p(e))};function h(e){let{children:t}=e;const n=function(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,s.L)(),[a,i]=(0,r.useState)(f(e));(0,r.useEffect)((()=>{t&&u.del()}),[t]);const o=(0,r.useCallback)((function(t,r){void 0===r&&(r={});const{persist:a=!0}=r;t?(i(t),a&&m(t)):(i(n?window.matchMedia("(prefers-color-scheme: dark)").matches?d.dark:d.light:e),u.del())}),[n,e]);(0,r.useEffect)((()=>{document.documentElement.setAttribute("data-theme",p(a))}),[a]),(0,r.useEffect)((()=>{if(t)return;const e=e=>{if(e.key!==l)return;const t=u.get();null!==t&&o(p(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,o]);const c=(0,r.useRef)(!1);return(0,r.useEffect)((()=>{if(t&&!n)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),r=()=>{window.matchMedia("print").matches||c.current?c.current=window.matchMedia("print").matches:o(null)};return e.addListener(r),()=>e.removeListener(r)}),[o,t,n]),(0,r.useMemo)((()=>({colorMode:a,setColorMode:o,get isDarkTheme(){return a===d.dark},setLightTheme(){o(d.light)},setDarkTheme(){o(d.dark)}})),[a,o])}();return r.createElement(c.Provider,{value:n},t)}function g(){const e=(0,r.useContext)(c);if(null==e)throw new i.i6("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},373:(e,t,n)=>{"use strict";n.d(t,{J:()=>y,L5:()=>g});var r=n(7294),a=n(143),i=n(9935),o=n(6668),s=n(2802),c=n(902),l=n(12);const u=e=>`docs-preferred-version-${e}`,d={save:(e,t,n)=>{(0,l.WA)(u(e),{persistence:t}).set(n)},read:(e,t)=>(0,l.WA)(u(e),{persistence:t}).get(),clear:(e,t)=>{(0,l.WA)(u(e),{persistence:t}).del()}},p=e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}])));const f=r.createContext(null);function m(){const e=(0,a._r)(),t=(0,o.L)().docs.versionPersistence,n=(0,r.useMemo)((()=>Object.keys(e)),[e]),[i,s]=(0,r.useState)((()=>p(n)));(0,r.useEffect)((()=>{s(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:r}=e;function a(e){const t=d.read(e,n);return r[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(d.clear(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,a(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[i,(0,r.useMemo)((()=>({savePreferredVersion:function(e,n){d.save(e,t,n),s((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function h(e){let{children:t}=e;const n=m();return r.createElement(f.Provider,{value:n},t)}function g(e){let{children:t}=e;return s.cE?r.createElement(h,null,t):r.createElement(r.Fragment,null,t)}function v(){const e=(0,r.useContext)(f);if(!e)throw new c.i6("DocsPreferredVersionContextProvider");return e}function y(e){void 0===e&&(e=i.m);const t=(0,a.zh)(e),[n,o]=v(),{preferredVersionName:s}=n[e];return{preferredVersion:t.versions.find((e=>e.name===s))??null,savePreferredVersionName:(0,r.useCallback)((t=>{o.savePreferredVersion(e,t)}),[o,e])}}},1116:(e,t,n)=>{"use strict";n.d(t,{V:()=>c,b:()=>s});var r=n(7294),a=n(902);const i=Symbol("EmptyContext"),o=r.createContext(i);function s(e){let{children:t,name:n,items:a}=e;const i=(0,r.useMemo)((()=>n&&a?{name:n,items:a}:null),[n,a]);return r.createElement(o.Provider,{value:i},t)}function c(){const e=(0,r.useContext)(o);if(e===i)throw new a.i6("DocsSidebarProvider");return e}},2961:(e,t,n)=>{"use strict";n.d(t,{M:()=>p,e:()=>f});var r=n(7294),a=n(3102),i=n(7524),o=n(6550),s=(n(1688),n(902));function c(e){!function(e){const t=(0,o.k6)(),n=(0,s.zX)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}var l=n(6668);const u=r.createContext(void 0);function d(){const e=function(){const e=(0,a.HY)(),{items:t}=(0,l.L)().navbar;return 0===t.length&&!e.component}(),t=(0,i.i)(),n=!e&&"mobile"===t,[o,s]=(0,r.useState)(!1);c((()=>{if(o)return s(!1),!1}));const u=(0,r.useCallback)((()=>{s((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&s(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:u,shown:o})),[e,n,u,o])}function p(e){let{children:t}=e;const n=d();return r.createElement(u.Provider,{value:n},t)}function f(){const e=r.useContext(u);if(void 0===e)throw new s.i6("NavbarMobileSidebarProvider");return e}},3102:(e,t,n)=>{"use strict";n.d(t,{HY:()=>s,Zo:()=>c,n2:()=>o});var r=n(7294),a=n(902);const i=r.createContext(null);function o(e){let{children:t}=e;const n=(0,r.useState)({component:null,props:null});return r.createElement(i.Provider,{value:n},t)}function s(){const e=(0,r.useContext)(i);if(!e)throw new a.i6("NavbarSecondaryMenuContentProvider");return e[0]}function c(e){let{component:t,props:n}=e;const o=(0,r.useContext)(i);if(!o)throw new a.i6("NavbarSecondaryMenuContentProvider");const[,s]=o,c=(0,a.Ql)(n);return(0,r.useEffect)((()=>{s({component:t,props:c})}),[s,t,c]),(0,r.useEffect)((()=>()=>s({component:null,props:null})),[s]),null}},9727:(e,t,n)=>{"use strict";n.d(t,{h:()=>a,t:()=>i});var r=n(7294);const a="navigation-with-keyboard";function i(){(0,r.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(a),"mousedown"===e.type&&document.body.classList.remove(a)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(a),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},7524:(e,t,n)=>{"use strict";n.d(t,{i:()=>l});var r=n(7294),a=n(412);const i={desktop:"desktop",mobile:"mobile",ssr:"ssr"},o=996;function s(){return a.Z.canUseDOM?window.innerWidth>o?i.desktop:i.mobile:i.ssr}const c=!1;function l(){const[e,t]=(0,r.useState)((()=>c?"ssr":s()));return(0,r.useEffect)((()=>{function e(){t(s())}const n=c?window.setTimeout(e,1e3):void 0;return window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e),clearTimeout(n)}}),[]),e}},5281:(e,t,n)=>{"use strict";n.d(t,{k:()=>r});const r={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",admonitionType:e=>`theme-admonition-${e}`},layout:{},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{}}},1442:(e,t,n)=>{"use strict";function r(){return window.matchMedia("(prefers-reduced-motion: reduce)").matches}n.d(t,{n:()=>r})},2802:(e,t,n)=>{"use strict";n.d(t,{Wl:()=>p,_F:()=>h,cE:()=>d,hI:()=>_,lO:()=>y,vY:()=>w,oz:()=>b,s1:()=>v});var r=n(7294),a=n(6550),i=n(8790),o=n(143),s=n(373),c=n(1116);function l(e){return Array.from(new Set(e))}var u=n(8596);const d=!!o._r;function p(e){if(e.href)return e.href;for(const t of e.items){if("link"===t.type)return t.href;if("category"===t.type){const e=p(t);if(e)return e}}}const f=(e,t)=>void 0!==e&&(0,u.Mg)(e,t),m=(e,t)=>e.some((e=>h(e,t)));function h(e,t){return"link"===e.type?f(e.href,t):"category"===e.type&&(f(e.href,t)||m(e.items,t))}function g(e){let{sidebarItems:t,pathname:n,onlyCategories:r=!1}=e;const a=[];return function e(t){for(const i of t)if("category"===i.type&&((0,u.Mg)(i.href,n)||e(i.items))||"link"===i.type&&(0,u.Mg)(i.href,n)){return r&&"category"!==i.type||a.unshift(i),!0}return!1}(t),a}function v(){const e=(0,c.V)(),{pathname:t}=(0,a.TH)(),n=(0,o.gA)()?.pluginData.breadcrumbs;return!1!==n&&e?g({sidebarItems:e.items,pathname:t}):null}function y(e){const{activeVersion:t}=(0,o.Iw)(e),{preferredVersion:n}=(0,s.J)(e),a=(0,o.yW)(e);return(0,r.useMemo)((()=>l([t,n,a].filter(Boolean))),[t,n,a])}function b(e,t){const n=y(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),r=t.find((t=>t[0]===e));if(!r)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable sidebar ids are:\n- ${t.map((e=>e[0])).join("\n- ")}`);return r[1]}),[e,n])}function w(e,t){const n=y(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),r=t.find((t=>t.id===e));if(!r){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`Couldn't find any doc with id "${e}" in version${n.length>1?"s":""} "${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${l(t.map((e=>e.id))).join("\n- ")}`)}return r}),[e,n])}function _(e){let{route:t,versionMetadata:n}=e;const r=(0,a.TH)(),o=t.routes,s=o.find((e=>(0,a.LX)(r.pathname,e)));if(!s)return null;const c=s.sidebar,l=c?n.docsSidebars[c]:void 0;return{docElement:(0,i.H)(o),sidebarName:c,sidebarItems:l}}},1944:(e,t,n)=>{"use strict";n.d(t,{FG:()=>p,d:()=>u,VC:()=>f});var r=n(7294),a=n(6010),i=n(5742),o=n(226);function s(){const e=r.useContext(o._);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var c=n(4996),l=n(2263);function u(e){let{title:t,description:n,keywords:a,image:o,children:s}=e;const u=function(e){const{siteConfig:t}=(0,l.Z)(),{title:n,titleDelimiter:r}=t;return e?.trim().length?`${e.trim()} ${r} ${n}`:n}(t),{withBaseUrl:d}=(0,c.C)(),p=o?d(o,{absolute:!0}):void 0;return r.createElement(i.Z,null,t&&r.createElement("title",null,u),t&&r.createElement("meta",{property:"og:title",content:u}),n&&r.createElement("meta",{name:"description",content:n}),n&&r.createElement("meta",{property:"og:description",content:n}),a&&r.createElement("meta",{name:"keywords",content:Array.isArray(a)?a.join(","):a}),p&&r.createElement("meta",{property:"og:image",content:p}),p&&r.createElement("meta",{name:"twitter:image",content:p}),s)}const d=r.createContext(void 0);function p(e){let{className:t,children:n}=e;const o=r.useContext(d),s=(0,a.Z)(o,t);return r.createElement(d.Provider,{value:s},r.createElement(i.Z,null,r.createElement("html",{className:s})),n)}function f(e){let{children:t}=e;const n=s(),i=`plugin-${n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const o=`plugin-id-${n.plugin.id}`;return r.createElement(p,{className:(0,a.Z)(i,o)},t)}},902:(e,t,n)=>{"use strict";n.d(t,{D9:()=>o,Qc:()=>l,Ql:()=>c,i6:()=>s,zX:()=>i});var r=n(7294);const a=n(412).Z.canUseDOM?r.useLayoutEffect:r.useEffect;function i(e){const t=(0,r.useRef)(e);return a((()=>{t.current=e}),[e]),(0,r.useCallback)((function(){return t.current(...arguments)}),[])}function o(e){const t=(0,r.useRef)();return a((()=>{t.current=e})),t.current}class s extends Error{constructor(e,t){super(),this.name="ReactContextError",this.message=`Hook ${this.stack?.split("\n")[1]?.match(/at (?:\w+\.)?(?<name>\w+)/)?.groups.name??""} is called outside the <${e}>. ${t??""}`}}function c(e){const t=Object.entries(e);return t.sort(((e,t)=>e[0].localeCompare(t[0]))),(0,r.useMemo)((()=>e),t.flat())}function l(e){return t=>{let{children:n}=t;return r.createElement(r.Fragment,null,e.reduceRight(((e,t)=>r.createElement(t,null,e)),n))}}},8596:(e,t,n)=>{"use strict";n.d(t,{Mg:()=>o,Ns:()=>s});var r=n(7294),a=n(723),i=n(2263);function o(e,t){const n=e=>(!e||e.endsWith("/")?e:`${e}/`)?.toLowerCase();return n(e)===n(t)}function s(){const{baseUrl:e}=(0,i.Z)().siteConfig;return(0,r.useMemo)((()=>function(e){let{baseUrl:t,routes:n}=e;function r(e){return e.path===t&&!0===e.exact}function a(e){return e.path===t&&!e.exact}return function e(t){if(0===t.length)return;return t.find(r)||e(t.filter(a).flatMap((e=>e.routes??[])))}(n)}({routes:a.Z,baseUrl:e})),[e])}},2466:(e,t,n)=>{"use strict";n.d(t,{Ct:()=>p,OC:()=>c,RF:()=>d});var r=n(7294),a=n(412),i=n(2389),o=n(902);const s=r.createContext(void 0);function c(e){let{children:t}=e;const n=function(){const e=(0,r.useRef)(!0);return(0,r.useMemo)((()=>({scrollEventsEnabledRef:e,enableScrollEvents:()=>{e.current=!0},disableScrollEvents:()=>{e.current=!1}})),[])}();return r.createElement(s.Provider,{value:n},t)}function l(){const e=(0,r.useContext)(s);if(null==e)throw new o.i6("ScrollControllerProvider");return e}const u=()=>a.Z.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function d(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=l(),a=(0,r.useRef)(u()),i=(0,o.zX)(e);(0,r.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=u();i(e,a.current),a.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)}),[i,n,...t])}function p(){const e=(0,r.useRef)(null),t=(0,i.Z)()&&"smooth"===getComputedStyle(document.documentElement).scrollBehavior;return{startScroll:n=>{e.current=t?function(e){return window.scrollTo({top:e,behavior:"smooth"}),()=>{}}(n):function(e){let t=null;const n=document.documentElement.scrollTop>e;return function r(){const a=document.documentElement.scrollTop;(n&&a>e||!n&&a<e)&&(t=requestAnimationFrame(r),window.scrollTo(0,Math.floor(.85*(a-e))+e))}(),()=>t&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>e.current?.()}}},3320:(e,t,n)=>{"use strict";n.d(t,{HX:()=>r,os:()=>a});n(2263);const r="default";function a(e,t){return`docs-${e}-${t}`}},12:(e,t,n)=>{"use strict";n.d(t,{WA:()=>c});n(7294),n(1688);const r="localStorage";function a(e){let{key:t,oldValue:n,newValue:r,storage:a}=e;if(n===r)return;const i=document.createEvent("StorageEvent");i.initStorageEvent("storage",!1,!1,t,n,r,window.location.href,a),window.dispatchEvent(i)}function i(e){if(void 0===e&&(e=r),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,o||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),o=!0),null}var t}let o=!1;const s={get:()=>null,set:()=>{},del:()=>{},listen:()=>()=>{}};function c(e,t){if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t,listen:t}}(e);const n=i(t?.persistence);return null===n?s:{get:()=>{try{return n.getItem(e)}catch(t){return console.error(`Docusaurus storage error, can't get key=${e}`,t),null}},set:t=>{try{const r=n.getItem(e);n.setItem(e,t),a({key:e,oldValue:r,newValue:t,storage:n})}catch(r){console.error(`Docusaurus storage error, can't set ${e}=${t}`,r)}},del:()=>{try{const t=n.getItem(e);n.removeItem(e),a({key:e,oldValue:t,newValue:null,storage:n})}catch(t){console.error(`Docusaurus storage error, can't delete key=${e}`,t)}},listen:t=>{try{const r=r=>{r.storageArea===n&&r.key===e&&t(r)};return window.addEventListener("storage",r),()=>window.removeEventListener("storage",r)}catch(r){return console.error(`Docusaurus storage error, can't listen for changes of key=${e}`,r),()=>{}}}}}},4711:(e,t,n)=>{"use strict";n.d(t,{l:()=>i});var r=n(2263),a=n(6550);function i(){const{siteConfig:{baseUrl:e,url:t},i18n:{defaultLocale:n,currentLocale:i}}=(0,r.Z)(),{pathname:o}=(0,a.TH)(),s=i===n?e:e.replace(`/${i}/`,"/"),c=o.replace(e,"");return{createUrl:function(e){let{locale:r,fullyQualified:a}=e;return`${a?t:""}${function(e){return e===n?`${s}`:`${s}${e}/`}(r)}${c}`}}}},5936:(e,t,n)=>{"use strict";n.d(t,{S:()=>o});var r=n(7294),a=n(6550),i=n(902);function o(e){const t=(0,a.TH)(),n=(0,i.D9)(t),o=(0,i.zX)(e);(0,r.useEffect)((()=>{n&&t!==n&&o({location:t,previousLocation:n})}),[o,t,n])}},6668:(e,t,n)=>{"use strict";n.d(t,{L:()=>a});var r=n(2263);function a(){return(0,r.Z)().siteConfig.themeConfig}},8802:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){const{trailingSlash:n,baseUrl:r}=t;if(e.startsWith("#"))return e;if(void 0===n)return e;const[a]=e.split(/[#?]/),i="/"===a||a===r?a:(o=a,n?function(e){return e.endsWith("/")?e:`${e}/`}(o):function(e){return e.endsWith("/")?e.slice(0,-1):e}(o));var o;return e.replace(a,i)}},4143:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=void 0,t.getErrorCausalChain=function e(t){return t.cause?[t,...e(t.cause)]:[t]}},8780:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=t.applyTrailingSlash=t.blogPostContainerID=void 0,t.blogPostContainerID="__blog-post-container";var a=n(8802);Object.defineProperty(t,"applyTrailingSlash",{enumerable:!0,get:function(){return r(a).default}});var i=n(4143);Object.defineProperty(t,"getErrorCausalChain",{enumerable:!0,get:function(){return i.getErrorCausalChain}})},6010:(e,t,n)=>{"use strict";function r(e){var t,n,a="";if("string"==typeof e||"number"==typeof e)a+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;t<e.length;t++)e[t]&&(n=r(e[t]))&&(a&&(a+=" "),a+=n);else for(t in e)e[t]&&(a&&(a+=" "),a+=t);return a}n.d(t,{Z:()=>a});const a=function(){for(var e,t,n=0,a="";n<arguments.length;)(e=arguments[n++])&&(t=r(e))&&(a&&(a+=" "),a+=t);return a}},9318:(e,t,n)=>{"use strict";n.d(t,{lX:()=>w,q_:()=>C,ob:()=>f,PP:()=>L,Ep:()=>p});var r=n(7462);function a(e){return"/"===e.charAt(0)}function i(e,t){for(var n=t,r=n+1,a=e.length;r<a;n+=1,r+=1)e[n]=e[r];e.pop()}const o=function(e,t){void 0===t&&(t="");var n,r=e&&e.split("/")||[],o=t&&t.split("/")||[],s=e&&a(e),c=t&&a(t),l=s||c;if(e&&a(e)?o=r:r.length&&(o.pop(),o=o.concat(r)),!o.length)return"/";if(o.length){var u=o[o.length-1];n="."===u||".."===u||""===u}else n=!1;for(var d=0,p=o.length;p>=0;p--){var f=o[p];"."===f?i(o,p):".."===f?(i(o,p),d++):d&&(i(o,p),d--)}if(!l)for(;d--;d)o.unshift("..");!l||""===o[0]||o[0]&&a(o[0])||o.unshift("");var m=o.join("/");return n&&"/"!==m.substr(-1)&&(m+="/"),m};var s=n(8776);function c(e){return"/"===e.charAt(0)?e:"/"+e}function l(e){return"/"===e.charAt(0)?e.substr(1):e}function u(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function d(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function p(e){var t=e.pathname,n=e.search,r=e.hash,a=t||"/";return n&&"?"!==n&&(a+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(a+="#"===r.charAt(0)?r:"#"+r),a}function f(e,t,n,a){var i;"string"==typeof e?(i=function(e){var t=e||"/",n="",r="",a=t.indexOf("#");-1!==a&&(r=t.substr(a),t=t.substr(0,a));var i=t.indexOf("?");return-1!==i&&(n=t.substr(i),t=t.substr(0,i)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),i.state=t):(void 0===(i=(0,r.Z)({},e)).pathname&&(i.pathname=""),i.search?"?"!==i.search.charAt(0)&&(i.search="?"+i.search):i.search="",i.hash?"#"!==i.hash.charAt(0)&&(i.hash="#"+i.hash):i.hash="",void 0!==t&&void 0===i.state&&(i.state=t));try{i.pathname=decodeURI(i.pathname)}catch(s){throw s instanceof URIError?new URIError('Pathname "'+i.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):s}return n&&(i.key=n),a?i.pathname?"/"!==i.pathname.charAt(0)&&(i.pathname=o(i.pathname,a.pathname)):i.pathname=a.pathname:i.pathname||(i.pathname="/"),i}function m(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,a){if(null!=e){var i="function"==typeof e?e(t,n):e;"string"==typeof i?"function"==typeof r?r(i,a):a(!0):a(!1!==i)}else a(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter((function(e){return e!==r}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;r<e;r++)n[r]=arguments[r];t.forEach((function(e){return e.apply(void 0,n)}))}}}var h=!("undefined"==typeof window||!window.document||!window.document.createElement);function g(e,t){t(window.confirm(e))}var v="popstate",y="hashchange";function b(){try{return window.history.state||{}}catch(e){return{}}}function w(e){void 0===e&&(e={}),h||(0,s.Z)(!1);var t,n=window.history,a=(-1===(t=window.navigator.userAgent).indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone"))&&window.history&&"pushState"in window.history,i=!(-1===window.navigator.userAgent.indexOf("Trident")),o=e,l=o.forceRefresh,w=void 0!==l&&l,_=o.getUserConfirmation,S=void 0===_?g:_,k=o.keyLength,E=void 0===k?6:k,x=e.basename?d(c(e.basename)):"";function C(e){var t=e||{},n=t.key,r=t.state,a=window.location,i=a.pathname+a.search+a.hash;return x&&(i=u(i,x)),f(i,r,n)}function T(){return Math.random().toString(36).substr(2,E)}var L=m();function A(e){(0,r.Z)(z,e),z.length=n.length,L.notifyListeners(z.location,z.action)}function N(e){(function(e){return void 0===e.state&&-1===navigator.userAgent.indexOf("CriOS")})(e)||I(C(e.state))}function O(){I(C(b()))}var P=!1;function I(e){if(P)P=!1,A();else{L.confirmTransitionTo(e,"POP",S,(function(t){t?A({action:"POP",location:e}):function(e){var t=z.location,n=M.indexOf(t.key);-1===n&&(n=0);var r=M.indexOf(e.key);-1===r&&(r=0);var a=n-r;a&&(P=!0,F(a))}(e)}))}}var R=C(b()),M=[R.key];function D(e){return x+p(e)}function F(e){n.go(e)}var B=0;function j(e){1===(B+=e)&&1===e?(window.addEventListener(v,N),i&&window.addEventListener(y,O)):0===B&&(window.removeEventListener(v,N),i&&window.removeEventListener(y,O))}var $=!1;var z={length:n.length,action:"POP",location:R,createHref:D,push:function(e,t){var r="PUSH",i=f(e,t,T(),z.location);L.confirmTransitionTo(i,r,S,(function(e){if(e){var t=D(i),o=i.key,s=i.state;if(a)if(n.pushState({key:o,state:s},null,t),w)window.location.href=t;else{var c=M.indexOf(z.location.key),l=M.slice(0,c+1);l.push(i.key),M=l,A({action:r,location:i})}else window.location.href=t}}))},replace:function(e,t){var r="REPLACE",i=f(e,t,T(),z.location);L.confirmTransitionTo(i,r,S,(function(e){if(e){var t=D(i),o=i.key,s=i.state;if(a)if(n.replaceState({key:o,state:s},null,t),w)window.location.replace(t);else{var c=M.indexOf(z.location.key);-1!==c&&(M[c]=i.key),A({action:r,location:i})}else window.location.replace(t)}}))},go:F,goBack:function(){F(-1)},goForward:function(){F(1)},block:function(e){void 0===e&&(e=!1);var t=L.setPrompt(e);return $||(j(1),$=!0),function(){return $&&($=!1,j(-1)),t()}},listen:function(e){var t=L.appendListener(e);return j(1),function(){j(-1),t()}}};return z}var _="hashchange",S={hashbang:{encodePath:function(e){return"!"===e.charAt(0)?e:"!/"+l(e)},decodePath:function(e){return"!"===e.charAt(0)?e.substr(1):e}},noslash:{encodePath:l,decodePath:c},slash:{encodePath:c,decodePath:c}};function k(e){var t=e.indexOf("#");return-1===t?e:e.slice(0,t)}function E(){var e=window.location.href,t=e.indexOf("#");return-1===t?"":e.substring(t+1)}function x(e){window.location.replace(k(window.location.href)+"#"+e)}function C(e){void 0===e&&(e={}),h||(0,s.Z)(!1);var t=window.history,n=(window.navigator.userAgent.indexOf("Firefox"),e),a=n.getUserConfirmation,i=void 0===a?g:a,o=n.hashType,l=void 0===o?"slash":o,v=e.basename?d(c(e.basename)):"",y=S[l],b=y.encodePath,w=y.decodePath;function C(){var e=w(E());return v&&(e=u(e,v)),f(e)}var T=m();function L(e){(0,r.Z)($,e),$.length=t.length,T.notifyListeners($.location,$.action)}var A=!1,N=null;function O(){var e,t,n=E(),r=b(n);if(n!==r)x(r);else{var a=C(),o=$.location;if(!A&&(t=a,(e=o).pathname===t.pathname&&e.search===t.search&&e.hash===t.hash))return;if(N===p(a))return;N=null,function(e){if(A)A=!1,L();else{var t="POP";T.confirmTransitionTo(e,t,i,(function(n){n?L({action:t,location:e}):function(e){var t=$.location,n=M.lastIndexOf(p(t));-1===n&&(n=0);var r=M.lastIndexOf(p(e));-1===r&&(r=0);var a=n-r;a&&(A=!0,D(a))}(e)}))}}(a)}}var P=E(),I=b(P);P!==I&&x(I);var R=C(),M=[p(R)];function D(e){t.go(e)}var F=0;function B(e){1===(F+=e)&&1===e?window.addEventListener(_,O):0===F&&window.removeEventListener(_,O)}var j=!1;var $={length:t.length,action:"POP",location:R,createHref:function(e){var t=document.querySelector("base"),n="";return t&&t.getAttribute("href")&&(n=k(window.location.href)),n+"#"+b(v+p(e))},push:function(e,t){var n="PUSH",r=f(e,void 0,void 0,$.location);T.confirmTransitionTo(r,n,i,(function(e){if(e){var t=p(r),a=b(v+t);if(E()!==a){N=t,function(e){window.location.hash=e}(a);var i=M.lastIndexOf(p($.location)),o=M.slice(0,i+1);o.push(t),M=o,L({action:n,location:r})}else L()}}))},replace:function(e,t){var n="REPLACE",r=f(e,void 0,void 0,$.location);T.confirmTransitionTo(r,n,i,(function(e){if(e){var t=p(r),a=b(v+t);E()!==a&&(N=t,x(a));var i=M.indexOf(p($.location));-1!==i&&(M[i]=t),L({action:n,location:r})}}))},go:D,goBack:function(){D(-1)},goForward:function(){D(1)},block:function(e){void 0===e&&(e=!1);var t=T.setPrompt(e);return j||(B(1),j=!0),function(){return j&&(j=!1,B(-1)),t()}},listen:function(e){var t=T.appendListener(e);return B(1),function(){B(-1),t()}}};return $}function T(e,t,n){return Math.min(Math.max(e,t),n)}function L(e){void 0===e&&(e={});var t=e,n=t.getUserConfirmation,a=t.initialEntries,i=void 0===a?["/"]:a,o=t.initialIndex,s=void 0===o?0:o,c=t.keyLength,l=void 0===c?6:c,u=m();function d(e){(0,r.Z)(w,e),w.length=w.entries.length,u.notifyListeners(w.location,w.action)}function h(){return Math.random().toString(36).substr(2,l)}var g=T(s,0,i.length-1),v=i.map((function(e){return f(e,void 0,"string"==typeof e?h():e.key||h())})),y=p;function b(e){var t=T(w.index+e,0,w.entries.length-1),r=w.entries[t];u.confirmTransitionTo(r,"POP",n,(function(e){e?d({action:"POP",location:r,index:t}):d()}))}var w={length:v.length,action:"POP",location:v[g],index:g,entries:v,createHref:y,push:function(e,t){var r="PUSH",a=f(e,t,h(),w.location);u.confirmTransitionTo(a,r,n,(function(e){if(e){var t=w.index+1,n=w.entries.slice(0);n.length>t?n.splice(t,n.length-t,a):n.push(a),d({action:r,location:a,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",a=f(e,t,h(),w.location);u.confirmTransitionTo(a,r,n,(function(e){e&&(w.entries[w.index]=a,d({action:r,location:a}))}))},go:b,goBack:function(){b(-1)},goForward:function(){b(1)},canGo:function(e){var t=w.index+e;return t>=0&&t<w.entries.length},block:function(e){return void 0===e&&(e=!1),u.setPrompt(e)},listen:function(e){return u.appendListener(e)}};return w}},8679:(e,t,n)=>{"use strict";var r=n(9864),a={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},i={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},o={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},s={};function c(e){return r.isMemo(e)?o:s[e.$$typeof]||a}s[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},s[r.Memo]=o;var l=Object.defineProperty,u=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,p=Object.getOwnPropertyDescriptor,f=Object.getPrototypeOf,m=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(m){var a=f(n);a&&a!==m&&e(t,a,r)}var o=u(n);d&&(o=o.concat(d(n)));for(var s=c(t),h=c(n),g=0;g<o.length;++g){var v=o[g];if(!(i[v]||r&&r[v]||h&&h[v]||s&&s[v])){var y=p(n,v);try{l(t,v,y)}catch(b){}}}}return t}},1143:e=>{"use strict";e.exports=function(e,t,n,r,a,i,o,s){if(!e){var c;if(void 0===t)c=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var l=[n,r,a,i,o,s],u=0;(c=new Error(t.replace(/%s/g,(function(){return l[u++]})))).name="Invariant Violation"}throw c.framesToPop=1,c}}},5826:e=>{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},2497:(e,t,n)=>{"use strict";n.r(t)},2295:(e,t,n)=>{"use strict";n.r(t)},4865:function(e,t,n){var r,a;r=function(){var e,t,n={version:"0.2.0"},r=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'};function a(e,t,n){return e<t?t:e>n?n:e}function i(e){return 100*(-1+e)}function o(e,t,n){var a;return(a="translate3d"===r.positionUsing?{transform:"translate3d("+i(e)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+i(e)+"%,0)"}:{"margin-left":i(e)+"%"}).transition="all "+t+"ms "+n,a}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(r[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=a(e,r.minimum,1),n.status=1===e?null:e;var i=n.render(!t),l=i.querySelector(r.barSelector),u=r.speed,d=r.easing;return i.offsetWidth,s((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),c(l,o(e,u,d)),1===e?(c(i,{transition:"none",opacity:1}),i.offsetWidth,setTimeout((function(){c(i,{transition:"all "+u+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),u)}),u)):setTimeout(t,u)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*a(Math.random()*t,.1,.95)),t=a(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},e=0,t=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===t&&n.start(),e++,t++,r.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");u(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=r.template;var a,o=t.querySelector(r.barSelector),s=e?"-100":i(n.status||0),l=document.querySelector(r.parent);return c(o,{transition:"all 0 linear",transform:"translate3d("+s+"%,0,0)"}),r.showSpinner||(a=t.querySelector(r.spinnerSelector))&&f(a),l!=document.body&&u(l,"nprogress-custom-parent"),l.appendChild(t),t},n.remove=function(){d(document.documentElement,"nprogress-busy"),d(document.querySelector(r.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&f(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var s=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),c=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()}))}function r(t){var n=document.body.style;if(t in n)return t;for(var r,a=e.length,i=t.charAt(0).toUpperCase()+t.slice(1);a--;)if((r=e[a]+i)in n)return r;return t}function a(e){return e=n(e),t[e]||(t[e]=r(e))}function i(e,t,n){t=a(t),e.style[t]=n}return function(e,t){var n,r,a=arguments;if(2==a.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&i(e,n,r);else i(e,a[1],a[2])}}();function l(e,t){return("string"==typeof e?e:p(e)).indexOf(" "+t+" ")>=0}function u(e,t){var n=p(e),r=n+t;l(n,t)||(e.className=r.substring(1))}function d(e,t){var n,r=p(e);l(e,t)&&(n=r.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function p(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function f(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(a="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=a)},7418:e=>{"use strict";var t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(a){return!1}}()?Object.assign:function(e,a){for(var i,o,s=function(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}(e),c=1;c<arguments.length;c++){for(var l in i=Object(arguments[c]))n.call(i,l)&&(s[l]=i[l]);if(t){o=t(i);for(var u=0;u<o.length;u++)r.call(i,o[u])&&(s[o[u]]=i[o[u]])}}return s}},4779:(e,t,n)=>{var r=n(5826);e.exports=f,e.exports.parse=i,e.exports.compile=function(e,t){return s(i(e,t),t)},e.exports.tokensToFunction=s,e.exports.tokensToRegExp=p;var a=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");function i(e,t){for(var n,r=[],i=0,o=0,s="",u=t&&t.delimiter||"/";null!=(n=a.exec(e));){var d=n[0],p=n[1],f=n.index;if(s+=e.slice(o,f),o=f+d.length,p)s+=p[1];else{var m=e[o],h=n[2],g=n[3],v=n[4],y=n[5],b=n[6],w=n[7];s&&(r.push(s),s="");var _=null!=h&&null!=m&&m!==h,S="+"===b||"*"===b,k="?"===b||"*"===b,E=n[2]||u,x=v||y;r.push({name:g||i++,prefix:h||"",delimiter:E,optional:k,repeat:S,partial:_,asterisk:!!w,pattern:x?l(x):w?".*":"[^"+c(E)+"]+?"})}}return o<e.length&&(s+=e.substr(o)),s&&r.push(s),r}function o(e){return encodeURI(e).replace(/[\/?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}function s(e,t){for(var n=new Array(e.length),a=0;a<e.length;a++)"object"==typeof e[a]&&(n[a]=new RegExp("^(?:"+e[a].pattern+")$",d(t)));return function(t,a){for(var i="",s=t||{},c=(a||{}).pretty?o:encodeURIComponent,l=0;l<e.length;l++){var u=e[l];if("string"!=typeof u){var d,p=s[u.name];if(null==p){if(u.optional){u.partial&&(i+=u.prefix);continue}throw new TypeError('Expected "'+u.name+'" to be defined')}if(r(p)){if(!u.repeat)throw new TypeError('Expected "'+u.name+'" to not repeat, but received `'+JSON.stringify(p)+"`");if(0===p.length){if(u.optional)continue;throw new TypeError('Expected "'+u.name+'" to not be empty')}for(var f=0;f<p.length;f++){if(d=c(p[f]),!n[l].test(d))throw new TypeError('Expected all "'+u.name+'" to match "'+u.pattern+'", but received `'+JSON.stringify(d)+"`");i+=(0===f?u.prefix:u.delimiter)+d}}else{if(d=u.asterisk?encodeURI(p).replace(/[?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()})):c(p),!n[l].test(d))throw new TypeError('Expected "'+u.name+'" to match "'+u.pattern+'", but received "'+d+'"');i+=u.prefix+d}}else i+=u}return i}}function c(e){return e.replace(/([.+*?=^!:${}()[\]|\/\\])/g,"\\$1")}function l(e){return e.replace(/([=!:$\/()])/g,"\\$1")}function u(e,t){return e.keys=t,e}function d(e){return e&&e.sensitive?"":"i"}function p(e,t,n){r(t)||(n=t||n,t=[]);for(var a=(n=n||{}).strict,i=!1!==n.end,o="",s=0;s<e.length;s++){var l=e[s];if("string"==typeof l)o+=c(l);else{var p=c(l.prefix),f="(?:"+l.pattern+")";t.push(l),l.repeat&&(f+="(?:"+p+f+")*"),o+=f=l.optional?l.partial?p+"("+f+")?":"(?:"+p+"("+f+"))?":p+"("+f+")"}}var m=c(n.delimiter||"/"),h=o.slice(-m.length)===m;return a||(o=(h?o.slice(0,-m.length):o)+"(?:"+m+"(?=$))?"),o+=i?"$":a&&h?"":"(?="+m+"|$)",u(new RegExp("^"+o,d(n)),t)}function f(e,t,n){return r(t)||(n=t||n,t=[]),n=n||{},e instanceof RegExp?function(e,t){var n=e.source.match(/\((?!\?)/g);if(n)for(var r=0;r<n.length;r++)t.push({name:r,prefix:null,delimiter:null,optional:!1,repeat:!1,partial:!1,asterisk:!1,pattern:null});return u(e,t)}(e,t):r(e)?function(e,t,n){for(var r=[],a=0;a<e.length;a++)r.push(f(e[a],t,n).source);return u(new RegExp("(?:"+r.join("|")+")",d(n)),t)}(e,t,n):function(e,t,n){return p(i(e,n),t,n)}(e,t,n)}},7410:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=function(){var e=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,n={},r={util:{encode:function e(t){return t instanceof a?new a(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function e(t,n){var a,i;switch(n=n||{},r.util.type(t)){case"Object":if(i=r.util.objId(t),n[i])return n[i];for(var o in a={},n[i]=a,t)t.hasOwnProperty(o)&&(a[o]=e(t[o],n));return a;case"Array":return i=r.util.objId(t),n[i]?n[i]:(a=[],n[i]=a,t.forEach((function(t,r){a[r]=e(t,n)})),a);default:return t}},getLanguage:function(t){for(;t;){var n=e.exec(t.className);if(n)return n[1].toLowerCase();t=t.parentElement}return"none"},setLanguage:function(t,n){t.className=t.className.replace(RegExp(e,"gi"),""),t.classList.add("language-"+n)},isActive:function(e,t,n){for(var r="no-"+t;e;){var a=e.classList;if(a.contains(t))return!0;if(a.contains(r))return!1;e=e.parentElement}return!!n}},languages:{plain:n,plaintext:n,text:n,txt:n,extend:function(e,t){var n=r.util.clone(r.languages[e]);for(var a in t)n[a]=t[a];return n},insertBefore:function(e,t,n,a){var i=(a=a||r.languages)[e],o={};for(var s in i)if(i.hasOwnProperty(s)){if(s==t)for(var c in n)n.hasOwnProperty(c)&&(o[c]=n[c]);n.hasOwnProperty(s)||(o[s]=i[s])}var l=a[e];return a[e]=o,r.languages.DFS(r.languages,(function(t,n){n===l&&t!=e&&(this[t]=o)})),o},DFS:function e(t,n,a,i){i=i||{};var o=r.util.objId;for(var s in t)if(t.hasOwnProperty(s)){n.call(t,s,t[s],a||s);var c=t[s],l=r.util.type(c);"Object"!==l||i[o(c)]?"Array"!==l||i[o(c)]||(i[o(c)]=!0,e(c,n,s,i)):(i[o(c)]=!0,e(c,n,null,i))}}},plugins:{},highlight:function(e,t,n){var i={code:e,grammar:t,language:n};return r.hooks.run("before-tokenize",i),i.tokens=r.tokenize(i.code,i.grammar),r.hooks.run("after-tokenize",i),a.stringify(r.util.encode(i.tokens),i.language)},tokenize:function(e,t){var n=t.rest;if(n){for(var r in n)t[r]=n[r];delete t.rest}var a=new s;return c(a,a.head,e),o(e,a,t,a.head,0),function(e){var t=[],n=e.head.next;for(;n!==e.tail;)t.push(n.value),n=n.next;return t}(a)},hooks:{all:{},add:function(e,t){var n=r.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=r.hooks.all[e];if(n&&n.length)for(var a,i=0;a=n[i++];)a(t)}},Token:a};function a(e,t,n,r){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length}function i(e,t,n,r){e.lastIndex=t;var a=e.exec(n);if(a&&r&&a[1]){var i=a[1].length;a.index+=i,a[0]=a[0].slice(i)}return a}function o(e,t,n,s,u,d){for(var p in n)if(n.hasOwnProperty(p)&&n[p]){var f=n[p];f=Array.isArray(f)?f:[f];for(var m=0;m<f.length;++m){if(d&&d.cause==p+","+m)return;var h=f[m],g=h.inside,v=!!h.lookbehind,y=!!h.greedy,b=h.alias;if(y&&!h.pattern.global){var w=h.pattern.toString().match(/[imsuy]*$/)[0];h.pattern=RegExp(h.pattern.source,w+"g")}for(var _=h.pattern||h,S=s.next,k=u;S!==t.tail&&!(d&&k>=d.reach);k+=S.value.length,S=S.next){var E=S.value;if(t.length>e.length)return;if(!(E instanceof a)){var x,C=1;if(y){if(!(x=i(_,k,e,v))||x.index>=e.length)break;var T=x.index,L=x.index+x[0].length,A=k;for(A+=S.value.length;T>=A;)A+=(S=S.next).value.length;if(k=A-=S.value.length,S.value instanceof a)continue;for(var N=S;N!==t.tail&&(A<L||"string"==typeof N.value);N=N.next)C++,A+=N.value.length;C--,E=e.slice(k,A),x.index-=k}else if(!(x=i(_,0,E,v)))continue;T=x.index;var O=x[0],P=E.slice(0,T),I=E.slice(T+O.length),R=k+E.length;d&&R>d.reach&&(d.reach=R);var M=S.prev;if(P&&(M=c(t,M,P),k+=P.length),l(t,M,C),S=c(t,M,new a(p,g?r.tokenize(O,g):O,b,O)),I&&c(t,S,I),C>1){var D={cause:p+","+m,reach:R};o(e,t,n,S.prev,k,D),d&&D.reach>d.reach&&(d.reach=D.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function c(e,t,n){var r=t.next,a={value:n,prev:t,next:r};return t.next=a,r.prev=a,e.length++,a}function l(e,t,n){for(var r=t.next,a=0;a<n&&r!==e.tail;a++)r=r.next;t.next=r,r.prev=t,e.length-=a}return a.stringify=function e(t,n){if("string"==typeof t)return t;if(Array.isArray(t)){var a="";return t.forEach((function(t){a+=e(t,n)})),a}var i={type:t.type,content:e(t.content,n),tag:"span",classes:["token",t.type],attributes:{},language:n},o=t.alias;o&&(Array.isArray(o)?Array.prototype.push.apply(i.classes,o):i.classes.push(o)),r.hooks.run("wrap",i);var s="";for(var c in i.attributes)s+=" "+c+'="'+(i.attributes[c]||"").replace(/"/g,""")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'"'+s+">"+i.content+"</"+i.tag+">"},r}(),a=r;r.default=r,a.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\s\S])*?-->/,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},a.languages.markup.tag.inside["attr-value"].inside.entity=a.languages.markup.entity,a.languages.markup.doctype.inside["internal-subset"].inside=a.languages.markup,a.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(a.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,lookbehind:!0,inside:a.languages[t]},n.cdata=/^<!\[CDATA\[|\]\]>$/i;var r={"included-cdata":{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,inside:n}};r["language-"+t]={pattern:/[\s\S]+/,inside:a.languages[t]};var i={};i[e]={pattern:RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:r},a.languages.insertBefore("markup","cdata",i)}}),Object.defineProperty(a.languages.markup.tag,"addAttribute",{value:function(e,t){a.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:a.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),a.languages.html=a.languages.markup,a.languages.mathml=a.languages.markup,a.languages.svg=a.languages.markup,a.languages.xml=a.languages.extend("markup",{}),a.languages.ssml=a.languages.xml,a.languages.atom=a.languages.xml,a.languages.rss=a.languages.xml,function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},r={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:r},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:r},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:r.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:r.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var a=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],i=r.variable[1].inside,o=0;o<a.length;o++)i[a[o]]=e.languages.bash[a[o]];e.languages.shell=e.languages.bash}(a),a.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},a.languages.c=a.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),a.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),a.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},a.languages.c.string],char:a.languages.c.char,comment:a.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:a.languages.c}}}}),a.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete a.languages.c.boolean,function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source.replace(/<keyword>/g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(a),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-](?:[^;{\s]|\s+(?![\s{]))*(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var n=e.languages.markup;n&&(n.tag.addInlined("style","css"),n.tag.addAttribute("style","css"))}(a),function(e){var t,n=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;e.languages.css.selector={pattern:e.languages.css.selector.pattern,lookbehind:!0,inside:t={"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+/,class:/\.[-\w]+/,id:/#[-\w]+/,attribute:{pattern:RegExp("\\[(?:[^[\\]\"']|"+n.source+")*\\]"),greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)(?:(?!\s)[-*\w\xA0-\uFFFF])*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},"attr-name":{pattern:/^(\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+/,lookbehind:!0},"attr-value":[n,{pattern:/(=\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},"n-th":[{pattern:/(\(\s*)[+-]?\d*[\dn](?:\s*[+-]\s*\d+)?(?=\s*\))/,lookbehind:!0,inside:{number:/[\dn]+/,operator:/[+-]/}},{pattern:/(\(\s*)(?:even|odd)(?=\s*\))/i,lookbehind:!0}],combinator:/>|\+|~|\|\|/,punctuation:/[(),]/}},e.languages.css.atrule.inside["selector-function-argument"].inside=t,e.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*/i,lookbehind:!0}});var r={pattern:/(\b\d+)(?:%|[a-z]+(?![\w-]))/,lookbehind:!0},a={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0};e.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:{pattern:/\B#[\da-f]{3,8}\b/i,alias:"color"},color:[{pattern:/(^|[^\w-])(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)(?![\w-])/i,lookbehind:!0},{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:r,number:a,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:r,number:a})}(a),a.languages.javascript=a.languages.extend("clike",{"class-name":[a.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),a.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,a.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:a.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:a.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:a.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:a.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:a.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),a.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:a.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),a.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),a.languages.markup&&(a.languages.markup.tag.addInlined("script","javascript"),a.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),a.languages.js=a.languages.javascript,function(e){var t=/#(?!\{).+/,n={pattern:/#\{[^}]+\}/,alias:"variable"};e.languages.coffeescript=e.languages.extend("javascript",{comment:t,string:[{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,inside:{interpolation:n}}],keyword:/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),e.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:t,interpolation:n}}}),e.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},script:{pattern:/[\s\S]+/,alias:"language-javascript",inside:e.languages.javascript}}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,greedy:!0,alias:"string"},{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string",inside:{interpolation:n}}]}),e.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/}),delete e.languages.coffeescript["template-string"],e.languages.coffee=e.languages.coffeescript}(a),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",a=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-]<PLAIN>)(?:[ \t]*(?:(?![#:])<PLAIN>|:<PLAIN>))*/.source.replace(/<PLAIN>/g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),i=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function o(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<value>>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<<prop>>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<<prop>>/g,(function(){return r}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<<prop>>[ \t]+)?)<<key>>(?=\s*:\s)/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<key>>/g,(function(){return"(?:"+a+"|"+i+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:o(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:o(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:o(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:o(i),lookbehind:!0,greedy:!0},number:{pattern:o(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(a),function(e){var t=/(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source;function n(e){return e=e.replace(/<inner>/g,(function(){return t})),RegExp(/((?:^|[^\\])(?:\\{2})*)/.source+"(?:"+e+")")}var r=/(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source,a=/\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g,(function(){return r})),i=/\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source;e.languages.markdown=e.languages.extend("markup",{}),e.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"front-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:e.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+a+i+"(?:"+a+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+a+i+")(?:"+a+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(r),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+a+")"+i+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+a+"$"),inside:{"table-header":{pattern:RegExp(r),alias:"important",inside:e.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n(/\b__(?:(?!_)<inner>|_(?:(?!_)<inner>)+_)+__\b|\*\*(?:(?!\*)<inner>|\*(?:(?!\*)<inner>)+\*)+\*\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/\b_(?:(?!_)<inner>|__(?:(?!_)<inner>)+__)+_\b|\*(?:(?!\*)<inner>|\*\*(?:(?!\*)<inner>)+\*\*)+\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~)<inner>)+\2/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:n(/!?\[(?:(?!\])<inner>)+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\])<inner>)+\])/.source),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(t){["url","bold","italic","strike","code-snippet"].forEach((function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])}))})),e.hooks.add("after-tokenize",(function(e){"markdown"!==e.language&&"md"!==e.language||function e(t){if(t&&"string"!=typeof t)for(var n=0,r=t.length;n<r;n++){var a=t[n];if("code"===a.type){var i=a.content[1],o=a.content[3];if(i&&o&&"code-language"===i.type&&"code-block"===o.type&&"string"==typeof i.content){var s=i.content.replace(/\b#/g,"sharp").replace(/\b\+\+/g,"pp"),c="language-"+(s=(/[a-z][\w-]*/i.exec(s)||[""])[0].toLowerCase());o.alias?"string"==typeof o.alias?o.alias=[o.alias,c]:o.alias.push(c):o.alias=[c]}}else e(a.content)}}(e.tokens)})),e.hooks.add("wrap",(function(t){if("code-block"===t.type){for(var n="",r=0,a=t.classes.length;r<a;r++){var i=t.classes[r],l=/language-(.+)/.exec(i);if(l){n=l[1];break}}var u,d=e.languages[n];if(d)t.content=e.highlight((u=t.content,u.replace(o,"").replace(/&(\w{1,8}|#x?[\da-f]{1,8});/gi,(function(e,t){var n;if("#"===(t=t.toLowerCase())[0])return n="x"===t[1]?parseInt(t.slice(2),16):Number(t.slice(1)),c(n);var r=s[t];return r||e}))),d,n);else if(n&&"none"!==n&&e.plugins.autoloader){var p="md-"+(new Date).valueOf()+"-"+Math.floor(1e16*Math.random());t.attributes.id=p,e.plugins.autoloader.loadLanguages(n,(function(){var t=document.getElementById(p);t&&(t.innerHTML=e.highlight(t.textContent,e.languages[n],n))}))}}}));var o=RegExp(e.languages.markup.tag.pattern.source,"gi"),s={amp:"&",lt:"<",gt:">",quot:'"'},c=String.fromCodePoint||String.fromCharCode;e.languages.md=e.languages.markdown}(a),a.languages.graphql={comment:/#.*/,description:{pattern:/(?:"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*")(?=\s*[a-z_])/i,greedy:!0,alias:"string",inside:{"language-markdown":{pattern:/(^"(?:"")?)(?!\1)[\s\S]+(?=\1$)/,lookbehind:!0,inside:a.languages.markdown}}},string:{pattern:/"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},number:/(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,boolean:/\b(?:false|true)\b/,variable:/\$[a-z_]\w*/i,directive:{pattern:/@[a-z_]\w*/i,alias:"function"},"attr-name":{pattern:/\b[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i,greedy:!0},"atom-input":{pattern:/\b[A-Z]\w*Input\b/,alias:"class-name"},scalar:/\b(?:Boolean|Float|ID|Int|String)\b/,constant:/\b[A-Z][A-Z_\d]*\b/,"class-name":{pattern:/(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*|:\s*|\[)[A-Z_]\w*/,lookbehind:!0},fragment:{pattern:/(\bfragment\s+|\.{3}\s*(?!on\b))[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-mutation":{pattern:/(\bmutation\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-query":{pattern:/(\bquery\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},keyword:/\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\b/,operator:/[!=|&]|\.{3}/,"property-query":/\w+(?=\s*\()/,object:/\w+(?=\s*\{)/,punctuation:/[!(){}\[\]:=,]/,property:/\w+/},a.hooks.add("after-tokenize",(function(e){if("graphql"===e.language)for(var t=e.tokens.filter((function(e){return"string"!=typeof e&&"comment"!==e.type&&"scalar"!==e.type})),n=0;n<t.length;){var r=t[n++];if("keyword"===r.type&&"mutation"===r.content){var a=[];if(d(["definition-mutation","punctuation"])&&"("===u(1).content){n+=2;var i=p(/^\($/,/^\)$/);if(-1===i)continue;for(;n<i;n++){var o=u(0);"variable"===o.type&&(f(o,"variable-input"),a.push(o.content))}n=i+1}if(d(["punctuation","property-query"])&&"{"===u(0).content&&(n++,f(u(0),"property-mutation"),a.length>0)){var s=p(/^\{$/,/^\}$/);if(-1===s)continue;for(var c=n;c<s;c++){var l=t[c];"variable"===l.type&&a.indexOf(l.content)>=0&&f(l,"variable-input")}}}}function u(e){return t[n+e]}function d(e,t){t=t||0;for(var n=0;n<e.length;n++){var r=u(n+t);if(!r||r.type!==e[n])return!1}return!0}function p(e,r){for(var a=1,i=n;i<t.length;i++){var o=t[i],s=o.content;if("punctuation"===o.type&&"string"==typeof s)if(e.test(s))a++;else if(r.test(s)&&0===--a)return i}return-1}function f(e,t){var n=e.alias;n?Array.isArray(n)||(e.alias=n=[n]):e.alias=n=[],n.push(t)}})),a.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},identifier:{pattern:/(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,greedy:!0,lookbehind:!0,inside:{punctuation:/^`|`$/}},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:FALSE|NULL|TRUE)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t=e.languages.javascript["template-string"],n=t.pattern.source,r=t.inside.interpolation,a=r.inside["interpolation-punctuation"],i=r.pattern.source;function o(t,r){if(e.languages[t])return{pattern:RegExp("((?:"+r+")\\s*)"+n),lookbehind:!0,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},"embedded-code":{pattern:/[\s\S]+/,alias:t}}}}function s(e,t){return"___"+t.toUpperCase()+"_"+e+"___"}function c(t,n,r){var a={code:t,grammar:n,language:r};return e.hooks.run("before-tokenize",a),a.tokens=e.tokenize(a.code,a.grammar),e.hooks.run("after-tokenize",a),a.tokens}function l(t){var n={};n["interpolation-punctuation"]=a;var i=e.tokenize(t,n);if(3===i.length){var o=[1,1];o.push.apply(o,c(i[1],e.languages.javascript,"javascript")),i.splice.apply(i,o)}return new e.Token("interpolation",i,r.alias,t)}function u(t,n,r){var a=e.tokenize(t,{interpolation:{pattern:RegExp(i),lookbehind:!0}}),o=0,u={},d=c(a.map((function(e){if("string"==typeof e)return e;for(var n,a=e.content;-1!==t.indexOf(n=s(o++,r)););return u[n]=a,n})).join(""),n,r),p=Object.keys(u);return o=0,function e(t){for(var n=0;n<t.length;n++){if(o>=p.length)return;var r=t[n];if("string"==typeof r||"string"==typeof r.content){var a=p[o],i="string"==typeof r?r:r.content,s=i.indexOf(a);if(-1!==s){++o;var c=i.substring(0,s),d=l(u[a]),f=i.substring(s+a.length),m=[];if(c&&m.push(c),m.push(d),f){var h=[f];e(h),m.push.apply(m,h)}"string"==typeof r?(t.splice.apply(t,[n,1].concat(m)),n+=m.length-1):r.content=m}}else{var g=r.content;Array.isArray(g)?e(g):e([g])}}}(d),new e.Token(r,d,"language-"+r,t)}e.languages.javascript["template-string"]=[o("css",/\b(?:styled(?:\([^)]*\))?(?:\s*\.\s*\w+(?:\([^)]*\))*)*|css(?:\s*\.\s*(?:global|resolve))?|createGlobalStyle|keyframes)/.source),o("html",/\bhtml|\.\s*(?:inner|outer)HTML\s*\+?=/.source),o("svg",/\bsvg/.source),o("markdown",/\b(?:markdown|md)/.source),o("graphql",/\b(?:gql|graphql(?:\s*\.\s*experimental)?)/.source),o("sql",/\bsql/.source),t].filter(Boolean);var d={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function p(e){return"string"==typeof e?e:Array.isArray(e)?e.map(p).join(""):p(e.content)}e.hooks.add("after-tokenize",(function(t){t.language in d&&function t(n){for(var r=0,a=n.length;r<a;r++){var i=n[r];if("string"!=typeof i){var o=i.content;if(Array.isArray(o))if("template-string"===i.type){var s=o[1];if(3===o.length&&"string"!=typeof s&&"embedded-code"===s.type){var c=p(s),l=s.alias,d=Array.isArray(l)?l[0]:l,f=e.languages[d];if(!f)continue;o[1]=u(c,f,d)}}else t(o);else"string"!=typeof o&&t([o])}}}(t.tokens)}))}(a),function(e){e.languages.typescript=e.languages.extend("javascript",{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var t=e.languages.extend("typescript",{});delete t["class-name"],e.languages.typescript["class-name"].inside=t,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t}}}}),e.languages.ts=e.languages.typescript}(a),function(e){function t(e,t){return RegExp(e.replace(/<ID>/g,(function(){return/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/.source})),t)}e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|(?:Weak)?(?:Map|Set)|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.insertBefore("javascript","keyword",{imports:{pattern:t(/(\bimport\b\s*)(?:<ID>(?:\s*,\s*(?:\*\s*as\s+<ID>|\{[^{}]*\}))?|\*\s*as\s+<ID>|\{[^{}]*\})(?=\s*\bfrom\b)/.source),lookbehind:!0,inside:e.languages.javascript},exports:{pattern:t(/(\bexport\b\s*)(?:\*(?:\s*as\s+<ID>)?(?=\s*\bfrom\b)|\{[^{}]*\})/.source),lookbehind:!0,inside:e.languages.javascript}}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\b(?:await|break|catch|continue|do|else|finally|for|if|return|switch|throw|try|while|yield)\b/,alias:"control-flow"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:t(/(\.\s*)#?<ID>/.source),lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|(?:local|session)Storage|location|navigator|performance|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var n=["function","function-variable","method","method-variable","property-access"],r=0;r<n.length;r++){var a=n[r],i=e.languages.javascript[a];"RegExp"===e.util.type(i)&&(i=e.languages.javascript[a]={pattern:i});var o=i.inside||{};i.inside=o,o["maybe-class-name"]=/^[A-Z][\s\S]*/}}(a),function(e){var t=e.util.clone(e.languages.javascript),n=/(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source,r=/(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source,a=/(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;function i(e,t){return e=e.replace(/<S>/g,(function(){return n})).replace(/<BRACES>/g,(function(){return r})).replace(/<SPREAD>/g,(function(){return a})),RegExp(e,t)}a=i(a).source,e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=i(/<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:i(/<SPREAD>/.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:i(/=<BRACES>/.source),alias:"language-javascript",inside:{"script-punctuation":{pattern:/^=(?=\{)/,alias:"punctuation"},rest:e.languages.jsx}}},e.languages.jsx.tag);var o=function(e){return e?"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(o).join(""):""},s=function(t){for(var n=[],r=0;r<t.length;r++){var a=t[r],i=!1;if("string"!=typeof a&&("tag"===a.type&&a.content[0]&&"tag"===a.content[0].type?"</"===a.content[0].content[0].content?n.length>0&&n[n.length-1].tagName===o(a.content[0].content[1])&&n.pop():"/>"===a.content[a.content.length-1].content||n.push({tagName:o(a.content[0].content[1]),openedBraces:0}):n.length>0&&"punctuation"===a.type&&"{"===a.content?n[n.length-1].openedBraces++:n.length>0&&n[n.length-1].openedBraces>0&&"punctuation"===a.type&&"}"===a.content?n[n.length-1].openedBraces--:i=!0),(i||"string"==typeof a)&&n.length>0&&0===n[n.length-1].openedBraces){var c=o(a);r<t.length-1&&("string"==typeof t[r+1]||"plain-text"===t[r+1].type)&&(c+=o(t[r+1]),t.splice(r+1,1)),r>0&&("string"==typeof t[r-1]||"plain-text"===t[r-1].type)&&(c=o(t[r-1])+c,t.splice(r-1,1),r--),t[r]=new e.Token("plain-text",c,null,c)}a.content&&"string"!=typeof a.content&&s(a.content)}};e.hooks.add("after-tokenize",(function(e){"jsx"!==e.language&&"tsx"!==e.language||s(e.tokens)}))}(a),function(e){e.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d.*$/m]};var t={"deleted-sign":"-","deleted-arrow":"<","inserted-sign":"+","inserted-arrow":">",unchanged:" ",diff:"!"};Object.keys(t).forEach((function(n){var r=t[n],a=[];/^\w+$/.test(n)||a.push(/\w+/.exec(n)[0]),"diff"===n&&a.push("bold"),e.languages.diff[n]={pattern:RegExp("^(?:["+r+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:a,inside:{line:{pattern:/(.)(?=[\s\S]).*(?:\r\n?|\n)?/,lookbehind:!0},prefix:{pattern:/[\s\S]/,alias:/\w+/.exec(n)[0]}}}})),Object.defineProperty(e.languages.diff,"PREFIXES",{value:t})}(a),a.languages.git={comment:/^#.*/m,deleted:/^[-\u2013].*/m,inserted:/^\+.*/m,string:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s--?\w+/}},coord:/^@@.*@@$/m,"commit-sha1":/^commit \w{40}$/m},a.languages.go=a.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),a.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete a.languages.go["class-name"],function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,a,i){if(n.language===r){var o=n.tokenStack=[];n.code=n.code.replace(a,(function(e){if("function"==typeof i&&!i(e))return e;for(var a,s=o.length;-1!==n.code.indexOf(a=t(r,s));)++s;return o[s]=e,a})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var a=0,i=Object.keys(n.tokenStack);!function o(s){for(var c=0;c<s.length&&!(a>=i.length);c++){var l=s[c];if("string"==typeof l||l.content&&"string"==typeof l.content){var u=i[a],d=n.tokenStack[u],p="string"==typeof l?l:l.content,f=t(r,u),m=p.indexOf(f);if(m>-1){++a;var h=p.substring(0,m),g=new e.Token(r,e.tokenize(d,n.grammar),"language-"+r,d),v=p.substring(m+f.length),y=[];h&&y.push.apply(y,o([h])),y.push(g),v&&y.push.apply(y,o([v])),"string"==typeof l?s.splice.apply(s,[c,1].concat(y)):l.content=y}}else l.content&&o(l.content)}return s}(n.tokens)}}}})}(a),function(e){e.languages.handlebars={comment:/\{\{![\s\S]*?\}\}/,delimiter:{pattern:/^\{\{\{?|\}\}\}?$/,alias:"punctuation"},string:/(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee][+-]?\d+)?/,boolean:/\b(?:false|true)\b/,block:{pattern:/^(\s*(?:~\s*)?)[#\/]\S+?(?=\s*(?:~\s*)?$|\s)/,lookbehind:!0,alias:"keyword"},brackets:{pattern:/\[[^\]]+\]/,inside:{punctuation:/\[|\]/,variable:/[\s\S]+/}},punctuation:/[!"#%&':()*+,.\/;<=>@\[\\\]^`{|}~]/,variable:/[^!"#%&'()*+,\/;<=>@\[\\\]^`{|}~\s]+/},e.hooks.add("before-tokenize",(function(t){e.languages["markup-templating"].buildPlaceholders(t,"handlebars",/\{\{\{[\s\S]+?\}\}\}|\{\{[\s\S]+?\}\}/g)})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"handlebars")})),e.languages.hbs=e.languages.handlebars}(a),a.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}},a.languages.webmanifest=a.languages.json,a.languages.less=a.languages.extend("css",{comment:[/\/\*[\s\S]*?\*\//,{pattern:/(^|[^\\])\/\/.*/,lookbehind:!0}],atrule:{pattern:/@[\w-](?:\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{punctuation:/[:()]/}},selector:{pattern:/(?:@\{[\w-]+\}|[^{};\s@])(?:@\{[\w-]+\}|\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};@\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{variable:/@+[\w-]+/}},property:/(?:@\{[\w-]+\}|[\w-])+(?:\+_?)?(?=\s*:)/,operator:/[+\-*\/]/}),a.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-].*?(?=[(;])/,lookbehind:!0,alias:"function"}}),a.languages.makefile={comment:{pattern:/(^|[^\\])#(?:\\(?:\r\n|[\s\S])|[^\\\r\n])*/,lookbehind:!0},string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"builtin-target":{pattern:/\.[A-Z][^:#=\s]+(?=\s*:(?!=))/,alias:"builtin"},target:{pattern:/^(?:[^:=\s]|[ \t]+(?![\s:]))+(?=\s*:(?!=))/m,alias:"symbol",inside:{variable:/\$+(?:(?!\$)[^(){}:#=\s]+|(?=[({]))/}},variable:/\$+(?:(?!\$)[^(){}:#=\s]+|\([@*%<^+?][DF]\)|(?=[({]))/,keyword:/-include\b|\b(?:define|else|endef|endif|export|ifn?def|ifn?eq|include|override|private|sinclude|undefine|unexport|vpath)\b/,function:{pattern:/(\()(?:abspath|addsuffix|and|basename|call|dir|error|eval|file|filter(?:-out)?|findstring|firstword|flavor|foreach|guile|if|info|join|lastword|load|notdir|or|origin|patsubst|realpath|shell|sort|strip|subst|suffix|value|warning|wildcard|word(?:list|s)?)(?=[ \t])/,lookbehind:!0},operator:/(?:::|[?:+!])?=|[|@]/,punctuation:/[:;(){}]/},a.languages.objectivec=a.languages.extend("c",{string:{pattern:/@?"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},keyword:/\b(?:asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|in|inline|int|long|register|return|self|short|signed|sizeof|static|struct|super|switch|typedef|typeof|union|unsigned|void|volatile|while)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/,operator:/-[->]?|\+\+?|!=?|<<?=?|>>?=?|==?|&&?|\|\|?|[~^%?*\/@]/}),delete a.languages.objectivec["class-name"],a.languages.objc=a.languages.objectivec,a.languages.ocaml={comment:{pattern:/\(\*[\s\S]*?\*\)/,greedy:!0},char:{pattern:/'(?:[^\\\r\n']|\\(?:.|[ox]?[0-9a-f]{1,3}))'/i,greedy:!0},string:[{pattern:/"(?:\\(?:[\s\S]|\r\n)|[^\\\r\n"])*"/,greedy:!0},{pattern:/\{([a-z_]*)\|[\s\S]*?\|\1\}/,greedy:!0}],number:[/\b(?:0b[01][01_]*|0o[0-7][0-7_]*)\b/i,/\b0x[a-f0-9][a-f0-9_]*(?:\.[a-f0-9_]*)?(?:p[+-]?\d[\d_]*)?(?!\w)/i,/\b\d[\d_]*(?:\.[\d_]*)?(?:e[+-]?\d[\d_]*)?(?!\w)/i],directive:{pattern:/\B#\w+/,alias:"property"},label:{pattern:/\B~\w+/,alias:"property"},"type-variable":{pattern:/\B'\w+/,alias:"function"},variant:{pattern:/`\w+/,alias:"symbol"},keyword:/\b(?:as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|match|method|module|mutable|new|nonrec|object|of|open|private|rec|sig|struct|then|to|try|type|val|value|virtual|when|where|while|with)\b/,boolean:/\b(?:false|true)\b/,"operator-like-punctuation":{pattern:/\[[<>|]|[>|]\]|\{<|>\}/,alias:"punctuation"},operator:/\.[.~]|:[=>]|[=<>@^|&+\-*\/$%!?~][!$%&*+\-.\/:<=>?@^|~]*|\b(?:and|asr|land|lor|lsl|lsr|lxor|mod|or)\b/,punctuation:/;;|::|[(){}\[\].,:;#]|\b_\b/},a.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},a.languages.python["string-interpolation"].inside.interpolation.inside.rest=a.languages.python,a.languages.py=a.languages.python,a.languages.reason=a.languages.extend("clike",{string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},"class-name":/\b[A-Z]\w*/,keyword:/\b(?:and|as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|method|module|mutable|new|nonrec|object|of|open|or|private|rec|sig|struct|switch|then|to|try|type|val|virtual|when|while|with)\b/,operator:/\.{3}|:[:=]|\|>|->|=(?:==?|>)?|<=?|>=?|[|^?'#!~`]|[+\-*\/]\.?|\b(?:asr|land|lor|lsl|lsr|lxor|mod)\b/}),a.languages.insertBefore("reason","class-name",{char:{pattern:/'(?:\\x[\da-f]{2}|\\o[0-3][0-7][0-7]|\\\d{3}|\\.|[^'\\\r\n])'/,greedy:!0},constructor:/\b[A-Z]\w*\b(?!\s*\.)/,label:{pattern:/\b[a-z]\w*(?=::)/,alias:"symbol"}}),delete a.languages.reason.function,function(e){e.languages.sass=e.languages.extend("css",{comment:{pattern:/^([ \t]*)\/[\/*].*(?:(?:\r?\n|\r)\1[ \t].+)*/m,lookbehind:!0,greedy:!0}}),e.languages.insertBefore("sass","atrule",{"atrule-line":{pattern:/^(?:[ \t]*)[@+=].+/m,greedy:!0,inside:{atrule:/(?:@[\w-]+|[+=])/}}}),delete e.languages.sass.atrule;var t=/\$[-\w]+|#\{\$[-\w]+\}/,n=[/[+*\/%]|[=!]=|<=?|>=?|\b(?:and|not|or)\b/,{pattern:/(\s)-(?=\s)/,lookbehind:!0}];e.languages.insertBefore("sass","property",{"variable-line":{pattern:/^[ \t]*\$.+/m,greedy:!0,inside:{punctuation:/:/,variable:t,operator:n}},"property-line":{pattern:/^[ \t]*(?:[^:\s]+ *:.*|:[^:\s].*)/m,greedy:!0,inside:{property:[/[^:\s]+(?=\s*:)/,{pattern:/(:)[^:\s]+/,lookbehind:!0}],punctuation:/:/,variable:t,operator:n,important:e.languages.sass.important}}}),delete e.languages.sass.property,delete e.languages.sass.important,e.languages.insertBefore("sass","punctuation",{selector:{pattern:/^([ \t]*)\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*(?:,(?:\r?\n|\r)\1[ \t]+\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*)*/m,lookbehind:!0,greedy:!0}})}(a),a.languages.scss=a.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-](?:\([^()]+\)|[^()\s]|\s+(?!\s))*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)?url(?=\()/i,selector:{pattern:/(?=\S)[^@;{}()]?(?:[^@;{}()\s]|\s+(?!\s)|#\{\$[-\w]+\})+(?=\s*\{(?:\}|\s|[^}][^:{}]*[:{][^}]))/,inside:{parent:{pattern:/&/,alias:"important"},placeholder:/%[-\w]+/,variable:/\$[-\w]+|#\{\$[-\w]+\}/}},property:{pattern:/(?:[-\w]|\$[-\w]|#\{\$[-\w]+\})+(?=\s*:)/,inside:{variable:/\$[-\w]+|#\{\$[-\w]+\}/}}}),a.languages.insertBefore("scss","atrule",{keyword:[/@(?:content|debug|each|else(?: if)?|extend|for|forward|function|if|import|include|mixin|return|use|warn|while)\b/i,{pattern:/( )(?:from|through)(?= )/,lookbehind:!0}]}),a.languages.insertBefore("scss","important",{variable:/\$[-\w]+|#\{\$[-\w]+\}/}),a.languages.insertBefore("scss","function",{"module-modifier":{pattern:/\b(?:as|hide|show|with)\b/i,alias:"keyword"},placeholder:{pattern:/%[-\w]+/,alias:"selector"},statement:{pattern:/\B!(?:default|optional)\b/i,alias:"keyword"},boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"},operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|not|or)(?=\s)/,lookbehind:!0}}),a.languages.scss.atrule.inside.rest=a.languages.scss,function(e){var t={pattern:/(\b\d+)(?:%|[a-z]+)/,lookbehind:!0},n={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0},r={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},url:{pattern:/\burl\((["']?).*?\1\)/i,greedy:!0},string:{pattern:/("|')(?:(?!\1)[^\\\r\n]|\\(?:\r\n|[\s\S]))*\1/,greedy:!0},interpolation:null,func:null,important:/\B!(?:important|optional)\b/i,keyword:{pattern:/(^|\s+)(?:(?:else|for|if|return|unless)(?=\s|$)|@[\w-]+)/,lookbehind:!0},hexcode:/#[\da-f]{3,6}/i,color:[/\b(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)\b/i,{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:t,number:n,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:t,boolean:/\b(?:false|true)\b/,operator:[/~|[+!\/%<>?=]=?|[-:]=|\*[*=]?|\.{2,3}|&&|\|\||\B-\B|\b(?:and|in|is(?: a| defined| not|nt)?|not|or)\b/],number:n,punctuation:/[{}()\[\];:,]/};r.interpolation={pattern:/\{[^\r\n}:]+\}/,alias:"variable",inside:{delimiter:{pattern:/^\{|\}$/,alias:"punctuation"},rest:r}},r.func={pattern:/[\w-]+\([^)]*\).*/,inside:{function:/^[^(]+/,rest:r}},e.languages.stylus={"atrule-declaration":{pattern:/(^[ \t]*)@.+/m,lookbehind:!0,inside:{atrule:/^@[\w-]+/,rest:r}},"variable-declaration":{pattern:/(^[ \t]*)[\w$-]+\s*.?=[ \t]*(?:\{[^{}]*\}|\S.*|$)/m,lookbehind:!0,inside:{variable:/^\S+/,rest:r}},statement:{pattern:/(^[ \t]*)(?:else|for|if|return|unless)[ \t].+/m,lookbehind:!0,inside:{keyword:/^\S+/,rest:r}},"property-declaration":{pattern:/((?:^|\{)([ \t]*))(?:[\w-]|\{[^}\r\n]+\})+(?:\s*:\s*|[ \t]+)(?!\s)[^{\r\n]*(?:;|[^{\r\n,]$(?!(?:\r?\n|\r)(?:\{|\2[ \t])))/m,lookbehind:!0,inside:{property:{pattern:/^[^\s:]+/,inside:{interpolation:r.interpolation}},rest:r}},selector:{pattern:/(^[ \t]*)(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)(?:(?:\r?\n|\r)(?:\1(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)))*(?:,$|\{|(?=(?:\r?\n|\r)(?:\{|\1[ \t])))/m,lookbehind:!0,inside:{interpolation:r.interpolation,comment:r.comment,punctuation:/[{},]/}},func:r.func,string:r.string,comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0,greedy:!0},interpolation:r.interpolation,punctuation:/[{}()\[\];:.]/}}(a),function(e){var t=e.util.clone(e.languages.typescript);e.languages.tsx=e.languages.extend("jsx",t),delete e.languages.tsx.parameter,delete e.languages.tsx["literal-property"];var n=e.languages.tsx.tag;n.pattern=RegExp(/(^|[^\w$]|(?=<\/))/.source+"(?:"+n.pattern.source+")",n.pattern.flags),n.lookbehind=!0}(a),a.languages.wasm={comment:[/\(;[\s\S]*?;\)/,{pattern:/;;.*/,greedy:!0}],string:{pattern:/"(?:\\[\s\S]|[^"\\])*"/,greedy:!0},keyword:[{pattern:/\b(?:align|offset)=/,inside:{operator:/=/}},{pattern:/\b(?:(?:f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|neg?|nearest|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|sqrt|store(?:8|16|32)?|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))?|memory\.(?:grow|size))\b/,inside:{punctuation:/\./}},/\b(?:anyfunc|block|br(?:_if|_table)?|call(?:_indirect)?|data|drop|elem|else|end|export|func|get_(?:global|local)|global|if|import|local|loop|memory|module|mut|nop|offset|param|result|return|select|set_(?:global|local)|start|table|tee_local|then|type|unreachable)\b/],variable:/\$[\w!#$%&'*+\-./:<=>?@\\^`|~]+/,number:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/,punctuation:/[()]/};const i=a},7346:()=>{Prism.languages["go-mod"]=Prism.languages["go-module"]={comment:{pattern:/\/\/.*/,greedy:!0},version:{pattern:/(^|[\s()[\],])v\d+\.\d+\.\d+(?:[+-][-+.\w]*)?(?![^\s()[\],])/,lookbehind:!0,alias:"number"},"go-version":{pattern:/((?:^|\s)go\s+)\d+(?:\.\d+){1,2}/,lookbehind:!0,alias:"number"},keyword:{pattern:/^([ \t]*)(?:exclude|go|module|replace|require|retract)\b/m,lookbehind:!0},operator:/=>/,punctuation:/[()[\],]/}},7345:()=>{!function(e){var t=/\b(?:bool|bytes|double|s?fixed(?:32|64)|float|[su]?int(?:32|64)|string)\b/;e.languages.protobuf=e.languages.extend("clike",{"class-name":[{pattern:/(\b(?:enum|extend|message|service)\s+)[A-Za-z_]\w*(?=\s*\{)/,lookbehind:!0},{pattern:/(\b(?:rpc\s+\w+|returns)\s*\(\s*(?:stream\s+)?)\.?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*(?=\s*\))/,lookbehind:!0}],keyword:/\b(?:enum|extend|extensions|import|message|oneof|option|optional|package|public|repeated|required|reserved|returns|rpc(?=\s+\w)|service|stream|syntax|to)\b(?!\s*=\s*\d)/,function:/\b[a-z_]\w*(?=\s*\()/i}),e.languages.insertBefore("protobuf","operator",{map:{pattern:/\bmap<\s*[\w.]+\s*,\s*[\w.]+\s*>(?=\s+[a-z_]\w*\s*[=;])/i,alias:"class-name",inside:{punctuation:/[<>.,]/,builtin:t}},builtin:t,"positional-class-name":{pattern:/(?:\b|\B\.)[a-z_]\w*(?:\.[a-z_]\w*)*(?=\s+[a-z_]\w*\s*[=;])/i,alias:"class-name",inside:{punctuation:/\./}},annotation:{pattern:/(\[\s*)[a-z_]\w*(?=\s*=)/i,lookbehind:!0}})}(Prism)},692:(e,t,n)=>{var r={"./prism-go-module":7346,"./prism-protobuf":7345};function a(e){var t=i(e);return n(t)}function i(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=i,e.exports=a,a.id=692},2703:(e,t,n)=>{"use strict";var r=n(414);function a(){}function i(){}i.resetWarningCache=a,e.exports=function(){function e(e,t,n,a,i,o){if(o!==r){var s=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw s.name="Invariant Violation",s}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:i,resetWarningCache:a};return n.PropTypes=n,n}},5697:(e,t,n)=>{e.exports=n(2703)()},414:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},4448:(e,t,n)=>{"use strict";var r=n(7294),a=n(7418),i=n(3840);function o(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}if(!r)throw Error(o(227));var s=new Set,c={};function l(e,t){u(e,t),u(e+"Capture",t)}function u(e,t){for(c[e]=t,e=0;e<t.length;e++)s.add(t[e])}var d=!("undefined"==typeof window||void 0===window.document||void 0===window.document.createElement),p=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,f=Object.prototype.hasOwnProperty,m={},h={};function g(e,t,n,r,a,i,o){this.acceptsBooleans=2===t||3===t||4===t,this.attributeName=r,this.attributeNamespace=a,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=o}var v={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach((function(e){v[e]=new g(e,0,!1,e,null,!1,!1)})),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach((function(e){var t=e[0];v[t]=new g(t,1,!1,e[1],null,!1,!1)})),["contentEditable","draggable","spellCheck","value"].forEach((function(e){v[e]=new g(e,2,!1,e.toLowerCase(),null,!1,!1)})),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach((function(e){v[e]=new g(e,2,!1,e,null,!1,!1)})),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach((function(e){v[e]=new g(e,3,!1,e.toLowerCase(),null,!1,!1)})),["checked","multiple","muted","selected"].forEach((function(e){v[e]=new g(e,3,!0,e,null,!1,!1)})),["capture","download"].forEach((function(e){v[e]=new g(e,4,!1,e,null,!1,!1)})),["cols","rows","size","span"].forEach((function(e){v[e]=new g(e,6,!1,e,null,!1,!1)})),["rowSpan","start"].forEach((function(e){v[e]=new g(e,5,!1,e.toLowerCase(),null,!1,!1)}));var y=/[\-:]([a-z])/g;function b(e){return e[1].toUpperCase()}function w(e,t,n,r){var a=v.hasOwnProperty(t)?v[t]:null;(null!==a?0===a.type:!r&&(2<t.length&&("o"===t[0]||"O"===t[0])&&("n"===t[1]||"N"===t[1])))||(function(e,t,n,r){if(null==t||function(e,t,n,r){if(null!==n&&0===n.type)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return!r&&(null!==n?!n.acceptsBooleans:"data-"!==(e=e.toLowerCase().slice(0,5))&&"aria-"!==e);default:return!1}}(e,t,n,r))return!0;if(r)return!1;if(null!==n)switch(n.type){case 3:return!t;case 4:return!1===t;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}(t,n,a,r)&&(n=null),r||null===a?function(e){return!!f.call(h,e)||!f.call(m,e)&&(p.test(e)?h[e]=!0:(m[e]=!0,!1))}(t)&&(null===n?e.removeAttribute(t):e.setAttribute(t,""+n)):a.mustUseProperty?e[a.propertyName]=null===n?3!==a.type&&"":n:(t=a.attributeName,r=a.attributeNamespace,null===n?e.removeAttribute(t):(n=3===(a=a.type)||4===a&&!0===n?"":""+n,r?e.setAttributeNS(r,t,n):e.setAttribute(t,n))))}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach((function(e){var t=e.replace(y,b);v[t]=new g(t,1,!1,e,null,!1,!1)})),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach((function(e){var t=e.replace(y,b);v[t]=new g(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)})),["xml:base","xml:lang","xml:space"].forEach((function(e){var t=e.replace(y,b);v[t]=new g(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)})),["tabIndex","crossOrigin"].forEach((function(e){v[e]=new g(e,1,!1,e.toLowerCase(),null,!1,!1)})),v.xlinkHref=new g("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach((function(e){v[e]=new g(e,1,!1,e.toLowerCase(),null,!0,!0)}));var _=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,S=60103,k=60106,E=60107,x=60108,C=60114,T=60109,L=60110,A=60112,N=60113,O=60120,P=60115,I=60116,R=60121,M=60128,D=60129,F=60130,B=60131;if("function"==typeof Symbol&&Symbol.for){var j=Symbol.for;S=j("react.element"),k=j("react.portal"),E=j("react.fragment"),x=j("react.strict_mode"),C=j("react.profiler"),T=j("react.provider"),L=j("react.context"),A=j("react.forward_ref"),N=j("react.suspense"),O=j("react.suspense_list"),P=j("react.memo"),I=j("react.lazy"),R=j("react.block"),j("react.scope"),M=j("react.opaque.id"),D=j("react.debug_trace_mode"),F=j("react.offscreen"),B=j("react.legacy_hidden")}var $,z="function"==typeof Symbol&&Symbol.iterator;function U(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=z&&e[z]||e["@@iterator"])?e:null}function q(e){if(void 0===$)try{throw Error()}catch(n){var t=n.stack.trim().match(/\n( *(at )?)/);$=t&&t[1]||""}return"\n"+$+e}var Z=!1;function H(e,t){if(!e||Z)return"";Z=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(t)if(t=function(){throw Error()},Object.defineProperty(t.prototype,"props",{set:function(){throw Error()}}),"object"==typeof Reflect&&Reflect.construct){try{Reflect.construct(t,[])}catch(c){var r=c}Reflect.construct(e,[],t)}else{try{t.call()}catch(c){r=c}e.call(t.prototype)}else{try{throw Error()}catch(c){r=c}e()}}catch(c){if(c&&r&&"string"==typeof c.stack){for(var a=c.stack.split("\n"),i=r.stack.split("\n"),o=a.length-1,s=i.length-1;1<=o&&0<=s&&a[o]!==i[s];)s--;for(;1<=o&&0<=s;o--,s--)if(a[o]!==i[s]){if(1!==o||1!==s)do{if(o--,0>--s||a[o]!==i[s])return"\n"+a[o].replace(" at new "," at ")}while(1<=o&&0<=s);break}}}finally{Z=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?q(e):""}function V(e){switch(e.tag){case 5:return q(e.type);case 16:return q("Lazy");case 13:return q("Suspense");case 19:return q("SuspenseList");case 0:case 2:case 15:return e=H(e.type,!1);case 11:return e=H(e.type.render,!1);case 22:return e=H(e.type._render,!1);case 1:return e=H(e.type,!0);default:return""}}function W(e){if(null==e)return null;if("function"==typeof e)return e.displayName||e.name||null;if("string"==typeof e)return e;switch(e){case E:return"Fragment";case k:return"Portal";case C:return"Profiler";case x:return"StrictMode";case N:return"Suspense";case O:return"SuspenseList"}if("object"==typeof e)switch(e.$$typeof){case L:return(e.displayName||"Context")+".Consumer";case T:return(e._context.displayName||"Context")+".Provider";case A:var t=e.render;return t=t.displayName||t.name||"",e.displayName||(""!==t?"ForwardRef("+t+")":"ForwardRef");case P:return W(e.type);case R:return W(e._render);case I:t=e._payload,e=e._init;try{return W(e(t))}catch(n){}}return null}function G(e){switch(typeof e){case"boolean":case"number":case"object":case"string":case"undefined":return e;default:return""}}function Y(e){var t=e.type;return(e=e.nodeName)&&"input"===e.toLowerCase()&&("checkbox"===t||"radio"===t)}function K(e){e._valueTracker||(e._valueTracker=function(e){var t=Y(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&void 0!==n&&"function"==typeof n.get&&"function"==typeof n.set){var a=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return a.call(this)},set:function(e){r=""+e,i.call(this,e)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(e){r=""+e},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}(e))}function X(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=Y(e)?e.checked?"true":"false":e.value),(e=r)!==n&&(t.setValue(e),!0)}function Q(e){if(void 0===(e=e||("undefined"!=typeof document?document:void 0)))return null;try{return e.activeElement||e.body}catch(t){return e.body}}function J(e,t){var n=t.checked;return a({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:null!=n?n:e._wrapperState.initialChecked})}function ee(e,t){var n=null==t.defaultValue?"":t.defaultValue,r=null!=t.checked?t.checked:t.defaultChecked;n=G(null!=t.value?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:"checkbox"===t.type||"radio"===t.type?null!=t.checked:null!=t.value}}function te(e,t){null!=(t=t.checked)&&w(e,"checked",t,!1)}function ne(e,t){te(e,t);var n=G(t.value),r=t.type;if(null!=n)"number"===r?(0===n&&""===e.value||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if("submit"===r||"reset"===r)return void e.removeAttribute("value");t.hasOwnProperty("value")?ae(e,t.type,n):t.hasOwnProperty("defaultValue")&&ae(e,t.type,G(t.defaultValue)),null==t.checked&&null!=t.defaultChecked&&(e.defaultChecked=!!t.defaultChecked)}function re(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!("submit"!==r&&"reset"!==r||void 0!==t.value&&null!==t.value))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}""!==(n=e.name)&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,""!==n&&(e.name=n)}function ae(e,t,n){"number"===t&&Q(e.ownerDocument)===e||(null==n?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}function ie(e,t){return e=a({children:void 0},t),(t=function(e){var t="";return r.Children.forEach(e,(function(e){null!=e&&(t+=e)})),t}(t.children))&&(e.children=t),e}function oe(e,t,n,r){if(e=e.options,t){t={};for(var a=0;a<n.length;a++)t["$"+n[a]]=!0;for(n=0;n<e.length;n++)a=t.hasOwnProperty("$"+e[n].value),e[n].selected!==a&&(e[n].selected=a),a&&r&&(e[n].defaultSelected=!0)}else{for(n=""+G(n),t=null,a=0;a<e.length;a++){if(e[a].value===n)return e[a].selected=!0,void(r&&(e[a].defaultSelected=!0));null!==t||e[a].disabled||(t=e[a])}null!==t&&(t.selected=!0)}}function se(e,t){if(null!=t.dangerouslySetInnerHTML)throw Error(o(91));return a({},t,{value:void 0,defaultValue:void 0,children:""+e._wrapperState.initialValue})}function ce(e,t){var n=t.value;if(null==n){if(n=t.children,t=t.defaultValue,null!=n){if(null!=t)throw Error(o(92));if(Array.isArray(n)){if(!(1>=n.length))throw Error(o(93));n=n[0]}t=n}null==t&&(t=""),n=t}e._wrapperState={initialValue:G(n)}}function le(e,t){var n=G(t.value),r=G(t.defaultValue);null!=n&&((n=""+n)!==e.value&&(e.value=n),null==t.defaultValue&&e.defaultValue!==n&&(e.defaultValue=n)),null!=r&&(e.defaultValue=""+r)}function ue(e){var t=e.textContent;t===e._wrapperState.initialValue&&""!==t&&null!==t&&(e.value=t)}var de={html:"http://www.w3.org/1999/xhtml",mathml:"http://www.w3.org/1998/Math/MathML",svg:"http://www.w3.org/2000/svg"};function pe(e){switch(e){case"svg":return"http://www.w3.org/2000/svg";case"math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function fe(e,t){return null==e||"http://www.w3.org/1999/xhtml"===e?pe(t):"http://www.w3.org/2000/svg"===e&&"foreignObject"===t?"http://www.w3.org/1999/xhtml":e}var me,he,ge=(he=function(e,t){if(e.namespaceURI!==de.svg||"innerHTML"in e)e.innerHTML=t;else{for((me=me||document.createElement("div")).innerHTML="<svg>"+t.valueOf().toString()+"</svg>",t=me.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}},"undefined"!=typeof MSApp&&MSApp.execUnsafeLocalFunction?function(e,t,n,r){MSApp.execUnsafeLocalFunction((function(){return he(e,t)}))}:he);function ve(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&3===n.nodeType)return void(n.nodeValue=t)}e.textContent=t}var ye={animationIterationCount:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},be=["Webkit","ms","Moz","O"];function we(e,t,n){return null==t||"boolean"==typeof t||""===t?"":n||"number"!=typeof t||0===t||ye.hasOwnProperty(e)&&ye[e]?(""+t).trim():t+"px"}function _e(e,t){for(var n in e=e.style,t)if(t.hasOwnProperty(n)){var r=0===n.indexOf("--"),a=we(n,t[n],r);"float"===n&&(n="cssFloat"),r?e.setProperty(n,a):e[n]=a}}Object.keys(ye).forEach((function(e){be.forEach((function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),ye[t]=ye[e]}))}));var Se=a({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function ke(e,t){if(t){if(Se[e]&&(null!=t.children||null!=t.dangerouslySetInnerHTML))throw Error(o(137,e));if(null!=t.dangerouslySetInnerHTML){if(null!=t.children)throw Error(o(60));if("object"!=typeof t.dangerouslySetInnerHTML||!("__html"in t.dangerouslySetInnerHTML))throw Error(o(61))}if(null!=t.style&&"object"!=typeof t.style)throw Error(o(62))}}function Ee(e,t){if(-1===e.indexOf("-"))return"string"==typeof t.is;switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}function xe(e){return(e=e.target||e.srcElement||window).correspondingUseElement&&(e=e.correspondingUseElement),3===e.nodeType?e.parentNode:e}var Ce=null,Te=null,Le=null;function Ae(e){if(e=na(e)){if("function"!=typeof Ce)throw Error(o(280));var t=e.stateNode;t&&(t=aa(t),Ce(e.stateNode,e.type,t))}}function Ne(e){Te?Le?Le.push(e):Le=[e]:Te=e}function Oe(){if(Te){var e=Te,t=Le;if(Le=Te=null,Ae(e),t)for(e=0;e<t.length;e++)Ae(t[e])}}function Pe(e,t){return e(t)}function Ie(e,t,n,r,a){return e(t,n,r,a)}function Re(){}var Me=Pe,De=!1,Fe=!1;function Be(){null===Te&&null===Le||(Re(),Oe())}function je(e,t){var n=e.stateNode;if(null===n)return null;var r=aa(n);if(null===r)return null;n=r[t];e:switch(t){case"onClick":case"onClickCapture":case"onDoubleClick":case"onDoubleClickCapture":case"onMouseDown":case"onMouseDownCapture":case"onMouseMove":case"onMouseMoveCapture":case"onMouseUp":case"onMouseUpCapture":case"onMouseEnter":(r=!r.disabled)||(r=!("button"===(e=e.type)||"input"===e||"select"===e||"textarea"===e)),e=!r;break e;default:e=!1}if(e)return null;if(n&&"function"!=typeof n)throw Error(o(231,t,typeof n));return n}var $e=!1;if(d)try{var ze={};Object.defineProperty(ze,"passive",{get:function(){$e=!0}}),window.addEventListener("test",ze,ze),window.removeEventListener("test",ze,ze)}catch(he){$e=!1}function Ue(e,t,n,r,a,i,o,s,c){var l=Array.prototype.slice.call(arguments,3);try{t.apply(n,l)}catch(u){this.onError(u)}}var qe=!1,Ze=null,He=!1,Ve=null,We={onError:function(e){qe=!0,Ze=e}};function Ge(e,t,n,r,a,i,o,s,c){qe=!1,Ze=null,Ue.apply(We,arguments)}function Ye(e){var t=e,n=e;if(e.alternate)for(;t.return;)t=t.return;else{e=t;do{0!=(1026&(t=e).flags)&&(n=t.return),e=t.return}while(e)}return 3===t.tag?n:null}function Ke(e){if(13===e.tag){var t=e.memoizedState;if(null===t&&(null!==(e=e.alternate)&&(t=e.memoizedState)),null!==t)return t.dehydrated}return null}function Xe(e){if(Ye(e)!==e)throw Error(o(188))}function Qe(e){if(e=function(e){var t=e.alternate;if(!t){if(null===(t=Ye(e)))throw Error(o(188));return t!==e?null:e}for(var n=e,r=t;;){var a=n.return;if(null===a)break;var i=a.alternate;if(null===i){if(null!==(r=a.return)){n=r;continue}break}if(a.child===i.child){for(i=a.child;i;){if(i===n)return Xe(a),e;if(i===r)return Xe(a),t;i=i.sibling}throw Error(o(188))}if(n.return!==r.return)n=a,r=i;else{for(var s=!1,c=a.child;c;){if(c===n){s=!0,n=a,r=i;break}if(c===r){s=!0,r=a,n=i;break}c=c.sibling}if(!s){for(c=i.child;c;){if(c===n){s=!0,n=i,r=a;break}if(c===r){s=!0,r=i,n=a;break}c=c.sibling}if(!s)throw Error(o(189))}}if(n.alternate!==r)throw Error(o(190))}if(3!==n.tag)throw Error(o(188));return n.stateNode.current===n?e:t}(e),!e)return null;for(var t=e;;){if(5===t.tag||6===t.tag)return t;if(t.child)t.child.return=t,t=t.child;else{if(t===e)break;for(;!t.sibling;){if(!t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}}return null}function Je(e,t){for(var n=e.alternate;null!==t;){if(t===e||t===n)return!0;t=t.return}return!1}var et,tt,nt,rt,at=!1,it=[],ot=null,st=null,ct=null,lt=new Map,ut=new Map,dt=[],pt="mousedown mouseup touchcancel touchend touchstart auxclick dblclick pointercancel pointerdown pointerup dragend dragstart drop compositionend compositionstart keydown keypress keyup input textInput copy cut paste click change contextmenu reset submit".split(" ");function ft(e,t,n,r,a){return{blockedOn:e,domEventName:t,eventSystemFlags:16|n,nativeEvent:a,targetContainers:[r]}}function mt(e,t){switch(e){case"focusin":case"focusout":ot=null;break;case"dragenter":case"dragleave":st=null;break;case"mouseover":case"mouseout":ct=null;break;case"pointerover":case"pointerout":lt.delete(t.pointerId);break;case"gotpointercapture":case"lostpointercapture":ut.delete(t.pointerId)}}function ht(e,t,n,r,a,i){return null===e||e.nativeEvent!==i?(e=ft(t,n,r,a,i),null!==t&&(null!==(t=na(t))&&tt(t)),e):(e.eventSystemFlags|=r,t=e.targetContainers,null!==a&&-1===t.indexOf(a)&&t.push(a),e)}function gt(e){var t=ta(e.target);if(null!==t){var n=Ye(t);if(null!==n)if(13===(t=n.tag)){if(null!==(t=Ke(n)))return e.blockedOn=t,void rt(e.lanePriority,(function(){i.unstable_runWithPriority(e.priority,(function(){nt(n)}))}))}else if(3===t&&n.stateNode.hydrate)return void(e.blockedOn=3===n.tag?n.stateNode.containerInfo:null)}e.blockedOn=null}function vt(e){if(null!==e.blockedOn)return!1;for(var t=e.targetContainers;0<t.length;){var n=Qt(e.domEventName,e.eventSystemFlags,t[0],e.nativeEvent);if(null!==n)return null!==(t=na(n))&&tt(t),e.blockedOn=n,!1;t.shift()}return!0}function yt(e,t,n){vt(e)&&n.delete(t)}function bt(){for(at=!1;0<it.length;){var e=it[0];if(null!==e.blockedOn){null!==(e=na(e.blockedOn))&&et(e);break}for(var t=e.targetContainers;0<t.length;){var n=Qt(e.domEventName,e.eventSystemFlags,t[0],e.nativeEvent);if(null!==n){e.blockedOn=n;break}t.shift()}null===e.blockedOn&&it.shift()}null!==ot&&vt(ot)&&(ot=null),null!==st&&vt(st)&&(st=null),null!==ct&&vt(ct)&&(ct=null),lt.forEach(yt),ut.forEach(yt)}function wt(e,t){e.blockedOn===t&&(e.blockedOn=null,at||(at=!0,i.unstable_scheduleCallback(i.unstable_NormalPriority,bt)))}function _t(e){function t(t){return wt(t,e)}if(0<it.length){wt(it[0],e);for(var n=1;n<it.length;n++){var r=it[n];r.blockedOn===e&&(r.blockedOn=null)}}for(null!==ot&&wt(ot,e),null!==st&&wt(st,e),null!==ct&&wt(ct,e),lt.forEach(t),ut.forEach(t),n=0;n<dt.length;n++)(r=dt[n]).blockedOn===e&&(r.blockedOn=null);for(;0<dt.length&&null===(n=dt[0]).blockedOn;)gt(n),null===n.blockedOn&&dt.shift()}function St(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit"+e]="webkit"+t,n["Moz"+e]="moz"+t,n}var kt={animationend:St("Animation","AnimationEnd"),animationiteration:St("Animation","AnimationIteration"),animationstart:St("Animation","AnimationStart"),transitionend:St("Transition","TransitionEnd")},Et={},xt={};function Ct(e){if(Et[e])return Et[e];if(!kt[e])return e;var t,n=kt[e];for(t in n)if(n.hasOwnProperty(t)&&t in xt)return Et[e]=n[t];return e}d&&(xt=document.createElement("div").style,"AnimationEvent"in window||(delete kt.animationend.animation,delete kt.animationiteration.animation,delete kt.animationstart.animation),"TransitionEvent"in window||delete kt.transitionend.transition);var Tt=Ct("animationend"),Lt=Ct("animationiteration"),At=Ct("animationstart"),Nt=Ct("transitionend"),Ot=new Map,Pt=new Map,It=["abort","abort",Tt,"animationEnd",Lt,"animationIteration",At,"animationStart","canplay","canPlay","canplaythrough","canPlayThrough","durationchange","durationChange","emptied","emptied","encrypted","encrypted","ended","ended","error","error","gotpointercapture","gotPointerCapture","load","load","loadeddata","loadedData","loadedmetadata","loadedMetadata","loadstart","loadStart","lostpointercapture","lostPointerCapture","playing","playing","progress","progress","seeking","seeking","stalled","stalled","suspend","suspend","timeupdate","timeUpdate",Nt,"transitionEnd","waiting","waiting"];function Rt(e,t){for(var n=0;n<e.length;n+=2){var r=e[n],a=e[n+1];a="on"+(a[0].toUpperCase()+a.slice(1)),Pt.set(r,t),Ot.set(r,a),l(a,[r])}}(0,i.unstable_now)();var Mt=8;function Dt(e){if(0!=(1&e))return Mt=15,1;if(0!=(2&e))return Mt=14,2;if(0!=(4&e))return Mt=13,4;var t=24&e;return 0!==t?(Mt=12,t):0!=(32&e)?(Mt=11,32):0!==(t=192&e)?(Mt=10,t):0!=(256&e)?(Mt=9,256):0!==(t=3584&e)?(Mt=8,t):0!=(4096&e)?(Mt=7,4096):0!==(t=4186112&e)?(Mt=6,t):0!==(t=62914560&e)?(Mt=5,t):67108864&e?(Mt=4,67108864):0!=(134217728&e)?(Mt=3,134217728):0!==(t=805306368&e)?(Mt=2,t):0!=(1073741824&e)?(Mt=1,1073741824):(Mt=8,e)}function Ft(e,t){var n=e.pendingLanes;if(0===n)return Mt=0;var r=0,a=0,i=e.expiredLanes,o=e.suspendedLanes,s=e.pingedLanes;if(0!==i)r=i,a=Mt=15;else if(0!==(i=134217727&n)){var c=i&~o;0!==c?(r=Dt(c),a=Mt):0!==(s&=i)&&(r=Dt(s),a=Mt)}else 0!==(i=n&~o)?(r=Dt(i),a=Mt):0!==s&&(r=Dt(s),a=Mt);if(0===r)return 0;if(r=n&((0>(r=31-qt(r))?0:1<<r)<<1)-1,0!==t&&t!==r&&0==(t&o)){if(Dt(t),a<=Mt)return t;Mt=a}if(0!==(t=e.entangledLanes))for(e=e.entanglements,t&=r;0<t;)a=1<<(n=31-qt(t)),r|=e[n],t&=~a;return r}function Bt(e){return 0!==(e=-1073741825&e.pendingLanes)?e:1073741824&e?1073741824:0}function jt(e,t){switch(e){case 15:return 1;case 14:return 2;case 12:return 0===(e=$t(24&~t))?jt(10,t):e;case 10:return 0===(e=$t(192&~t))?jt(8,t):e;case 8:return 0===(e=$t(3584&~t))&&(0===(e=$t(4186112&~t))&&(e=512)),e;case 2:return 0===(t=$t(805306368&~t))&&(t=268435456),t}throw Error(o(358,e))}function $t(e){return e&-e}function zt(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function Ut(e,t,n){e.pendingLanes|=t;var r=t-1;e.suspendedLanes&=r,e.pingedLanes&=r,(e=e.eventTimes)[t=31-qt(t)]=n}var qt=Math.clz32?Math.clz32:function(e){return 0===e?32:31-(Zt(e)/Ht|0)|0},Zt=Math.log,Ht=Math.LN2;var Vt=i.unstable_UserBlockingPriority,Wt=i.unstable_runWithPriority,Gt=!0;function Yt(e,t,n,r){De||Re();var a=Xt,i=De;De=!0;try{Ie(a,e,t,n,r)}finally{(De=i)||Be()}}function Kt(e,t,n,r){Wt(Vt,Xt.bind(null,e,t,n,r))}function Xt(e,t,n,r){var a;if(Gt)if((a=0==(4&t))&&0<it.length&&-1<pt.indexOf(e))e=ft(null,e,t,n,r),it.push(e);else{var i=Qt(e,t,n,r);if(null===i)a&&mt(e,r);else{if(a){if(-1<pt.indexOf(e))return e=ft(i,e,t,n,r),void it.push(e);if(function(e,t,n,r,a){switch(t){case"focusin":return ot=ht(ot,e,t,n,r,a),!0;case"dragenter":return st=ht(st,e,t,n,r,a),!0;case"mouseover":return ct=ht(ct,e,t,n,r,a),!0;case"pointerover":var i=a.pointerId;return lt.set(i,ht(lt.get(i)||null,e,t,n,r,a)),!0;case"gotpointercapture":return i=a.pointerId,ut.set(i,ht(ut.get(i)||null,e,t,n,r,a)),!0}return!1}(i,e,t,n,r))return;mt(e,r)}Rr(e,t,r,null,n)}}}function Qt(e,t,n,r){var a=xe(r);if(null!==(a=ta(a))){var i=Ye(a);if(null===i)a=null;else{var o=i.tag;if(13===o){if(null!==(a=Ke(i)))return a;a=null}else if(3===o){if(i.stateNode.hydrate)return 3===i.tag?i.stateNode.containerInfo:null;a=null}else i!==a&&(a=null)}}return Rr(e,t,r,a,n),null}var Jt=null,en=null,tn=null;function nn(){if(tn)return tn;var e,t,n=en,r=n.length,a="value"in Jt?Jt.value:Jt.textContent,i=a.length;for(e=0;e<r&&n[e]===a[e];e++);var o=r-e;for(t=1;t<=o&&n[r-t]===a[i-t];t++);return tn=a.slice(e,1<t?1-t:void 0)}function rn(e){var t=e.keyCode;return"charCode"in e?0===(e=e.charCode)&&13===t&&(e=13):e=t,10===e&&(e=13),32<=e||13===e?e:0}function an(){return!0}function on(){return!1}function sn(e){function t(t,n,r,a,i){for(var o in this._reactName=t,this._targetInst=r,this.type=n,this.nativeEvent=a,this.target=i,this.currentTarget=null,e)e.hasOwnProperty(o)&&(t=e[o],this[o]=t?t(a):a[o]);return this.isDefaultPrevented=(null!=a.defaultPrevented?a.defaultPrevented:!1===a.returnValue)?an:on,this.isPropagationStopped=on,this}return a(t.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=an)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=an)},persist:function(){},isPersistent:an}),t}var cn,ln,un,dn={eventPhase:0,bubbles:0,cancelable:0,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:0,isTrusted:0},pn=sn(dn),fn=a({},dn,{view:0,detail:0}),mn=sn(fn),hn=a({},fn,{screenX:0,screenY:0,clientX:0,clientY:0,pageX:0,pageY:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,getModifierState:Tn,button:0,buttons:0,relatedTarget:function(e){return void 0===e.relatedTarget?e.fromElement===e.srcElement?e.toElement:e.fromElement:e.relatedTarget},movementX:function(e){return"movementX"in e?e.movementX:(e!==un&&(un&&"mousemove"===e.type?(cn=e.screenX-un.screenX,ln=e.screenY-un.screenY):ln=cn=0,un=e),cn)},movementY:function(e){return"movementY"in e?e.movementY:ln}}),gn=sn(hn),vn=sn(a({},hn,{dataTransfer:0})),yn=sn(a({},fn,{relatedTarget:0})),bn=sn(a({},dn,{animationName:0,elapsedTime:0,pseudoElement:0})),wn=a({},dn,{clipboardData:function(e){return"clipboardData"in e?e.clipboardData:window.clipboardData}}),_n=sn(wn),Sn=sn(a({},dn,{data:0})),kn={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},En={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"},xn={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"};function Cn(e){var t=this.nativeEvent;return t.getModifierState?t.getModifierState(e):!!(e=xn[e])&&!!t[e]}function Tn(){return Cn}var Ln=a({},fn,{key:function(e){if(e.key){var t=kn[e.key]||e.key;if("Unidentified"!==t)return t}return"keypress"===e.type?13===(e=rn(e))?"Enter":String.fromCharCode(e):"keydown"===e.type||"keyup"===e.type?En[e.keyCode]||"Unidentified":""},code:0,location:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,repeat:0,locale:0,getModifierState:Tn,charCode:function(e){return"keypress"===e.type?rn(e):0},keyCode:function(e){return"keydown"===e.type||"keyup"===e.type?e.keyCode:0},which:function(e){return"keypress"===e.type?rn(e):"keydown"===e.type||"keyup"===e.type?e.keyCode:0}}),An=sn(Ln),Nn=sn(a({},hn,{pointerId:0,width:0,height:0,pressure:0,tangentialPressure:0,tiltX:0,tiltY:0,twist:0,pointerType:0,isPrimary:0})),On=sn(a({},fn,{touches:0,targetTouches:0,changedTouches:0,altKey:0,metaKey:0,ctrlKey:0,shiftKey:0,getModifierState:Tn})),Pn=sn(a({},dn,{propertyName:0,elapsedTime:0,pseudoElement:0})),In=a({},hn,{deltaX:function(e){return"deltaX"in e?e.deltaX:"wheelDeltaX"in e?-e.wheelDeltaX:0},deltaY:function(e){return"deltaY"in e?e.deltaY:"wheelDeltaY"in e?-e.wheelDeltaY:"wheelDelta"in e?-e.wheelDelta:0},deltaZ:0,deltaMode:0}),Rn=sn(In),Mn=[9,13,27,32],Dn=d&&"CompositionEvent"in window,Fn=null;d&&"documentMode"in document&&(Fn=document.documentMode);var Bn=d&&"TextEvent"in window&&!Fn,jn=d&&(!Dn||Fn&&8<Fn&&11>=Fn),$n=String.fromCharCode(32),zn=!1;function Un(e,t){switch(e){case"keyup":return-1!==Mn.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function qn(e){return"object"==typeof(e=e.detail)&&"data"in e?e.data:null}var Zn=!1;var Hn={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};function Vn(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return"input"===t?!!Hn[e.type]:"textarea"===t}function Wn(e,t,n,r){Ne(r),0<(t=Dr(t,"onChange")).length&&(n=new pn("onChange","change",null,n,r),e.push({event:n,listeners:t}))}var Gn=null,Yn=null;function Kn(e){Lr(e,0)}function Xn(e){if(X(ra(e)))return e}function Qn(e,t){if("change"===e)return t}var Jn=!1;if(d){var er;if(d){var tr="oninput"in document;if(!tr){var nr=document.createElement("div");nr.setAttribute("oninput","return;"),tr="function"==typeof nr.oninput}er=tr}else er=!1;Jn=er&&(!document.documentMode||9<document.documentMode)}function rr(){Gn&&(Gn.detachEvent("onpropertychange",ar),Yn=Gn=null)}function ar(e){if("value"===e.propertyName&&Xn(Yn)){var t=[];if(Wn(t,Yn,e,xe(e)),e=Kn,De)e(t);else{De=!0;try{Pe(e,t)}finally{De=!1,Be()}}}}function ir(e,t,n){"focusin"===e?(rr(),Yn=n,(Gn=t).attachEvent("onpropertychange",ar)):"focusout"===e&&rr()}function or(e){if("selectionchange"===e||"keyup"===e||"keydown"===e)return Xn(Yn)}function sr(e,t){if("click"===e)return Xn(t)}function cr(e,t){if("input"===e||"change"===e)return Xn(t)}var lr="function"==typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t},ur=Object.prototype.hasOwnProperty;function dr(e,t){if(lr(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(r=0;r<n.length;r++)if(!ur.call(t,n[r])||!lr(e[n[r]],t[n[r]]))return!1;return!0}function pr(e){for(;e&&e.firstChild;)e=e.firstChild;return e}function fr(e,t){var n,r=pr(e);for(e=0;r;){if(3===r.nodeType){if(n=e+r.textContent.length,e<=t&&n>=t)return{node:r,offset:t-e};e=n}e:{for(;r;){if(r.nextSibling){r=r.nextSibling;break e}r=r.parentNode}r=void 0}r=pr(r)}}function mr(e,t){return!(!e||!t)&&(e===t||(!e||3!==e.nodeType)&&(t&&3===t.nodeType?mr(e,t.parentNode):"contains"in e?e.contains(t):!!e.compareDocumentPosition&&!!(16&e.compareDocumentPosition(t))))}function hr(){for(var e=window,t=Q();t instanceof e.HTMLIFrameElement;){try{var n="string"==typeof t.contentWindow.location.href}catch(r){n=!1}if(!n)break;t=Q((e=t.contentWindow).document)}return t}function gr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&("text"===e.type||"search"===e.type||"tel"===e.type||"url"===e.type||"password"===e.type)||"textarea"===t||"true"===e.contentEditable)}var vr=d&&"documentMode"in document&&11>=document.documentMode,yr=null,br=null,wr=null,_r=!1;function Sr(e,t,n){var r=n.window===n?n.document:9===n.nodeType?n:n.ownerDocument;_r||null==yr||yr!==Q(r)||("selectionStart"in(r=yr)&&gr(r)?r={start:r.selectionStart,end:r.selectionEnd}:r={anchorNode:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection()).anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset},wr&&dr(wr,r)||(wr=r,0<(r=Dr(br,"onSelect")).length&&(t=new pn("onSelect","select",null,t,n),e.push({event:t,listeners:r}),t.target=yr)))}Rt("cancel cancel click click close close contextmenu contextMenu copy copy cut cut auxclick auxClick dblclick doubleClick dragend dragEnd dragstart dragStart drop drop focusin focus focusout blur input input invalid invalid keydown keyDown keypress keyPress keyup keyUp mousedown mouseDown mouseup mouseUp paste paste pause pause play play pointercancel pointerCancel pointerdown pointerDown pointerup pointerUp ratechange rateChange reset reset seeked seeked submit submit touchcancel touchCancel touchend touchEnd touchstart touchStart volumechange volumeChange".split(" "),0),Rt("drag drag dragenter dragEnter dragexit dragExit dragleave dragLeave dragover dragOver mousemove mouseMove mouseout mouseOut mouseover mouseOver pointermove pointerMove pointerout pointerOut pointerover pointerOver scroll scroll toggle toggle touchmove touchMove wheel wheel".split(" "),1),Rt(It,2);for(var kr="change selectionchange textInput compositionstart compositionend compositionupdate".split(" "),Er=0;Er<kr.length;Er++)Pt.set(kr[Er],0);u("onMouseEnter",["mouseout","mouseover"]),u("onMouseLeave",["mouseout","mouseover"]),u("onPointerEnter",["pointerout","pointerover"]),u("onPointerLeave",["pointerout","pointerover"]),l("onChange","change click focusin focusout input keydown keyup selectionchange".split(" ")),l("onSelect","focusout contextmenu dragend focusin keydown keyup mousedown mouseup selectionchange".split(" ")),l("onBeforeInput",["compositionend","keypress","textInput","paste"]),l("onCompositionEnd","compositionend focusout keydown keypress keyup mousedown".split(" ")),l("onCompositionStart","compositionstart focusout keydown keypress keyup mousedown".split(" ")),l("onCompositionUpdate","compositionupdate focusout keydown keypress keyup mousedown".split(" "));var xr="abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange seeked seeking stalled suspend timeupdate volumechange waiting".split(" "),Cr=new Set("cancel close invalid load scroll toggle".split(" ").concat(xr));function Tr(e,t,n){var r=e.type||"unknown-event";e.currentTarget=n,function(e,t,n,r,a,i,s,c,l){if(Ge.apply(this,arguments),qe){if(!qe)throw Error(o(198));var u=Ze;qe=!1,Ze=null,He||(He=!0,Ve=u)}}(r,t,void 0,e),e.currentTarget=null}function Lr(e,t){t=0!=(4&t);for(var n=0;n<e.length;n++){var r=e[n],a=r.event;r=r.listeners;e:{var i=void 0;if(t)for(var o=r.length-1;0<=o;o--){var s=r[o],c=s.instance,l=s.currentTarget;if(s=s.listener,c!==i&&a.isPropagationStopped())break e;Tr(a,s,l),i=c}else for(o=0;o<r.length;o++){if(c=(s=r[o]).instance,l=s.currentTarget,s=s.listener,c!==i&&a.isPropagationStopped())break e;Tr(a,s,l),i=c}}}if(He)throw e=Ve,He=!1,Ve=null,e}function Ar(e,t){var n=ia(t),r=e+"__bubble";n.has(r)||(Ir(t,e,2,!1),n.add(r))}var Nr="_reactListening"+Math.random().toString(36).slice(2);function Or(e){e[Nr]||(e[Nr]=!0,s.forEach((function(t){Cr.has(t)||Pr(t,!1,e,null),Pr(t,!0,e,null)})))}function Pr(e,t,n,r){var a=4<arguments.length&&void 0!==arguments[4]?arguments[4]:0,i=n;if("selectionchange"===e&&9!==n.nodeType&&(i=n.ownerDocument),null!==r&&!t&&Cr.has(e)){if("scroll"!==e)return;a|=2,i=r}var o=ia(i),s=e+"__"+(t?"capture":"bubble");o.has(s)||(t&&(a|=4),Ir(i,e,a,t),o.add(s))}function Ir(e,t,n,r){var a=Pt.get(t);switch(void 0===a?2:a){case 0:a=Yt;break;case 1:a=Kt;break;default:a=Xt}n=a.bind(null,t,n,e),a=void 0,!$e||"touchstart"!==t&&"touchmove"!==t&&"wheel"!==t||(a=!0),r?void 0!==a?e.addEventListener(t,n,{capture:!0,passive:a}):e.addEventListener(t,n,!0):void 0!==a?e.addEventListener(t,n,{passive:a}):e.addEventListener(t,n,!1)}function Rr(e,t,n,r,a){var i=r;if(0==(1&t)&&0==(2&t)&&null!==r)e:for(;;){if(null===r)return;var o=r.tag;if(3===o||4===o){var s=r.stateNode.containerInfo;if(s===a||8===s.nodeType&&s.parentNode===a)break;if(4===o)for(o=r.return;null!==o;){var c=o.tag;if((3===c||4===c)&&((c=o.stateNode.containerInfo)===a||8===c.nodeType&&c.parentNode===a))return;o=o.return}for(;null!==s;){if(null===(o=ta(s)))return;if(5===(c=o.tag)||6===c){r=i=o;continue e}s=s.parentNode}}r=r.return}!function(e,t,n){if(Fe)return e(t,n);Fe=!0;try{return Me(e,t,n)}finally{Fe=!1,Be()}}((function(){var r=i,a=xe(n),o=[];e:{var s=Ot.get(e);if(void 0!==s){var c=pn,l=e;switch(e){case"keypress":if(0===rn(n))break e;case"keydown":case"keyup":c=An;break;case"focusin":l="focus",c=yn;break;case"focusout":l="blur",c=yn;break;case"beforeblur":case"afterblur":c=yn;break;case"click":if(2===n.button)break e;case"auxclick":case"dblclick":case"mousedown":case"mousemove":case"mouseup":case"mouseout":case"mouseover":case"contextmenu":c=gn;break;case"drag":case"dragend":case"dragenter":case"dragexit":case"dragleave":case"dragover":case"dragstart":case"drop":c=vn;break;case"touchcancel":case"touchend":case"touchmove":case"touchstart":c=On;break;case Tt:case Lt:case At:c=bn;break;case Nt:c=Pn;break;case"scroll":c=mn;break;case"wheel":c=Rn;break;case"copy":case"cut":case"paste":c=_n;break;case"gotpointercapture":case"lostpointercapture":case"pointercancel":case"pointerdown":case"pointermove":case"pointerout":case"pointerover":case"pointerup":c=Nn}var u=0!=(4&t),d=!u&&"scroll"===e,p=u?null!==s?s+"Capture":null:s;u=[];for(var f,m=r;null!==m;){var h=(f=m).stateNode;if(5===f.tag&&null!==h&&(f=h,null!==p&&(null!=(h=je(m,p))&&u.push(Mr(m,h,f)))),d)break;m=m.return}0<u.length&&(s=new c(s,l,null,n,a),o.push({event:s,listeners:u}))}}if(0==(7&t)){if(c="mouseout"===e||"pointerout"===e,(!(s="mouseover"===e||"pointerover"===e)||0!=(16&t)||!(l=n.relatedTarget||n.fromElement)||!ta(l)&&!l[Jr])&&(c||s)&&(s=a.window===a?a:(s=a.ownerDocument)?s.defaultView||s.parentWindow:window,c?(c=r,null!==(l=(l=n.relatedTarget||n.toElement)?ta(l):null)&&(l!==(d=Ye(l))||5!==l.tag&&6!==l.tag)&&(l=null)):(c=null,l=r),c!==l)){if(u=gn,h="onMouseLeave",p="onMouseEnter",m="mouse","pointerout"!==e&&"pointerover"!==e||(u=Nn,h="onPointerLeave",p="onPointerEnter",m="pointer"),d=null==c?s:ra(c),f=null==l?s:ra(l),(s=new u(h,m+"leave",c,n,a)).target=d,s.relatedTarget=f,h=null,ta(a)===r&&((u=new u(p,m+"enter",l,n,a)).target=f,u.relatedTarget=d,h=u),d=h,c&&l)e:{for(p=l,m=0,f=u=c;f;f=Fr(f))m++;for(f=0,h=p;h;h=Fr(h))f++;for(;0<m-f;)u=Fr(u),m--;for(;0<f-m;)p=Fr(p),f--;for(;m--;){if(u===p||null!==p&&u===p.alternate)break e;u=Fr(u),p=Fr(p)}u=null}else u=null;null!==c&&Br(o,s,c,u,!1),null!==l&&null!==d&&Br(o,d,l,u,!0)}if("select"===(c=(s=r?ra(r):window).nodeName&&s.nodeName.toLowerCase())||"input"===c&&"file"===s.type)var g=Qn;else if(Vn(s))if(Jn)g=cr;else{g=or;var v=ir}else(c=s.nodeName)&&"input"===c.toLowerCase()&&("checkbox"===s.type||"radio"===s.type)&&(g=sr);switch(g&&(g=g(e,r))?Wn(o,g,n,a):(v&&v(e,s,r),"focusout"===e&&(v=s._wrapperState)&&v.controlled&&"number"===s.type&&ae(s,"number",s.value)),v=r?ra(r):window,e){case"focusin":(Vn(v)||"true"===v.contentEditable)&&(yr=v,br=r,wr=null);break;case"focusout":wr=br=yr=null;break;case"mousedown":_r=!0;break;case"contextmenu":case"mouseup":case"dragend":_r=!1,Sr(o,n,a);break;case"selectionchange":if(vr)break;case"keydown":case"keyup":Sr(o,n,a)}var y;if(Dn)e:{switch(e){case"compositionstart":var b="onCompositionStart";break e;case"compositionend":b="onCompositionEnd";break e;case"compositionupdate":b="onCompositionUpdate";break e}b=void 0}else Zn?Un(e,n)&&(b="onCompositionEnd"):"keydown"===e&&229===n.keyCode&&(b="onCompositionStart");b&&(jn&&"ko"!==n.locale&&(Zn||"onCompositionStart"!==b?"onCompositionEnd"===b&&Zn&&(y=nn()):(en="value"in(Jt=a)?Jt.value:Jt.textContent,Zn=!0)),0<(v=Dr(r,b)).length&&(b=new Sn(b,e,null,n,a),o.push({event:b,listeners:v}),y?b.data=y:null!==(y=qn(n))&&(b.data=y))),(y=Bn?function(e,t){switch(e){case"compositionend":return qn(t);case"keypress":return 32!==t.which?null:(zn=!0,$n);case"textInput":return(e=t.data)===$n&&zn?null:e;default:return null}}(e,n):function(e,t){if(Zn)return"compositionend"===e||!Dn&&Un(e,t)?(e=nn(),tn=en=Jt=null,Zn=!1,e):null;switch(e){case"paste":default:return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1<t.char.length)return t.char;if(t.which)return String.fromCharCode(t.which)}return null;case"compositionend":return jn&&"ko"!==t.locale?null:t.data}}(e,n))&&(0<(r=Dr(r,"onBeforeInput")).length&&(a=new Sn("onBeforeInput","beforeinput",null,n,a),o.push({event:a,listeners:r}),a.data=y))}Lr(o,t)}))}function Mr(e,t,n){return{instance:e,listener:t,currentTarget:n}}function Dr(e,t){for(var n=t+"Capture",r=[];null!==e;){var a=e,i=a.stateNode;5===a.tag&&null!==i&&(a=i,null!=(i=je(e,n))&&r.unshift(Mr(e,i,a)),null!=(i=je(e,t))&&r.push(Mr(e,i,a))),e=e.return}return r}function Fr(e){if(null===e)return null;do{e=e.return}while(e&&5!==e.tag);return e||null}function Br(e,t,n,r,a){for(var i=t._reactName,o=[];null!==n&&n!==r;){var s=n,c=s.alternate,l=s.stateNode;if(null!==c&&c===r)break;5===s.tag&&null!==l&&(s=l,a?null!=(c=je(n,i))&&o.unshift(Mr(n,c,s)):a||null!=(c=je(n,i))&&o.push(Mr(n,c,s))),n=n.return}0!==o.length&&e.push({event:t,listeners:o})}function jr(){}var $r=null,zr=null;function Ur(e,t){switch(e){case"button":case"input":case"select":case"textarea":return!!t.autoFocus}return!1}function qr(e,t){return"textarea"===e||"option"===e||"noscript"===e||"string"==typeof t.children||"number"==typeof t.children||"object"==typeof t.dangerouslySetInnerHTML&&null!==t.dangerouslySetInnerHTML&&null!=t.dangerouslySetInnerHTML.__html}var Zr="function"==typeof setTimeout?setTimeout:void 0,Hr="function"==typeof clearTimeout?clearTimeout:void 0;function Vr(e){1===e.nodeType?e.textContent="":9===e.nodeType&&(null!=(e=e.body)&&(e.textContent=""))}function Wr(e){for(;null!=e;e=e.nextSibling){var t=e.nodeType;if(1===t||3===t)break}return e}function Gr(e){e=e.previousSibling;for(var t=0;e;){if(8===e.nodeType){var n=e.data;if("$"===n||"$!"===n||"$?"===n){if(0===t)return e;t--}else"/$"===n&&t++}e=e.previousSibling}return null}var Yr=0;var Kr=Math.random().toString(36).slice(2),Xr="__reactFiber$"+Kr,Qr="__reactProps$"+Kr,Jr="__reactContainer$"+Kr,ea="__reactEvents$"+Kr;function ta(e){var t=e[Xr];if(t)return t;for(var n=e.parentNode;n;){if(t=n[Jr]||n[Xr]){if(n=t.alternate,null!==t.child||null!==n&&null!==n.child)for(e=Gr(e);null!==e;){if(n=e[Xr])return n;e=Gr(e)}return t}n=(e=n).parentNode}return null}function na(e){return!(e=e[Xr]||e[Jr])||5!==e.tag&&6!==e.tag&&13!==e.tag&&3!==e.tag?null:e}function ra(e){if(5===e.tag||6===e.tag)return e.stateNode;throw Error(o(33))}function aa(e){return e[Qr]||null}function ia(e){var t=e[ea];return void 0===t&&(t=e[ea]=new Set),t}var oa=[],sa=-1;function ca(e){return{current:e}}function la(e){0>sa||(e.current=oa[sa],oa[sa]=null,sa--)}function ua(e,t){sa++,oa[sa]=e.current,e.current=t}var da={},pa=ca(da),fa=ca(!1),ma=da;function ha(e,t){var n=e.type.contextTypes;if(!n)return da;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var a,i={};for(a in n)i[a]=t[a];return r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=i),i}function ga(e){return null!=(e=e.childContextTypes)}function va(){la(fa),la(pa)}function ya(e,t,n){if(pa.current!==da)throw Error(o(168));ua(pa,t),ua(fa,n)}function ba(e,t,n){var r=e.stateNode;if(e=t.childContextTypes,"function"!=typeof r.getChildContext)return n;for(var i in r=r.getChildContext())if(!(i in e))throw Error(o(108,W(t)||"Unknown",i));return a({},n,r)}function wa(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||da,ma=pa.current,ua(pa,e),ua(fa,fa.current),!0}function _a(e,t,n){var r=e.stateNode;if(!r)throw Error(o(169));n?(e=ba(e,t,ma),r.__reactInternalMemoizedMergedChildContext=e,la(fa),la(pa),ua(pa,e)):la(fa),ua(fa,n)}var Sa=null,ka=null,Ea=i.unstable_runWithPriority,xa=i.unstable_scheduleCallback,Ca=i.unstable_cancelCallback,Ta=i.unstable_shouldYield,La=i.unstable_requestPaint,Aa=i.unstable_now,Na=i.unstable_getCurrentPriorityLevel,Oa=i.unstable_ImmediatePriority,Pa=i.unstable_UserBlockingPriority,Ia=i.unstable_NormalPriority,Ra=i.unstable_LowPriority,Ma=i.unstable_IdlePriority,Da={},Fa=void 0!==La?La:function(){},Ba=null,ja=null,$a=!1,za=Aa(),Ua=1e4>za?Aa:function(){return Aa()-za};function qa(){switch(Na()){case Oa:return 99;case Pa:return 98;case Ia:return 97;case Ra:return 96;case Ma:return 95;default:throw Error(o(332))}}function Za(e){switch(e){case 99:return Oa;case 98:return Pa;case 97:return Ia;case 96:return Ra;case 95:return Ma;default:throw Error(o(332))}}function Ha(e,t){return e=Za(e),Ea(e,t)}function Va(e,t,n){return e=Za(e),xa(e,t,n)}function Wa(){if(null!==ja){var e=ja;ja=null,Ca(e)}Ga()}function Ga(){if(!$a&&null!==Ba){$a=!0;var e=0;try{var t=Ba;Ha(99,(function(){for(;e<t.length;e++){var n=t[e];do{n=n(!0)}while(null!==n)}})),Ba=null}catch(n){throw null!==Ba&&(Ba=Ba.slice(e+1)),xa(Oa,Wa),n}finally{$a=!1}}}var Ya=_.ReactCurrentBatchConfig;function Ka(e,t){if(e&&e.defaultProps){for(var n in t=a({},t),e=e.defaultProps)void 0===t[n]&&(t[n]=e[n]);return t}return t}var Xa=ca(null),Qa=null,Ja=null,ei=null;function ti(){ei=Ja=Qa=null}function ni(e){var t=Xa.current;la(Xa),e.type._context._currentValue=t}function ri(e,t){for(;null!==e;){var n=e.alternate;if((e.childLanes&t)===t){if(null===n||(n.childLanes&t)===t)break;n.childLanes|=t}else e.childLanes|=t,null!==n&&(n.childLanes|=t);e=e.return}}function ai(e,t){Qa=e,ei=Ja=null,null!==(e=e.dependencies)&&null!==e.firstContext&&(0!=(e.lanes&t)&&(Do=!0),e.firstContext=null)}function ii(e,t){if(ei!==e&&!1!==t&&0!==t)if("number"==typeof t&&1073741823!==t||(ei=e,t=1073741823),t={context:e,observedBits:t,next:null},null===Ja){if(null===Qa)throw Error(o(308));Ja=t,Qa.dependencies={lanes:0,firstContext:t,responders:null}}else Ja=Ja.next=t;return e._currentValue}var oi=!1;function si(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null},effects:null}}function ci(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function li(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function ui(e,t){if(null!==(e=e.updateQueue)){var n=(e=e.shared).pending;null===n?t.next=t:(t.next=n.next,n.next=t),e.pending=t}}function di(e,t){var n=e.updateQueue,r=e.alternate;if(null!==r&&n===(r=r.updateQueue)){var a=null,i=null;if(null!==(n=n.firstBaseUpdate)){do{var o={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};null===i?a=i=o:i=i.next=o,n=n.next}while(null!==n);null===i?a=i=t:i=i.next=t}else a=i=t;return n={baseState:r.baseState,firstBaseUpdate:a,lastBaseUpdate:i,shared:r.shared,effects:r.effects},void(e.updateQueue=n)}null===(e=n.lastBaseUpdate)?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function pi(e,t,n,r){var i=e.updateQueue;oi=!1;var o=i.firstBaseUpdate,s=i.lastBaseUpdate,c=i.shared.pending;if(null!==c){i.shared.pending=null;var l=c,u=l.next;l.next=null,null===s?o=u:s.next=u,s=l;var d=e.alternate;if(null!==d){var p=(d=d.updateQueue).lastBaseUpdate;p!==s&&(null===p?d.firstBaseUpdate=u:p.next=u,d.lastBaseUpdate=l)}}if(null!==o){for(p=i.baseState,s=0,d=u=l=null;;){c=o.lane;var f=o.eventTime;if((r&c)===c){null!==d&&(d=d.next={eventTime:f,lane:0,tag:o.tag,payload:o.payload,callback:o.callback,next:null});e:{var m=e,h=o;switch(c=t,f=n,h.tag){case 1:if("function"==typeof(m=h.payload)){p=m.call(f,p,c);break e}p=m;break e;case 3:m.flags=-4097&m.flags|64;case 0:if(null==(c="function"==typeof(m=h.payload)?m.call(f,p,c):m))break e;p=a({},p,c);break e;case 2:oi=!0}}null!==o.callback&&(e.flags|=32,null===(c=i.effects)?i.effects=[o]:c.push(o))}else f={eventTime:f,lane:c,tag:o.tag,payload:o.payload,callback:o.callback,next:null},null===d?(u=d=f,l=p):d=d.next=f,s|=c;if(null===(o=o.next)){if(null===(c=i.shared.pending))break;o=c.next,c.next=null,i.lastBaseUpdate=c,i.shared.pending=null}}null===d&&(l=p),i.baseState=l,i.firstBaseUpdate=u,i.lastBaseUpdate=d,zs|=s,e.lanes=s,e.memoizedState=p}}function fi(e,t,n){if(e=t.effects,t.effects=null,null!==e)for(t=0;t<e.length;t++){var r=e[t],a=r.callback;if(null!==a){if(r.callback=null,r=n,"function"!=typeof a)throw Error(o(191,a));a.call(r)}}}var mi=(new r.Component).refs;function hi(e,t,n,r){n=null==(n=n(r,t=e.memoizedState))?t:a({},t,n),e.memoizedState=n,0===e.lanes&&(e.updateQueue.baseState=n)}var gi={isMounted:function(e){return!!(e=e._reactInternals)&&Ye(e)===e},enqueueSetState:function(e,t,n){e=e._reactInternals;var r=pc(),a=fc(e),i=li(r,a);i.payload=t,null!=n&&(i.callback=n),ui(e,i),mc(e,a,r)},enqueueReplaceState:function(e,t,n){e=e._reactInternals;var r=pc(),a=fc(e),i=li(r,a);i.tag=1,i.payload=t,null!=n&&(i.callback=n),ui(e,i),mc(e,a,r)},enqueueForceUpdate:function(e,t){e=e._reactInternals;var n=pc(),r=fc(e),a=li(n,r);a.tag=2,null!=t&&(a.callback=t),ui(e,a),mc(e,r,n)}};function vi(e,t,n,r,a,i,o){return"function"==typeof(e=e.stateNode).shouldComponentUpdate?e.shouldComponentUpdate(r,i,o):!t.prototype||!t.prototype.isPureReactComponent||(!dr(n,r)||!dr(a,i))}function yi(e,t,n){var r=!1,a=da,i=t.contextType;return"object"==typeof i&&null!==i?i=ii(i):(a=ga(t)?ma:pa.current,i=(r=null!=(r=t.contextTypes))?ha(e,a):da),t=new t(n,i),e.memoizedState=null!==t.state&&void 0!==t.state?t.state:null,t.updater=gi,e.stateNode=t,t._reactInternals=e,r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=a,e.__reactInternalMemoizedMaskedChildContext=i),t}function bi(e,t,n,r){e=t.state,"function"==typeof t.componentWillReceiveProps&&t.componentWillReceiveProps(n,r),"function"==typeof t.UNSAFE_componentWillReceiveProps&&t.UNSAFE_componentWillReceiveProps(n,r),t.state!==e&&gi.enqueueReplaceState(t,t.state,null)}function wi(e,t,n,r){var a=e.stateNode;a.props=n,a.state=e.memoizedState,a.refs=mi,si(e);var i=t.contextType;"object"==typeof i&&null!==i?a.context=ii(i):(i=ga(t)?ma:pa.current,a.context=ha(e,i)),pi(e,n,a,r),a.state=e.memoizedState,"function"==typeof(i=t.getDerivedStateFromProps)&&(hi(e,t,i,n),a.state=e.memoizedState),"function"==typeof t.getDerivedStateFromProps||"function"==typeof a.getSnapshotBeforeUpdate||"function"!=typeof a.UNSAFE_componentWillMount&&"function"!=typeof a.componentWillMount||(t=a.state,"function"==typeof a.componentWillMount&&a.componentWillMount(),"function"==typeof a.UNSAFE_componentWillMount&&a.UNSAFE_componentWillMount(),t!==a.state&&gi.enqueueReplaceState(a,a.state,null),pi(e,n,a,r),a.state=e.memoizedState),"function"==typeof a.componentDidMount&&(e.flags|=4)}var _i=Array.isArray;function Si(e,t,n){if(null!==(e=n.ref)&&"function"!=typeof e&&"object"!=typeof e){if(n._owner){if(n=n._owner){if(1!==n.tag)throw Error(o(309));var r=n.stateNode}if(!r)throw Error(o(147,e));var a=""+e;return null!==t&&null!==t.ref&&"function"==typeof t.ref&&t.ref._stringRef===a?t.ref:(t=function(e){var t=r.refs;t===mi&&(t=r.refs={}),null===e?delete t[a]:t[a]=e},t._stringRef=a,t)}if("string"!=typeof e)throw Error(o(284));if(!n._owner)throw Error(o(290,e))}return e}function ki(e,t){if("textarea"!==e.type)throw Error(o(31,"[object Object]"===Object.prototype.toString.call(t)?"object with keys {"+Object.keys(t).join(", ")+"}":t))}function Ei(e){function t(t,n){if(e){var r=t.lastEffect;null!==r?(r.nextEffect=n,t.lastEffect=n):t.firstEffect=t.lastEffect=n,n.nextEffect=null,n.flags=8}}function n(n,r){if(!e)return null;for(;null!==r;)t(n,r),r=r.sibling;return null}function r(e,t){for(e=new Map;null!==t;)null!==t.key?e.set(t.key,t):e.set(t.index,t),t=t.sibling;return e}function a(e,t){return(e=Vc(e,t)).index=0,e.sibling=null,e}function i(t,n,r){return t.index=r,e?null!==(r=t.alternate)?(r=r.index)<n?(t.flags=2,n):r:(t.flags=2,n):n}function s(t){return e&&null===t.alternate&&(t.flags=2),t}function c(e,t,n,r){return null===t||6!==t.tag?((t=Kc(n,e.mode,r)).return=e,t):((t=a(t,n)).return=e,t)}function l(e,t,n,r){return null!==t&&t.elementType===n.type?((r=a(t,n.props)).ref=Si(e,t,n),r.return=e,r):((r=Wc(n.type,n.key,n.props,null,e.mode,r)).ref=Si(e,t,n),r.return=e,r)}function u(e,t,n,r){return null===t||4!==t.tag||t.stateNode.containerInfo!==n.containerInfo||t.stateNode.implementation!==n.implementation?((t=Xc(n,e.mode,r)).return=e,t):((t=a(t,n.children||[])).return=e,t)}function d(e,t,n,r,i){return null===t||7!==t.tag?((t=Gc(n,e.mode,r,i)).return=e,t):((t=a(t,n)).return=e,t)}function p(e,t,n){if("string"==typeof t||"number"==typeof t)return(t=Kc(""+t,e.mode,n)).return=e,t;if("object"==typeof t&&null!==t){switch(t.$$typeof){case S:return(n=Wc(t.type,t.key,t.props,null,e.mode,n)).ref=Si(e,null,t),n.return=e,n;case k:return(t=Xc(t,e.mode,n)).return=e,t}if(_i(t)||U(t))return(t=Gc(t,e.mode,n,null)).return=e,t;ki(e,t)}return null}function f(e,t,n,r){var a=null!==t?t.key:null;if("string"==typeof n||"number"==typeof n)return null!==a?null:c(e,t,""+n,r);if("object"==typeof n&&null!==n){switch(n.$$typeof){case S:return n.key===a?n.type===E?d(e,t,n.props.children,r,a):l(e,t,n,r):null;case k:return n.key===a?u(e,t,n,r):null}if(_i(n)||U(n))return null!==a?null:d(e,t,n,r,null);ki(e,n)}return null}function m(e,t,n,r,a){if("string"==typeof r||"number"==typeof r)return c(t,e=e.get(n)||null,""+r,a);if("object"==typeof r&&null!==r){switch(r.$$typeof){case S:return e=e.get(null===r.key?n:r.key)||null,r.type===E?d(t,e,r.props.children,a,r.key):l(t,e,r,a);case k:return u(t,e=e.get(null===r.key?n:r.key)||null,r,a)}if(_i(r)||U(r))return d(t,e=e.get(n)||null,r,a,null);ki(t,r)}return null}function h(a,o,s,c){for(var l=null,u=null,d=o,h=o=0,g=null;null!==d&&h<s.length;h++){d.index>h?(g=d,d=null):g=d.sibling;var v=f(a,d,s[h],c);if(null===v){null===d&&(d=g);break}e&&d&&null===v.alternate&&t(a,d),o=i(v,o,h),null===u?l=v:u.sibling=v,u=v,d=g}if(h===s.length)return n(a,d),l;if(null===d){for(;h<s.length;h++)null!==(d=p(a,s[h],c))&&(o=i(d,o,h),null===u?l=d:u.sibling=d,u=d);return l}for(d=r(a,d);h<s.length;h++)null!==(g=m(d,a,h,s[h],c))&&(e&&null!==g.alternate&&d.delete(null===g.key?h:g.key),o=i(g,o,h),null===u?l=g:u.sibling=g,u=g);return e&&d.forEach((function(e){return t(a,e)})),l}function g(a,s,c,l){var u=U(c);if("function"!=typeof u)throw Error(o(150));if(null==(c=u.call(c)))throw Error(o(151));for(var d=u=null,h=s,g=s=0,v=null,y=c.next();null!==h&&!y.done;g++,y=c.next()){h.index>g?(v=h,h=null):v=h.sibling;var b=f(a,h,y.value,l);if(null===b){null===h&&(h=v);break}e&&h&&null===b.alternate&&t(a,h),s=i(b,s,g),null===d?u=b:d.sibling=b,d=b,h=v}if(y.done)return n(a,h),u;if(null===h){for(;!y.done;g++,y=c.next())null!==(y=p(a,y.value,l))&&(s=i(y,s,g),null===d?u=y:d.sibling=y,d=y);return u}for(h=r(a,h);!y.done;g++,y=c.next())null!==(y=m(h,a,g,y.value,l))&&(e&&null!==y.alternate&&h.delete(null===y.key?g:y.key),s=i(y,s,g),null===d?u=y:d.sibling=y,d=y);return e&&h.forEach((function(e){return t(a,e)})),u}return function(e,r,i,c){var l="object"==typeof i&&null!==i&&i.type===E&&null===i.key;l&&(i=i.props.children);var u="object"==typeof i&&null!==i;if(u)switch(i.$$typeof){case S:e:{for(u=i.key,l=r;null!==l;){if(l.key===u){if(7===l.tag){if(i.type===E){n(e,l.sibling),(r=a(l,i.props.children)).return=e,e=r;break e}}else if(l.elementType===i.type){n(e,l.sibling),(r=a(l,i.props)).ref=Si(e,l,i),r.return=e,e=r;break e}n(e,l);break}t(e,l),l=l.sibling}i.type===E?((r=Gc(i.props.children,e.mode,c,i.key)).return=e,e=r):((c=Wc(i.type,i.key,i.props,null,e.mode,c)).ref=Si(e,r,i),c.return=e,e=c)}return s(e);case k:e:{for(l=i.key;null!==r;){if(r.key===l){if(4===r.tag&&r.stateNode.containerInfo===i.containerInfo&&r.stateNode.implementation===i.implementation){n(e,r.sibling),(r=a(r,i.children||[])).return=e,e=r;break e}n(e,r);break}t(e,r),r=r.sibling}(r=Xc(i,e.mode,c)).return=e,e=r}return s(e)}if("string"==typeof i||"number"==typeof i)return i=""+i,null!==r&&6===r.tag?(n(e,r.sibling),(r=a(r,i)).return=e,e=r):(n(e,r),(r=Kc(i,e.mode,c)).return=e,e=r),s(e);if(_i(i))return h(e,r,i,c);if(U(i))return g(e,r,i,c);if(u&&ki(e,i),void 0===i&&!l)switch(e.tag){case 1:case 22:case 0:case 11:case 15:throw Error(o(152,W(e.type)||"Component"))}return n(e,r)}}var xi=Ei(!0),Ci=Ei(!1),Ti={},Li=ca(Ti),Ai=ca(Ti),Ni=ca(Ti);function Oi(e){if(e===Ti)throw Error(o(174));return e}function Pi(e,t){switch(ua(Ni,t),ua(Ai,e),ua(Li,Ti),e=t.nodeType){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:fe(null,"");break;default:t=fe(t=(e=8===e?t.parentNode:t).namespaceURI||null,e=e.tagName)}la(Li),ua(Li,t)}function Ii(){la(Li),la(Ai),la(Ni)}function Ri(e){Oi(Ni.current);var t=Oi(Li.current),n=fe(t,e.type);t!==n&&(ua(Ai,e),ua(Li,n))}function Mi(e){Ai.current===e&&(la(Li),la(Ai))}var Di=ca(0);function Fi(e){for(var t=e;null!==t;){if(13===t.tag){var n=t.memoizedState;if(null!==n&&(null===(n=n.dehydrated)||"$?"===n.data||"$!"===n.data))return t}else if(19===t.tag&&void 0!==t.memoizedProps.revealOrder){if(0!=(64&t.flags))return t}else if(null!==t.child){t.child.return=t,t=t.child;continue}if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}var Bi=null,ji=null,$i=!1;function zi(e,t){var n=Zc(5,null,null,0);n.elementType="DELETED",n.type="DELETED",n.stateNode=t,n.return=e,n.flags=8,null!==e.lastEffect?(e.lastEffect.nextEffect=n,e.lastEffect=n):e.firstEffect=e.lastEffect=n}function Ui(e,t){switch(e.tag){case 5:var n=e.type;return null!==(t=1!==t.nodeType||n.toLowerCase()!==t.nodeName.toLowerCase()?null:t)&&(e.stateNode=t,!0);case 6:return null!==(t=""===e.pendingProps||3!==t.nodeType?null:t)&&(e.stateNode=t,!0);default:return!1}}function qi(e){if($i){var t=ji;if(t){var n=t;if(!Ui(e,t)){if(!(t=Wr(n.nextSibling))||!Ui(e,t))return e.flags=-1025&e.flags|2,$i=!1,void(Bi=e);zi(Bi,n)}Bi=e,ji=Wr(t.firstChild)}else e.flags=-1025&e.flags|2,$i=!1,Bi=e}}function Zi(e){for(e=e.return;null!==e&&5!==e.tag&&3!==e.tag&&13!==e.tag;)e=e.return;Bi=e}function Hi(e){if(e!==Bi)return!1;if(!$i)return Zi(e),$i=!0,!1;var t=e.type;if(5!==e.tag||"head"!==t&&"body"!==t&&!qr(t,e.memoizedProps))for(t=ji;t;)zi(e,t),t=Wr(t.nextSibling);if(Zi(e),13===e.tag){if(!(e=null!==(e=e.memoizedState)?e.dehydrated:null))throw Error(o(317));e:{for(e=e.nextSibling,t=0;e;){if(8===e.nodeType){var n=e.data;if("/$"===n){if(0===t){ji=Wr(e.nextSibling);break e}t--}else"$"!==n&&"$!"!==n&&"$?"!==n||t++}e=e.nextSibling}ji=null}}else ji=Bi?Wr(e.stateNode.nextSibling):null;return!0}function Vi(){ji=Bi=null,$i=!1}var Wi=[];function Gi(){for(var e=0;e<Wi.length;e++)Wi[e]._workInProgressVersionPrimary=null;Wi.length=0}var Yi=_.ReactCurrentDispatcher,Ki=_.ReactCurrentBatchConfig,Xi=0,Qi=null,Ji=null,eo=null,to=!1,no=!1;function ro(){throw Error(o(321))}function ao(e,t){if(null===t)return!1;for(var n=0;n<t.length&&n<e.length;n++)if(!lr(e[n],t[n]))return!1;return!0}function io(e,t,n,r,a,i){if(Xi=i,Qi=t,t.memoizedState=null,t.updateQueue=null,t.lanes=0,Yi.current=null===e||null===e.memoizedState?Po:Io,e=n(r,a),no){i=0;do{if(no=!1,!(25>i))throw Error(o(301));i+=1,eo=Ji=null,t.updateQueue=null,Yi.current=Ro,e=n(r,a)}while(no)}if(Yi.current=Oo,t=null!==Ji&&null!==Ji.next,Xi=0,eo=Ji=Qi=null,to=!1,t)throw Error(o(300));return e}function oo(){var e={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return null===eo?Qi.memoizedState=eo=e:eo=eo.next=e,eo}function so(){if(null===Ji){var e=Qi.alternate;e=null!==e?e.memoizedState:null}else e=Ji.next;var t=null===eo?Qi.memoizedState:eo.next;if(null!==t)eo=t,Ji=e;else{if(null===e)throw Error(o(310));e={memoizedState:(Ji=e).memoizedState,baseState:Ji.baseState,baseQueue:Ji.baseQueue,queue:Ji.queue,next:null},null===eo?Qi.memoizedState=eo=e:eo=eo.next=e}return eo}function co(e,t){return"function"==typeof t?t(e):t}function lo(e){var t=so(),n=t.queue;if(null===n)throw Error(o(311));n.lastRenderedReducer=e;var r=Ji,a=r.baseQueue,i=n.pending;if(null!==i){if(null!==a){var s=a.next;a.next=i.next,i.next=s}r.baseQueue=a=i,n.pending=null}if(null!==a){a=a.next,r=r.baseState;var c=s=i=null,l=a;do{var u=l.lane;if((Xi&u)===u)null!==c&&(c=c.next={lane:0,action:l.action,eagerReducer:l.eagerReducer,eagerState:l.eagerState,next:null}),r=l.eagerReducer===e?l.eagerState:e(r,l.action);else{var d={lane:u,action:l.action,eagerReducer:l.eagerReducer,eagerState:l.eagerState,next:null};null===c?(s=c=d,i=r):c=c.next=d,Qi.lanes|=u,zs|=u}l=l.next}while(null!==l&&l!==a);null===c?i=r:c.next=s,lr(r,t.memoizedState)||(Do=!0),t.memoizedState=r,t.baseState=i,t.baseQueue=c,n.lastRenderedState=r}return[t.memoizedState,n.dispatch]}function uo(e){var t=so(),n=t.queue;if(null===n)throw Error(o(311));n.lastRenderedReducer=e;var r=n.dispatch,a=n.pending,i=t.memoizedState;if(null!==a){n.pending=null;var s=a=a.next;do{i=e(i,s.action),s=s.next}while(s!==a);lr(i,t.memoizedState)||(Do=!0),t.memoizedState=i,null===t.baseQueue&&(t.baseState=i),n.lastRenderedState=i}return[i,r]}function po(e,t,n){var r=t._getVersion;r=r(t._source);var a=t._workInProgressVersionPrimary;if(null!==a?e=a===r:(e=e.mutableReadLanes,(e=(Xi&e)===e)&&(t._workInProgressVersionPrimary=r,Wi.push(t))),e)return n(t._source);throw Wi.push(t),Error(o(350))}function fo(e,t,n,r){var a=Is;if(null===a)throw Error(o(349));var i=t._getVersion,s=i(t._source),c=Yi.current,l=c.useState((function(){return po(a,t,n)})),u=l[1],d=l[0];l=eo;var p=e.memoizedState,f=p.refs,m=f.getSnapshot,h=p.source;p=p.subscribe;var g=Qi;return e.memoizedState={refs:f,source:t,subscribe:r},c.useEffect((function(){f.getSnapshot=n,f.setSnapshot=u;var e=i(t._source);if(!lr(s,e)){e=n(t._source),lr(d,e)||(u(e),e=fc(g),a.mutableReadLanes|=e&a.pendingLanes),e=a.mutableReadLanes,a.entangledLanes|=e;for(var r=a.entanglements,o=e;0<o;){var c=31-qt(o),l=1<<c;r[c]|=e,o&=~l}}}),[n,t,r]),c.useEffect((function(){return r(t._source,(function(){var e=f.getSnapshot,n=f.setSnapshot;try{n(e(t._source));var r=fc(g);a.mutableReadLanes|=r&a.pendingLanes}catch(i){n((function(){throw i}))}}))}),[t,r]),lr(m,n)&&lr(h,t)&&lr(p,r)||((e={pending:null,dispatch:null,lastRenderedReducer:co,lastRenderedState:d}).dispatch=u=No.bind(null,Qi,e),l.queue=e,l.baseQueue=null,d=po(a,t,n),l.memoizedState=l.baseState=d),d}function mo(e,t,n){return fo(so(),e,t,n)}function ho(e){var t=oo();return"function"==typeof e&&(e=e()),t.memoizedState=t.baseState=e,e=(e=t.queue={pending:null,dispatch:null,lastRenderedReducer:co,lastRenderedState:e}).dispatch=No.bind(null,Qi,e),[t.memoizedState,e]}function go(e,t,n,r){return e={tag:e,create:t,destroy:n,deps:r,next:null},null===(t=Qi.updateQueue)?(t={lastEffect:null},Qi.updateQueue=t,t.lastEffect=e.next=e):null===(n=t.lastEffect)?t.lastEffect=e.next=e:(r=n.next,n.next=e,e.next=r,t.lastEffect=e),e}function vo(e){return e={current:e},oo().memoizedState=e}function yo(){return so().memoizedState}function bo(e,t,n,r){var a=oo();Qi.flags|=e,a.memoizedState=go(1|t,n,void 0,void 0===r?null:r)}function wo(e,t,n,r){var a=so();r=void 0===r?null:r;var i=void 0;if(null!==Ji){var o=Ji.memoizedState;if(i=o.destroy,null!==r&&ao(r,o.deps))return void go(t,n,i,r)}Qi.flags|=e,a.memoizedState=go(1|t,n,i,r)}function _o(e,t){return bo(516,4,e,t)}function So(e,t){return wo(516,4,e,t)}function ko(e,t){return wo(4,2,e,t)}function Eo(e,t){return"function"==typeof t?(e=e(),t(e),function(){t(null)}):null!=t?(e=e(),t.current=e,function(){t.current=null}):void 0}function xo(e,t,n){return n=null!=n?n.concat([e]):null,wo(4,2,Eo.bind(null,t,e),n)}function Co(){}function To(e,t){var n=so();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&ao(t,r[1])?r[0]:(n.memoizedState=[e,t],e)}function Lo(e,t){var n=so();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&ao(t,r[1])?r[0]:(e=e(),n.memoizedState=[e,t],e)}function Ao(e,t){var n=qa();Ha(98>n?98:n,(function(){e(!0)})),Ha(97<n?97:n,(function(){var n=Ki.transition;Ki.transition=1;try{e(!1),t()}finally{Ki.transition=n}}))}function No(e,t,n){var r=pc(),a=fc(e),i={lane:a,action:n,eagerReducer:null,eagerState:null,next:null},o=t.pending;if(null===o?i.next=i:(i.next=o.next,o.next=i),t.pending=i,o=e.alternate,e===Qi||null!==o&&o===Qi)no=to=!0;else{if(0===e.lanes&&(null===o||0===o.lanes)&&null!==(o=t.lastRenderedReducer))try{var s=t.lastRenderedState,c=o(s,n);if(i.eagerReducer=o,i.eagerState=c,lr(c,s))return}catch(l){}mc(e,a,r)}}var Oo={readContext:ii,useCallback:ro,useContext:ro,useEffect:ro,useImperativeHandle:ro,useLayoutEffect:ro,useMemo:ro,useReducer:ro,useRef:ro,useState:ro,useDebugValue:ro,useDeferredValue:ro,useTransition:ro,useMutableSource:ro,useOpaqueIdentifier:ro,unstable_isNewReconciler:!1},Po={readContext:ii,useCallback:function(e,t){return oo().memoizedState=[e,void 0===t?null:t],e},useContext:ii,useEffect:_o,useImperativeHandle:function(e,t,n){return n=null!=n?n.concat([e]):null,bo(4,2,Eo.bind(null,t,e),n)},useLayoutEffect:function(e,t){return bo(4,2,e,t)},useMemo:function(e,t){var n=oo();return t=void 0===t?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=oo();return t=void 0!==n?n(t):t,r.memoizedState=r.baseState=t,e=(e=r.queue={pending:null,dispatch:null,lastRenderedReducer:e,lastRenderedState:t}).dispatch=No.bind(null,Qi,e),[r.memoizedState,e]},useRef:vo,useState:ho,useDebugValue:Co,useDeferredValue:function(e){var t=ho(e),n=t[0],r=t[1];return _o((function(){var t=Ki.transition;Ki.transition=1;try{r(e)}finally{Ki.transition=t}}),[e]),n},useTransition:function(){var e=ho(!1),t=e[0];return vo(e=Ao.bind(null,e[1])),[e,t]},useMutableSource:function(e,t,n){var r=oo();return r.memoizedState={refs:{getSnapshot:t,setSnapshot:null},source:e,subscribe:n},fo(r,e,t,n)},useOpaqueIdentifier:function(){if($i){var e=!1,t=function(e){return{$$typeof:M,toString:e,valueOf:e}}((function(){throw e||(e=!0,n("r:"+(Yr++).toString(36))),Error(o(355))})),n=ho(t)[1];return 0==(2&Qi.mode)&&(Qi.flags|=516,go(5,(function(){n("r:"+(Yr++).toString(36))}),void 0,null)),t}return ho(t="r:"+(Yr++).toString(36)),t},unstable_isNewReconciler:!1},Io={readContext:ii,useCallback:To,useContext:ii,useEffect:So,useImperativeHandle:xo,useLayoutEffect:ko,useMemo:Lo,useReducer:lo,useRef:yo,useState:function(){return lo(co)},useDebugValue:Co,useDeferredValue:function(e){var t=lo(co),n=t[0],r=t[1];return So((function(){var t=Ki.transition;Ki.transition=1;try{r(e)}finally{Ki.transition=t}}),[e]),n},useTransition:function(){var e=lo(co)[0];return[yo().current,e]},useMutableSource:mo,useOpaqueIdentifier:function(){return lo(co)[0]},unstable_isNewReconciler:!1},Ro={readContext:ii,useCallback:To,useContext:ii,useEffect:So,useImperativeHandle:xo,useLayoutEffect:ko,useMemo:Lo,useReducer:uo,useRef:yo,useState:function(){return uo(co)},useDebugValue:Co,useDeferredValue:function(e){var t=uo(co),n=t[0],r=t[1];return So((function(){var t=Ki.transition;Ki.transition=1;try{r(e)}finally{Ki.transition=t}}),[e]),n},useTransition:function(){var e=uo(co)[0];return[yo().current,e]},useMutableSource:mo,useOpaqueIdentifier:function(){return uo(co)[0]},unstable_isNewReconciler:!1},Mo=_.ReactCurrentOwner,Do=!1;function Fo(e,t,n,r){t.child=null===e?Ci(t,null,n,r):xi(t,e.child,n,r)}function Bo(e,t,n,r,a){n=n.render;var i=t.ref;return ai(t,a),r=io(e,t,n,r,i,a),null===e||Do?(t.flags|=1,Fo(e,t,r,a),t.child):(t.updateQueue=e.updateQueue,t.flags&=-517,e.lanes&=~a,is(e,t,a))}function jo(e,t,n,r,a,i){if(null===e){var o=n.type;return"function"!=typeof o||Hc(o)||void 0!==o.defaultProps||null!==n.compare||void 0!==n.defaultProps?((e=Wc(n.type,null,r,t,t.mode,i)).ref=t.ref,e.return=t,t.child=e):(t.tag=15,t.type=o,$o(e,t,o,r,a,i))}return o=e.child,0==(a&i)&&(a=o.memoizedProps,(n=null!==(n=n.compare)?n:dr)(a,r)&&e.ref===t.ref)?is(e,t,i):(t.flags|=1,(e=Vc(o,r)).ref=t.ref,e.return=t,t.child=e)}function $o(e,t,n,r,a,i){if(null!==e&&dr(e.memoizedProps,r)&&e.ref===t.ref){if(Do=!1,0==(i&a))return t.lanes=e.lanes,is(e,t,i);0!=(16384&e.flags)&&(Do=!0)}return qo(e,t,n,r,i)}function zo(e,t,n){var r=t.pendingProps,a=r.children,i=null!==e?e.memoizedState:null;if("hidden"===r.mode||"unstable-defer-without-hiding"===r.mode)if(0==(4&t.mode))t.memoizedState={baseLanes:0},Sc(t,n);else{if(0==(1073741824&n))return e=null!==i?i.baseLanes|n:n,t.lanes=t.childLanes=1073741824,t.memoizedState={baseLanes:e},Sc(t,e),null;t.memoizedState={baseLanes:0},Sc(t,null!==i?i.baseLanes:n)}else null!==i?(r=i.baseLanes|n,t.memoizedState=null):r=n,Sc(t,r);return Fo(e,t,a,n),t.child}function Uo(e,t){var n=t.ref;(null===e&&null!==n||null!==e&&e.ref!==n)&&(t.flags|=128)}function qo(e,t,n,r,a){var i=ga(n)?ma:pa.current;return i=ha(t,i),ai(t,a),n=io(e,t,n,r,i,a),null===e||Do?(t.flags|=1,Fo(e,t,n,a),t.child):(t.updateQueue=e.updateQueue,t.flags&=-517,e.lanes&=~a,is(e,t,a))}function Zo(e,t,n,r,a){if(ga(n)){var i=!0;wa(t)}else i=!1;if(ai(t,a),null===t.stateNode)null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),yi(t,n,r),wi(t,n,r,a),r=!0;else if(null===e){var o=t.stateNode,s=t.memoizedProps;o.props=s;var c=o.context,l=n.contextType;"object"==typeof l&&null!==l?l=ii(l):l=ha(t,l=ga(n)?ma:pa.current);var u=n.getDerivedStateFromProps,d="function"==typeof u||"function"==typeof o.getSnapshotBeforeUpdate;d||"function"!=typeof o.UNSAFE_componentWillReceiveProps&&"function"!=typeof o.componentWillReceiveProps||(s!==r||c!==l)&&bi(t,o,r,l),oi=!1;var p=t.memoizedState;o.state=p,pi(t,r,o,a),c=t.memoizedState,s!==r||p!==c||fa.current||oi?("function"==typeof u&&(hi(t,n,u,r),c=t.memoizedState),(s=oi||vi(t,n,s,r,p,c,l))?(d||"function"!=typeof o.UNSAFE_componentWillMount&&"function"!=typeof o.componentWillMount||("function"==typeof o.componentWillMount&&o.componentWillMount(),"function"==typeof o.UNSAFE_componentWillMount&&o.UNSAFE_componentWillMount()),"function"==typeof o.componentDidMount&&(t.flags|=4)):("function"==typeof o.componentDidMount&&(t.flags|=4),t.memoizedProps=r,t.memoizedState=c),o.props=r,o.state=c,o.context=l,r=s):("function"==typeof o.componentDidMount&&(t.flags|=4),r=!1)}else{o=t.stateNode,ci(e,t),s=t.memoizedProps,l=t.type===t.elementType?s:Ka(t.type,s),o.props=l,d=t.pendingProps,p=o.context,"object"==typeof(c=n.contextType)&&null!==c?c=ii(c):c=ha(t,c=ga(n)?ma:pa.current);var f=n.getDerivedStateFromProps;(u="function"==typeof f||"function"==typeof o.getSnapshotBeforeUpdate)||"function"!=typeof o.UNSAFE_componentWillReceiveProps&&"function"!=typeof o.componentWillReceiveProps||(s!==d||p!==c)&&bi(t,o,r,c),oi=!1,p=t.memoizedState,o.state=p,pi(t,r,o,a);var m=t.memoizedState;s!==d||p!==m||fa.current||oi?("function"==typeof f&&(hi(t,n,f,r),m=t.memoizedState),(l=oi||vi(t,n,l,r,p,m,c))?(u||"function"!=typeof o.UNSAFE_componentWillUpdate&&"function"!=typeof o.componentWillUpdate||("function"==typeof o.componentWillUpdate&&o.componentWillUpdate(r,m,c),"function"==typeof o.UNSAFE_componentWillUpdate&&o.UNSAFE_componentWillUpdate(r,m,c)),"function"==typeof o.componentDidUpdate&&(t.flags|=4),"function"==typeof o.getSnapshotBeforeUpdate&&(t.flags|=256)):("function"!=typeof o.componentDidUpdate||s===e.memoizedProps&&p===e.memoizedState||(t.flags|=4),"function"!=typeof o.getSnapshotBeforeUpdate||s===e.memoizedProps&&p===e.memoizedState||(t.flags|=256),t.memoizedProps=r,t.memoizedState=m),o.props=r,o.state=m,o.context=c,r=l):("function"!=typeof o.componentDidUpdate||s===e.memoizedProps&&p===e.memoizedState||(t.flags|=4),"function"!=typeof o.getSnapshotBeforeUpdate||s===e.memoizedProps&&p===e.memoizedState||(t.flags|=256),r=!1)}return Ho(e,t,n,r,i,a)}function Ho(e,t,n,r,a,i){Uo(e,t);var o=0!=(64&t.flags);if(!r&&!o)return a&&_a(t,n,!1),is(e,t,i);r=t.stateNode,Mo.current=t;var s=o&&"function"!=typeof n.getDerivedStateFromError?null:r.render();return t.flags|=1,null!==e&&o?(t.child=xi(t,e.child,null,i),t.child=xi(t,null,s,i)):Fo(e,t,s,i),t.memoizedState=r.state,a&&_a(t,n,!0),t.child}function Vo(e){var t=e.stateNode;t.pendingContext?ya(0,t.pendingContext,t.pendingContext!==t.context):t.context&&ya(0,t.context,!1),Pi(e,t.containerInfo)}var Wo,Go,Yo,Ko,Xo={dehydrated:null,retryLane:0};function Qo(e,t,n){var r,a=t.pendingProps,i=Di.current,o=!1;return(r=0!=(64&t.flags))||(r=(null===e||null!==e.memoizedState)&&0!=(2&i)),r?(o=!0,t.flags&=-65):null!==e&&null===e.memoizedState||void 0===a.fallback||!0===a.unstable_avoidThisFallback||(i|=1),ua(Di,1&i),null===e?(void 0!==a.fallback&&qi(t),e=a.children,i=a.fallback,o?(e=Jo(t,e,i,n),t.child.memoizedState={baseLanes:n},t.memoizedState=Xo,e):"number"==typeof a.unstable_expectedLoadTime?(e=Jo(t,e,i,n),t.child.memoizedState={baseLanes:n},t.memoizedState=Xo,t.lanes=33554432,e):((n=Yc({mode:"visible",children:e},t.mode,n,null)).return=t,t.child=n)):(e.memoizedState,o?(a=ts(e,t,a.children,a.fallback,n),o=t.child,i=e.child.memoizedState,o.memoizedState=null===i?{baseLanes:n}:{baseLanes:i.baseLanes|n},o.childLanes=e.childLanes&~n,t.memoizedState=Xo,a):(n=es(e,t,a.children,n),t.memoizedState=null,n))}function Jo(e,t,n,r){var a=e.mode,i=e.child;return t={mode:"hidden",children:t},0==(2&a)&&null!==i?(i.childLanes=0,i.pendingProps=t):i=Yc(t,a,0,null),n=Gc(n,a,r,null),i.return=e,n.return=e,i.sibling=n,e.child=i,n}function es(e,t,n,r){var a=e.child;return e=a.sibling,n=Vc(a,{mode:"visible",children:n}),0==(2&t.mode)&&(n.lanes=r),n.return=t,n.sibling=null,null!==e&&(e.nextEffect=null,e.flags=8,t.firstEffect=t.lastEffect=e),t.child=n}function ts(e,t,n,r,a){var i=t.mode,o=e.child;e=o.sibling;var s={mode:"hidden",children:n};return 0==(2&i)&&t.child!==o?((n=t.child).childLanes=0,n.pendingProps=s,null!==(o=n.lastEffect)?(t.firstEffect=n.firstEffect,t.lastEffect=o,o.nextEffect=null):t.firstEffect=t.lastEffect=null):n=Vc(o,s),null!==e?r=Vc(e,r):(r=Gc(r,i,a,null)).flags|=2,r.return=t,n.return=t,n.sibling=r,t.child=n,r}function ns(e,t){e.lanes|=t;var n=e.alternate;null!==n&&(n.lanes|=t),ri(e.return,t)}function rs(e,t,n,r,a,i){var o=e.memoizedState;null===o?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:r,tail:n,tailMode:a,lastEffect:i}:(o.isBackwards=t,o.rendering=null,o.renderingStartTime=0,o.last=r,o.tail=n,o.tailMode=a,o.lastEffect=i)}function as(e,t,n){var r=t.pendingProps,a=r.revealOrder,i=r.tail;if(Fo(e,t,r.children,n),0!=(2&(r=Di.current)))r=1&r|2,t.flags|=64;else{if(null!==e&&0!=(64&e.flags))e:for(e=t.child;null!==e;){if(13===e.tag)null!==e.memoizedState&&ns(e,n);else if(19===e.tag)ns(e,n);else if(null!==e.child){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;null===e.sibling;){if(null===e.return||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}if(ua(Di,r),0==(2&t.mode))t.memoizedState=null;else switch(a){case"forwards":for(n=t.child,a=null;null!==n;)null!==(e=n.alternate)&&null===Fi(e)&&(a=n),n=n.sibling;null===(n=a)?(a=t.child,t.child=null):(a=n.sibling,n.sibling=null),rs(t,!1,a,n,i,t.lastEffect);break;case"backwards":for(n=null,a=t.child,t.child=null;null!==a;){if(null!==(e=a.alternate)&&null===Fi(e)){t.child=a;break}e=a.sibling,a.sibling=n,n=a,a=e}rs(t,!0,n,null,i,t.lastEffect);break;case"together":rs(t,!1,null,null,void 0,t.lastEffect);break;default:t.memoizedState=null}return t.child}function is(e,t,n){if(null!==e&&(t.dependencies=e.dependencies),zs|=t.lanes,0!=(n&t.childLanes)){if(null!==e&&t.child!==e.child)throw Error(o(153));if(null!==t.child){for(n=Vc(e=t.child,e.pendingProps),t.child=n,n.return=t;null!==e.sibling;)e=e.sibling,(n=n.sibling=Vc(e,e.pendingProps)).return=t;n.sibling=null}return t.child}return null}function os(e,t){if(!$i)switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;null!==t;)null!==t.alternate&&(n=t),t=t.sibling;null===n?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var r=null;null!==n;)null!==n.alternate&&(r=n),n=n.sibling;null===r?t||null===e.tail?e.tail=null:e.tail.sibling=null:r.sibling=null}}function ss(e,t,n){var r=t.pendingProps;switch(t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return null;case 1:case 17:return ga(t.type)&&va(),null;case 3:return Ii(),la(fa),la(pa),Gi(),(r=t.stateNode).pendingContext&&(r.context=r.pendingContext,r.pendingContext=null),null!==e&&null!==e.child||(Hi(t)?t.flags|=4:r.hydrate||(t.flags|=256)),Go(t),null;case 5:Mi(t);var i=Oi(Ni.current);if(n=t.type,null!==e&&null!=t.stateNode)Yo(e,t,n,r,i),e.ref!==t.ref&&(t.flags|=128);else{if(!r){if(null===t.stateNode)throw Error(o(166));return null}if(e=Oi(Li.current),Hi(t)){r=t.stateNode,n=t.type;var s=t.memoizedProps;switch(r[Xr]=t,r[Qr]=s,n){case"dialog":Ar("cancel",r),Ar("close",r);break;case"iframe":case"object":case"embed":Ar("load",r);break;case"video":case"audio":for(e=0;e<xr.length;e++)Ar(xr[e],r);break;case"source":Ar("error",r);break;case"img":case"image":case"link":Ar("error",r),Ar("load",r);break;case"details":Ar("toggle",r);break;case"input":ee(r,s),Ar("invalid",r);break;case"select":r._wrapperState={wasMultiple:!!s.multiple},Ar("invalid",r);break;case"textarea":ce(r,s),Ar("invalid",r)}for(var l in ke(n,s),e=null,s)s.hasOwnProperty(l)&&(i=s[l],"children"===l?"string"==typeof i?r.textContent!==i&&(e=["children",i]):"number"==typeof i&&r.textContent!==""+i&&(e=["children",""+i]):c.hasOwnProperty(l)&&null!=i&&"onScroll"===l&&Ar("scroll",r));switch(n){case"input":K(r),re(r,s,!0);break;case"textarea":K(r),ue(r);break;case"select":case"option":break;default:"function"==typeof s.onClick&&(r.onclick=jr)}r=e,t.updateQueue=r,null!==r&&(t.flags|=4)}else{switch(l=9===i.nodeType?i:i.ownerDocument,e===de.html&&(e=pe(n)),e===de.html?"script"===n?((e=l.createElement("div")).innerHTML="<script><\/script>",e=e.removeChild(e.firstChild)):"string"==typeof r.is?e=l.createElement(n,{is:r.is}):(e=l.createElement(n),"select"===n&&(l=e,r.multiple?l.multiple=!0:r.size&&(l.size=r.size))):e=l.createElementNS(e,n),e[Xr]=t,e[Qr]=r,Wo(e,t,!1,!1),t.stateNode=e,l=Ee(n,r),n){case"dialog":Ar("cancel",e),Ar("close",e),i=r;break;case"iframe":case"object":case"embed":Ar("load",e),i=r;break;case"video":case"audio":for(i=0;i<xr.length;i++)Ar(xr[i],e);i=r;break;case"source":Ar("error",e),i=r;break;case"img":case"image":case"link":Ar("error",e),Ar("load",e),i=r;break;case"details":Ar("toggle",e),i=r;break;case"input":ee(e,r),i=J(e,r),Ar("invalid",e);break;case"option":i=ie(e,r);break;case"select":e._wrapperState={wasMultiple:!!r.multiple},i=a({},r,{value:void 0}),Ar("invalid",e);break;case"textarea":ce(e,r),i=se(e,r),Ar("invalid",e);break;default:i=r}ke(n,i);var u=i;for(s in u)if(u.hasOwnProperty(s)){var d=u[s];"style"===s?_e(e,d):"dangerouslySetInnerHTML"===s?null!=(d=d?d.__html:void 0)&&ge(e,d):"children"===s?"string"==typeof d?("textarea"!==n||""!==d)&&ve(e,d):"number"==typeof d&&ve(e,""+d):"suppressContentEditableWarning"!==s&&"suppressHydrationWarning"!==s&&"autoFocus"!==s&&(c.hasOwnProperty(s)?null!=d&&"onScroll"===s&&Ar("scroll",e):null!=d&&w(e,s,d,l))}switch(n){case"input":K(e),re(e,r,!1);break;case"textarea":K(e),ue(e);break;case"option":null!=r.value&&e.setAttribute("value",""+G(r.value));break;case"select":e.multiple=!!r.multiple,null!=(s=r.value)?oe(e,!!r.multiple,s,!1):null!=r.defaultValue&&oe(e,!!r.multiple,r.defaultValue,!0);break;default:"function"==typeof i.onClick&&(e.onclick=jr)}Ur(n,r)&&(t.flags|=4)}null!==t.ref&&(t.flags|=128)}return null;case 6:if(e&&null!=t.stateNode)Ko(e,t,e.memoizedProps,r);else{if("string"!=typeof r&&null===t.stateNode)throw Error(o(166));n=Oi(Ni.current),Oi(Li.current),Hi(t)?(r=t.stateNode,n=t.memoizedProps,r[Xr]=t,r.nodeValue!==n&&(t.flags|=4)):((r=(9===n.nodeType?n:n.ownerDocument).createTextNode(r))[Xr]=t,t.stateNode=r)}return null;case 13:return la(Di),r=t.memoizedState,0!=(64&t.flags)?(t.lanes=n,t):(r=null!==r,n=!1,null===e?void 0!==t.memoizedProps.fallback&&Hi(t):n=null!==e.memoizedState,r&&!n&&0!=(2&t.mode)&&(null===e&&!0!==t.memoizedProps.unstable_avoidThisFallback||0!=(1&Di.current)?0===Bs&&(Bs=3):(0!==Bs&&3!==Bs||(Bs=4),null===Is||0==(134217727&zs)&&0==(134217727&Us)||yc(Is,Ms))),(r||n)&&(t.flags|=4),null);case 4:return Ii(),Go(t),null===e&&Or(t.stateNode.containerInfo),null;case 10:return ni(t),null;case 19:if(la(Di),null===(r=t.memoizedState))return null;if(s=0!=(64&t.flags),null===(l=r.rendering))if(s)os(r,!1);else{if(0!==Bs||null!==e&&0!=(64&e.flags))for(e=t.child;null!==e;){if(null!==(l=Fi(e))){for(t.flags|=64,os(r,!1),null!==(s=l.updateQueue)&&(t.updateQueue=s,t.flags|=4),null===r.lastEffect&&(t.firstEffect=null),t.lastEffect=r.lastEffect,r=n,n=t.child;null!==n;)e=r,(s=n).flags&=2,s.nextEffect=null,s.firstEffect=null,s.lastEffect=null,null===(l=s.alternate)?(s.childLanes=0,s.lanes=e,s.child=null,s.memoizedProps=null,s.memoizedState=null,s.updateQueue=null,s.dependencies=null,s.stateNode=null):(s.childLanes=l.childLanes,s.lanes=l.lanes,s.child=l.child,s.memoizedProps=l.memoizedProps,s.memoizedState=l.memoizedState,s.updateQueue=l.updateQueue,s.type=l.type,e=l.dependencies,s.dependencies=null===e?null:{lanes:e.lanes,firstContext:e.firstContext}),n=n.sibling;return ua(Di,1&Di.current|2),t.child}e=e.sibling}null!==r.tail&&Ua()>Vs&&(t.flags|=64,s=!0,os(r,!1),t.lanes=33554432)}else{if(!s)if(null!==(e=Fi(l))){if(t.flags|=64,s=!0,null!==(n=e.updateQueue)&&(t.updateQueue=n,t.flags|=4),os(r,!0),null===r.tail&&"hidden"===r.tailMode&&!l.alternate&&!$i)return null!==(t=t.lastEffect=r.lastEffect)&&(t.nextEffect=null),null}else 2*Ua()-r.renderingStartTime>Vs&&1073741824!==n&&(t.flags|=64,s=!0,os(r,!1),t.lanes=33554432);r.isBackwards?(l.sibling=t.child,t.child=l):(null!==(n=r.last)?n.sibling=l:t.child=l,r.last=l)}return null!==r.tail?(n=r.tail,r.rendering=n,r.tail=n.sibling,r.lastEffect=t.lastEffect,r.renderingStartTime=Ua(),n.sibling=null,t=Di.current,ua(Di,s?1&t|2:1&t),n):null;case 23:case 24:return kc(),null!==e&&null!==e.memoizedState!=(null!==t.memoizedState)&&"unstable-defer-without-hiding"!==r.mode&&(t.flags|=4),null}throw Error(o(156,t.tag))}function cs(e){switch(e.tag){case 1:ga(e.type)&&va();var t=e.flags;return 4096&t?(e.flags=-4097&t|64,e):null;case 3:if(Ii(),la(fa),la(pa),Gi(),0!=(64&(t=e.flags)))throw Error(o(285));return e.flags=-4097&t|64,e;case 5:return Mi(e),null;case 13:return la(Di),4096&(t=e.flags)?(e.flags=-4097&t|64,e):null;case 19:return la(Di),null;case 4:return Ii(),null;case 10:return ni(e),null;case 23:case 24:return kc(),null;default:return null}}function ls(e,t){try{var n="",r=t;do{n+=V(r),r=r.return}while(r);var a=n}catch(i){a="\nError generating stack: "+i.message+"\n"+i.stack}return{value:e,source:t,stack:a}}function us(e,t){try{console.error(t.value)}catch(n){setTimeout((function(){throw n}))}}Wo=function(e,t){for(var n=t.child;null!==n;){if(5===n.tag||6===n.tag)e.appendChild(n.stateNode);else if(4!==n.tag&&null!==n.child){n.child.return=n,n=n.child;continue}if(n===t)break;for(;null===n.sibling;){if(null===n.return||n.return===t)return;n=n.return}n.sibling.return=n.return,n=n.sibling}},Go=function(){},Yo=function(e,t,n,r){var i=e.memoizedProps;if(i!==r){e=t.stateNode,Oi(Li.current);var o,s=null;switch(n){case"input":i=J(e,i),r=J(e,r),s=[];break;case"option":i=ie(e,i),r=ie(e,r),s=[];break;case"select":i=a({},i,{value:void 0}),r=a({},r,{value:void 0}),s=[];break;case"textarea":i=se(e,i),r=se(e,r),s=[];break;default:"function"!=typeof i.onClick&&"function"==typeof r.onClick&&(e.onclick=jr)}for(d in ke(n,r),n=null,i)if(!r.hasOwnProperty(d)&&i.hasOwnProperty(d)&&null!=i[d])if("style"===d){var l=i[d];for(o in l)l.hasOwnProperty(o)&&(n||(n={}),n[o]="")}else"dangerouslySetInnerHTML"!==d&&"children"!==d&&"suppressContentEditableWarning"!==d&&"suppressHydrationWarning"!==d&&"autoFocus"!==d&&(c.hasOwnProperty(d)?s||(s=[]):(s=s||[]).push(d,null));for(d in r){var u=r[d];if(l=null!=i?i[d]:void 0,r.hasOwnProperty(d)&&u!==l&&(null!=u||null!=l))if("style"===d)if(l){for(o in l)!l.hasOwnProperty(o)||u&&u.hasOwnProperty(o)||(n||(n={}),n[o]="");for(o in u)u.hasOwnProperty(o)&&l[o]!==u[o]&&(n||(n={}),n[o]=u[o])}else n||(s||(s=[]),s.push(d,n)),n=u;else"dangerouslySetInnerHTML"===d?(u=u?u.__html:void 0,l=l?l.__html:void 0,null!=u&&l!==u&&(s=s||[]).push(d,u)):"children"===d?"string"!=typeof u&&"number"!=typeof u||(s=s||[]).push(d,""+u):"suppressContentEditableWarning"!==d&&"suppressHydrationWarning"!==d&&(c.hasOwnProperty(d)?(null!=u&&"onScroll"===d&&Ar("scroll",e),s||l===u||(s=[])):"object"==typeof u&&null!==u&&u.$$typeof===M?u.toString():(s=s||[]).push(d,u))}n&&(s=s||[]).push("style",n);var d=s;(t.updateQueue=d)&&(t.flags|=4)}},Ko=function(e,t,n,r){n!==r&&(t.flags|=4)};var ds="function"==typeof WeakMap?WeakMap:Map;function ps(e,t,n){(n=li(-1,n)).tag=3,n.payload={element:null};var r=t.value;return n.callback=function(){Ks||(Ks=!0,Xs=r),us(0,t)},n}function fs(e,t,n){(n=li(-1,n)).tag=3;var r=e.type.getDerivedStateFromError;if("function"==typeof r){var a=t.value;n.payload=function(){return us(0,t),r(a)}}var i=e.stateNode;return null!==i&&"function"==typeof i.componentDidCatch&&(n.callback=function(){"function"!=typeof r&&(null===Qs?Qs=new Set([this]):Qs.add(this),us(0,t));var e=t.stack;this.componentDidCatch(t.value,{componentStack:null!==e?e:""})}),n}var ms="function"==typeof WeakSet?WeakSet:Set;function hs(e){var t=e.ref;if(null!==t)if("function"==typeof t)try{t(null)}catch(n){$c(e,n)}else t.current=null}function gs(e,t){switch(t.tag){case 0:case 11:case 15:case 22:case 5:case 6:case 4:case 17:return;case 1:if(256&t.flags&&null!==e){var n=e.memoizedProps,r=e.memoizedState;t=(e=t.stateNode).getSnapshotBeforeUpdate(t.elementType===t.type?n:Ka(t.type,n),r),e.__reactInternalSnapshotBeforeUpdate=t}return;case 3:return void(256&t.flags&&Vr(t.stateNode.containerInfo))}throw Error(o(163))}function vs(e,t,n){switch(n.tag){case 0:case 11:case 15:case 22:if(null!==(t=null!==(t=n.updateQueue)?t.lastEffect:null)){e=t=t.next;do{if(3==(3&e.tag)){var r=e.create;e.destroy=r()}e=e.next}while(e!==t)}if(null!==(t=null!==(t=n.updateQueue)?t.lastEffect:null)){e=t=t.next;do{var a=e;r=a.next,0!=(4&(a=a.tag))&&0!=(1&a)&&(Fc(n,e),Dc(n,e)),e=r}while(e!==t)}return;case 1:return e=n.stateNode,4&n.flags&&(null===t?e.componentDidMount():(r=n.elementType===n.type?t.memoizedProps:Ka(n.type,t.memoizedProps),e.componentDidUpdate(r,t.memoizedState,e.__reactInternalSnapshotBeforeUpdate))),void(null!==(t=n.updateQueue)&&fi(n,t,e));case 3:if(null!==(t=n.updateQueue)){if(e=null,null!==n.child)switch(n.child.tag){case 5:case 1:e=n.child.stateNode}fi(n,t,e)}return;case 5:return e=n.stateNode,void(null===t&&4&n.flags&&Ur(n.type,n.memoizedProps)&&e.focus());case 6:case 4:case 12:case 19:case 17:case 20:case 21:case 23:case 24:return;case 13:return void(null===n.memoizedState&&(n=n.alternate,null!==n&&(n=n.memoizedState,null!==n&&(n=n.dehydrated,null!==n&&_t(n)))))}throw Error(o(163))}function ys(e,t){for(var n=e;;){if(5===n.tag){var r=n.stateNode;if(t)"function"==typeof(r=r.style).setProperty?r.setProperty("display","none","important"):r.display="none";else{r=n.stateNode;var a=n.memoizedProps.style;a=null!=a&&a.hasOwnProperty("display")?a.display:null,r.style.display=we("display",a)}}else if(6===n.tag)n.stateNode.nodeValue=t?"":n.memoizedProps;else if((23!==n.tag&&24!==n.tag||null===n.memoizedState||n===e)&&null!==n.child){n.child.return=n,n=n.child;continue}if(n===e)break;for(;null===n.sibling;){if(null===n.return||n.return===e)return;n=n.return}n.sibling.return=n.return,n=n.sibling}}function bs(e,t){if(ka&&"function"==typeof ka.onCommitFiberUnmount)try{ka.onCommitFiberUnmount(Sa,t)}catch(i){}switch(t.tag){case 0:case 11:case 14:case 15:case 22:if(null!==(e=t.updateQueue)&&null!==(e=e.lastEffect)){var n=e=e.next;do{var r=n,a=r.destroy;if(r=r.tag,void 0!==a)if(0!=(4&r))Fc(t,n);else{r=t;try{a()}catch(i){$c(r,i)}}n=n.next}while(n!==e)}break;case 1:if(hs(t),"function"==typeof(e=t.stateNode).componentWillUnmount)try{e.props=t.memoizedProps,e.state=t.memoizedState,e.componentWillUnmount()}catch(i){$c(t,i)}break;case 5:hs(t);break;case 4:xs(e,t)}}function ws(e){e.alternate=null,e.child=null,e.dependencies=null,e.firstEffect=null,e.lastEffect=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.return=null,e.updateQueue=null}function _s(e){return 5===e.tag||3===e.tag||4===e.tag}function Ss(e){e:{for(var t=e.return;null!==t;){if(_s(t))break e;t=t.return}throw Error(o(160))}var n=t;switch(t=n.stateNode,n.tag){case 5:var r=!1;break;case 3:case 4:t=t.containerInfo,r=!0;break;default:throw Error(o(161))}16&n.flags&&(ve(t,""),n.flags&=-17);e:t:for(n=e;;){for(;null===n.sibling;){if(null===n.return||_s(n.return)){n=null;break e}n=n.return}for(n.sibling.return=n.return,n=n.sibling;5!==n.tag&&6!==n.tag&&18!==n.tag;){if(2&n.flags)continue t;if(null===n.child||4===n.tag)continue t;n.child.return=n,n=n.child}if(!(2&n.flags)){n=n.stateNode;break e}}r?ks(e,n,t):Es(e,n,t)}function ks(e,t,n){var r=e.tag,a=5===r||6===r;if(a)e=a?e.stateNode:e.stateNode.instance,t?8===n.nodeType?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(8===n.nodeType?(t=n.parentNode).insertBefore(e,n):(t=n).appendChild(e),null!=(n=n._reactRootContainer)||null!==t.onclick||(t.onclick=jr));else if(4!==r&&null!==(e=e.child))for(ks(e,t,n),e=e.sibling;null!==e;)ks(e,t,n),e=e.sibling}function Es(e,t,n){var r=e.tag,a=5===r||6===r;if(a)e=a?e.stateNode:e.stateNode.instance,t?n.insertBefore(e,t):n.appendChild(e);else if(4!==r&&null!==(e=e.child))for(Es(e,t,n),e=e.sibling;null!==e;)Es(e,t,n),e=e.sibling}function xs(e,t){for(var n,r,a=t,i=!1;;){if(!i){i=a.return;e:for(;;){if(null===i)throw Error(o(160));switch(n=i.stateNode,i.tag){case 5:r=!1;break e;case 3:case 4:n=n.containerInfo,r=!0;break e}i=i.return}i=!0}if(5===a.tag||6===a.tag){e:for(var s=e,c=a,l=c;;)if(bs(s,l),null!==l.child&&4!==l.tag)l.child.return=l,l=l.child;else{if(l===c)break e;for(;null===l.sibling;){if(null===l.return||l.return===c)break e;l=l.return}l.sibling.return=l.return,l=l.sibling}r?(s=n,c=a.stateNode,8===s.nodeType?s.parentNode.removeChild(c):s.removeChild(c)):n.removeChild(a.stateNode)}else if(4===a.tag){if(null!==a.child){n=a.stateNode.containerInfo,r=!0,a.child.return=a,a=a.child;continue}}else if(bs(e,a),null!==a.child){a.child.return=a,a=a.child;continue}if(a===t)break;for(;null===a.sibling;){if(null===a.return||a.return===t)return;4===(a=a.return).tag&&(i=!1)}a.sibling.return=a.return,a=a.sibling}}function Cs(e,t){switch(t.tag){case 0:case 11:case 14:case 15:case 22:var n=t.updateQueue;if(null!==(n=null!==n?n.lastEffect:null)){var r=n=n.next;do{3==(3&r.tag)&&(e=r.destroy,r.destroy=void 0,void 0!==e&&e()),r=r.next}while(r!==n)}return;case 1:case 12:case 17:return;case 5:if(null!=(n=t.stateNode)){r=t.memoizedProps;var a=null!==e?e.memoizedProps:r;e=t.type;var i=t.updateQueue;if(t.updateQueue=null,null!==i){for(n[Qr]=r,"input"===e&&"radio"===r.type&&null!=r.name&&te(n,r),Ee(e,a),t=Ee(e,r),a=0;a<i.length;a+=2){var s=i[a],c=i[a+1];"style"===s?_e(n,c):"dangerouslySetInnerHTML"===s?ge(n,c):"children"===s?ve(n,c):w(n,s,c,t)}switch(e){case"input":ne(n,r);break;case"textarea":le(n,r);break;case"select":e=n._wrapperState.wasMultiple,n._wrapperState.wasMultiple=!!r.multiple,null!=(i=r.value)?oe(n,!!r.multiple,i,!1):e!==!!r.multiple&&(null!=r.defaultValue?oe(n,!!r.multiple,r.defaultValue,!0):oe(n,!!r.multiple,r.multiple?[]:"",!1))}}}return;case 6:if(null===t.stateNode)throw Error(o(162));return void(t.stateNode.nodeValue=t.memoizedProps);case 3:return void((n=t.stateNode).hydrate&&(n.hydrate=!1,_t(n.containerInfo)));case 13:return null!==t.memoizedState&&(Hs=Ua(),ys(t.child,!0)),void Ts(t);case 19:return void Ts(t);case 23:case 24:return void ys(t,null!==t.memoizedState)}throw Error(o(163))}function Ts(e){var t=e.updateQueue;if(null!==t){e.updateQueue=null;var n=e.stateNode;null===n&&(n=e.stateNode=new ms),t.forEach((function(t){var r=Uc.bind(null,e,t);n.has(t)||(n.add(t),t.then(r,r))}))}}function Ls(e,t){return null!==e&&(null===(e=e.memoizedState)||null!==e.dehydrated)&&(null!==(t=t.memoizedState)&&null===t.dehydrated)}var As=Math.ceil,Ns=_.ReactCurrentDispatcher,Os=_.ReactCurrentOwner,Ps=0,Is=null,Rs=null,Ms=0,Ds=0,Fs=ca(0),Bs=0,js=null,$s=0,zs=0,Us=0,qs=0,Zs=null,Hs=0,Vs=1/0;function Ws(){Vs=Ua()+500}var Gs,Ys=null,Ks=!1,Xs=null,Qs=null,Js=!1,ec=null,tc=90,nc=[],rc=[],ac=null,ic=0,oc=null,sc=-1,cc=0,lc=0,uc=null,dc=!1;function pc(){return 0!=(48&Ps)?Ua():-1!==sc?sc:sc=Ua()}function fc(e){if(0==(2&(e=e.mode)))return 1;if(0==(4&e))return 99===qa()?1:2;if(0===cc&&(cc=$s),0!==Ya.transition){0!==lc&&(lc=null!==Zs?Zs.pendingLanes:0),e=cc;var t=4186112&~lc;return 0===(t&=-t)&&(0===(t=(e=4186112&~e)&-e)&&(t=8192)),t}return e=qa(),0!=(4&Ps)&&98===e?e=jt(12,cc):e=jt(e=function(e){switch(e){case 99:return 15;case 98:return 10;case 97:case 96:return 8;case 95:return 2;default:return 0}}(e),cc),e}function mc(e,t,n){if(50<ic)throw ic=0,oc=null,Error(o(185));if(null===(e=hc(e,t)))return null;Ut(e,t,n),e===Is&&(Us|=t,4===Bs&&yc(e,Ms));var r=qa();1===t?0!=(8&Ps)&&0==(48&Ps)?bc(e):(gc(e,n),0===Ps&&(Ws(),Wa())):(0==(4&Ps)||98!==r&&99!==r||(null===ac?ac=new Set([e]):ac.add(e)),gc(e,n)),Zs=e}function hc(e,t){e.lanes|=t;var n=e.alternate;for(null!==n&&(n.lanes|=t),n=e,e=e.return;null!==e;)e.childLanes|=t,null!==(n=e.alternate)&&(n.childLanes|=t),n=e,e=e.return;return 3===n.tag?n.stateNode:null}function gc(e,t){for(var n=e.callbackNode,r=e.suspendedLanes,a=e.pingedLanes,i=e.expirationTimes,s=e.pendingLanes;0<s;){var c=31-qt(s),l=1<<c,u=i[c];if(-1===u){if(0==(l&r)||0!=(l&a)){u=t,Dt(l);var d=Mt;i[c]=10<=d?u+250:6<=d?u+5e3:-1}}else u<=t&&(e.expiredLanes|=l);s&=~l}if(r=Ft(e,e===Is?Ms:0),t=Mt,0===r)null!==n&&(n!==Da&&Ca(n),e.callbackNode=null,e.callbackPriority=0);else{if(null!==n){if(e.callbackPriority===t)return;n!==Da&&Ca(n)}15===t?(n=bc.bind(null,e),null===Ba?(Ba=[n],ja=xa(Oa,Ga)):Ba.push(n),n=Da):14===t?n=Va(99,bc.bind(null,e)):(n=function(e){switch(e){case 15:case 14:return 99;case 13:case 12:case 11:case 10:return 98;case 9:case 8:case 7:case 6:case 4:case 5:return 97;case 3:case 2:case 1:return 95;case 0:return 90;default:throw Error(o(358,e))}}(t),n=Va(n,vc.bind(null,e))),e.callbackPriority=t,e.callbackNode=n}}function vc(e){if(sc=-1,lc=cc=0,0!=(48&Ps))throw Error(o(327));var t=e.callbackNode;if(Mc()&&e.callbackNode!==t)return null;var n=Ft(e,e===Is?Ms:0);if(0===n)return null;var r=n,a=Ps;Ps|=16;var i=Cc();for(Is===e&&Ms===r||(Ws(),Ec(e,r));;)try{Ac();break}catch(c){xc(e,c)}if(ti(),Ns.current=i,Ps=a,null!==Rs?r=0:(Is=null,Ms=0,r=Bs),0!=($s&Us))Ec(e,0);else if(0!==r){if(2===r&&(Ps|=64,e.hydrate&&(e.hydrate=!1,Vr(e.containerInfo)),0!==(n=Bt(e))&&(r=Tc(e,n))),1===r)throw t=js,Ec(e,0),yc(e,n),gc(e,Ua()),t;switch(e.finishedWork=e.current.alternate,e.finishedLanes=n,r){case 0:case 1:throw Error(o(345));case 2:case 5:Pc(e);break;case 3:if(yc(e,n),(62914560&n)===n&&10<(r=Hs+500-Ua())){if(0!==Ft(e,0))break;if(((a=e.suspendedLanes)&n)!==n){pc(),e.pingedLanes|=e.suspendedLanes&a;break}e.timeoutHandle=Zr(Pc.bind(null,e),r);break}Pc(e);break;case 4:if(yc(e,n),(4186112&n)===n)break;for(r=e.eventTimes,a=-1;0<n;){var s=31-qt(n);i=1<<s,(s=r[s])>a&&(a=s),n&=~i}if(n=a,10<(n=(120>(n=Ua()-n)?120:480>n?480:1080>n?1080:1920>n?1920:3e3>n?3e3:4320>n?4320:1960*As(n/1960))-n)){e.timeoutHandle=Zr(Pc.bind(null,e),n);break}Pc(e);break;default:throw Error(o(329))}}return gc(e,Ua()),e.callbackNode===t?vc.bind(null,e):null}function yc(e,t){for(t&=~qs,t&=~Us,e.suspendedLanes|=t,e.pingedLanes&=~t,e=e.expirationTimes;0<t;){var n=31-qt(t),r=1<<n;e[n]=-1,t&=~r}}function bc(e){if(0!=(48&Ps))throw Error(o(327));if(Mc(),e===Is&&0!=(e.expiredLanes&Ms)){var t=Ms,n=Tc(e,t);0!=($s&Us)&&(n=Tc(e,t=Ft(e,t)))}else n=Tc(e,t=Ft(e,0));if(0!==e.tag&&2===n&&(Ps|=64,e.hydrate&&(e.hydrate=!1,Vr(e.containerInfo)),0!==(t=Bt(e))&&(n=Tc(e,t))),1===n)throw n=js,Ec(e,0),yc(e,t),gc(e,Ua()),n;return e.finishedWork=e.current.alternate,e.finishedLanes=t,Pc(e),gc(e,Ua()),null}function wc(e,t){var n=Ps;Ps|=1;try{return e(t)}finally{0===(Ps=n)&&(Ws(),Wa())}}function _c(e,t){var n=Ps;Ps&=-2,Ps|=8;try{return e(t)}finally{0===(Ps=n)&&(Ws(),Wa())}}function Sc(e,t){ua(Fs,Ds),Ds|=t,$s|=t}function kc(){Ds=Fs.current,la(Fs)}function Ec(e,t){e.finishedWork=null,e.finishedLanes=0;var n=e.timeoutHandle;if(-1!==n&&(e.timeoutHandle=-1,Hr(n)),null!==Rs)for(n=Rs.return;null!==n;){var r=n;switch(r.tag){case 1:null!=(r=r.type.childContextTypes)&&va();break;case 3:Ii(),la(fa),la(pa),Gi();break;case 5:Mi(r);break;case 4:Ii();break;case 13:case 19:la(Di);break;case 10:ni(r);break;case 23:case 24:kc()}n=n.return}Is=e,Rs=Vc(e.current,null),Ms=Ds=$s=t,Bs=0,js=null,qs=Us=zs=0}function xc(e,t){for(;;){var n=Rs;try{if(ti(),Yi.current=Oo,to){for(var r=Qi.memoizedState;null!==r;){var a=r.queue;null!==a&&(a.pending=null),r=r.next}to=!1}if(Xi=0,eo=Ji=Qi=null,no=!1,Os.current=null,null===n||null===n.return){Bs=1,js=t,Rs=null;break}e:{var i=e,o=n.return,s=n,c=t;if(t=Ms,s.flags|=2048,s.firstEffect=s.lastEffect=null,null!==c&&"object"==typeof c&&"function"==typeof c.then){var l=c;if(0==(2&s.mode)){var u=s.alternate;u?(s.updateQueue=u.updateQueue,s.memoizedState=u.memoizedState,s.lanes=u.lanes):(s.updateQueue=null,s.memoizedState=null)}var d=0!=(1&Di.current),p=o;do{var f;if(f=13===p.tag){var m=p.memoizedState;if(null!==m)f=null!==m.dehydrated;else{var h=p.memoizedProps;f=void 0!==h.fallback&&(!0!==h.unstable_avoidThisFallback||!d)}}if(f){var g=p.updateQueue;if(null===g){var v=new Set;v.add(l),p.updateQueue=v}else g.add(l);if(0==(2&p.mode)){if(p.flags|=64,s.flags|=16384,s.flags&=-2981,1===s.tag)if(null===s.alternate)s.tag=17;else{var y=li(-1,1);y.tag=2,ui(s,y)}s.lanes|=1;break e}c=void 0,s=t;var b=i.pingCache;if(null===b?(b=i.pingCache=new ds,c=new Set,b.set(l,c)):void 0===(c=b.get(l))&&(c=new Set,b.set(l,c)),!c.has(s)){c.add(s);var w=zc.bind(null,i,l,s);l.then(w,w)}p.flags|=4096,p.lanes=t;break e}p=p.return}while(null!==p);c=Error((W(s.type)||"A React component")+" suspended while rendering, but no fallback UI was specified.\n\nAdd a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.")}5!==Bs&&(Bs=2),c=ls(c,s),p=o;do{switch(p.tag){case 3:i=c,p.flags|=4096,t&=-t,p.lanes|=t,di(p,ps(0,i,t));break e;case 1:i=c;var _=p.type,S=p.stateNode;if(0==(64&p.flags)&&("function"==typeof _.getDerivedStateFromError||null!==S&&"function"==typeof S.componentDidCatch&&(null===Qs||!Qs.has(S)))){p.flags|=4096,t&=-t,p.lanes|=t,di(p,fs(p,i,t));break e}}p=p.return}while(null!==p)}Oc(n)}catch(k){t=k,Rs===n&&null!==n&&(Rs=n=n.return);continue}break}}function Cc(){var e=Ns.current;return Ns.current=Oo,null===e?Oo:e}function Tc(e,t){var n=Ps;Ps|=16;var r=Cc();for(Is===e&&Ms===t||Ec(e,t);;)try{Lc();break}catch(a){xc(e,a)}if(ti(),Ps=n,Ns.current=r,null!==Rs)throw Error(o(261));return Is=null,Ms=0,Bs}function Lc(){for(;null!==Rs;)Nc(Rs)}function Ac(){for(;null!==Rs&&!Ta();)Nc(Rs)}function Nc(e){var t=Gs(e.alternate,e,Ds);e.memoizedProps=e.pendingProps,null===t?Oc(e):Rs=t,Os.current=null}function Oc(e){var t=e;do{var n=t.alternate;if(e=t.return,0==(2048&t.flags)){if(null!==(n=ss(n,t,Ds)))return void(Rs=n);if(24!==(n=t).tag&&23!==n.tag||null===n.memoizedState||0!=(1073741824&Ds)||0==(4&n.mode)){for(var r=0,a=n.child;null!==a;)r|=a.lanes|a.childLanes,a=a.sibling;n.childLanes=r}null!==e&&0==(2048&e.flags)&&(null===e.firstEffect&&(e.firstEffect=t.firstEffect),null!==t.lastEffect&&(null!==e.lastEffect&&(e.lastEffect.nextEffect=t.firstEffect),e.lastEffect=t.lastEffect),1<t.flags&&(null!==e.lastEffect?e.lastEffect.nextEffect=t:e.firstEffect=t,e.lastEffect=t))}else{if(null!==(n=cs(t)))return n.flags&=2047,void(Rs=n);null!==e&&(e.firstEffect=e.lastEffect=null,e.flags|=2048)}if(null!==(t=t.sibling))return void(Rs=t);Rs=t=e}while(null!==t);0===Bs&&(Bs=5)}function Pc(e){var t=qa();return Ha(99,Ic.bind(null,e,t)),null}function Ic(e,t){do{Mc()}while(null!==ec);if(0!=(48&Ps))throw Error(o(327));var n=e.finishedWork;if(null===n)return null;if(e.finishedWork=null,e.finishedLanes=0,n===e.current)throw Error(o(177));e.callbackNode=null;var r=n.lanes|n.childLanes,a=r,i=e.pendingLanes&~a;e.pendingLanes=a,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=a,e.mutableReadLanes&=a,e.entangledLanes&=a,a=e.entanglements;for(var s=e.eventTimes,c=e.expirationTimes;0<i;){var l=31-qt(i),u=1<<l;a[l]=0,s[l]=-1,c[l]=-1,i&=~u}if(null!==ac&&0==(24&r)&&ac.has(e)&&ac.delete(e),e===Is&&(Rs=Is=null,Ms=0),1<n.flags?null!==n.lastEffect?(n.lastEffect.nextEffect=n,r=n.firstEffect):r=n:r=n.firstEffect,null!==r){if(a=Ps,Ps|=32,Os.current=null,$r=Gt,gr(s=hr())){if("selectionStart"in s)c={start:s.selectionStart,end:s.selectionEnd};else e:if(c=(c=s.ownerDocument)&&c.defaultView||window,(u=c.getSelection&&c.getSelection())&&0!==u.rangeCount){c=u.anchorNode,i=u.anchorOffset,l=u.focusNode,u=u.focusOffset;try{c.nodeType,l.nodeType}catch(C){c=null;break e}var d=0,p=-1,f=-1,m=0,h=0,g=s,v=null;t:for(;;){for(var y;g!==c||0!==i&&3!==g.nodeType||(p=d+i),g!==l||0!==u&&3!==g.nodeType||(f=d+u),3===g.nodeType&&(d+=g.nodeValue.length),null!==(y=g.firstChild);)v=g,g=y;for(;;){if(g===s)break t;if(v===c&&++m===i&&(p=d),v===l&&++h===u&&(f=d),null!==(y=g.nextSibling))break;v=(g=v).parentNode}g=y}c=-1===p||-1===f?null:{start:p,end:f}}else c=null;c=c||{start:0,end:0}}else c=null;zr={focusedElem:s,selectionRange:c},Gt=!1,uc=null,dc=!1,Ys=r;do{try{Rc()}catch(C){if(null===Ys)throw Error(o(330));$c(Ys,C),Ys=Ys.nextEffect}}while(null!==Ys);uc=null,Ys=r;do{try{for(s=e;null!==Ys;){var b=Ys.flags;if(16&b&&ve(Ys.stateNode,""),128&b){var w=Ys.alternate;if(null!==w){var _=w.ref;null!==_&&("function"==typeof _?_(null):_.current=null)}}switch(1038&b){case 2:Ss(Ys),Ys.flags&=-3;break;case 6:Ss(Ys),Ys.flags&=-3,Cs(Ys.alternate,Ys);break;case 1024:Ys.flags&=-1025;break;case 1028:Ys.flags&=-1025,Cs(Ys.alternate,Ys);break;case 4:Cs(Ys.alternate,Ys);break;case 8:xs(s,c=Ys);var S=c.alternate;ws(c),null!==S&&ws(S)}Ys=Ys.nextEffect}}catch(C){if(null===Ys)throw Error(o(330));$c(Ys,C),Ys=Ys.nextEffect}}while(null!==Ys);if(_=zr,w=hr(),b=_.focusedElem,s=_.selectionRange,w!==b&&b&&b.ownerDocument&&mr(b.ownerDocument.documentElement,b)){null!==s&&gr(b)&&(w=s.start,void 0===(_=s.end)&&(_=w),"selectionStart"in b?(b.selectionStart=w,b.selectionEnd=Math.min(_,b.value.length)):(_=(w=b.ownerDocument||document)&&w.defaultView||window).getSelection&&(_=_.getSelection(),c=b.textContent.length,S=Math.min(s.start,c),s=void 0===s.end?S:Math.min(s.end,c),!_.extend&&S>s&&(c=s,s=S,S=c),c=fr(b,S),i=fr(b,s),c&&i&&(1!==_.rangeCount||_.anchorNode!==c.node||_.anchorOffset!==c.offset||_.focusNode!==i.node||_.focusOffset!==i.offset)&&((w=w.createRange()).setStart(c.node,c.offset),_.removeAllRanges(),S>s?(_.addRange(w),_.extend(i.node,i.offset)):(w.setEnd(i.node,i.offset),_.addRange(w))))),w=[];for(_=b;_=_.parentNode;)1===_.nodeType&&w.push({element:_,left:_.scrollLeft,top:_.scrollTop});for("function"==typeof b.focus&&b.focus(),b=0;b<w.length;b++)(_=w[b]).element.scrollLeft=_.left,_.element.scrollTop=_.top}Gt=!!$r,zr=$r=null,e.current=n,Ys=r;do{try{for(b=e;null!==Ys;){var k=Ys.flags;if(36&k&&vs(b,Ys.alternate,Ys),128&k){w=void 0;var E=Ys.ref;if(null!==E){var x=Ys.stateNode;Ys.tag,w=x,"function"==typeof E?E(w):E.current=w}}Ys=Ys.nextEffect}}catch(C){if(null===Ys)throw Error(o(330));$c(Ys,C),Ys=Ys.nextEffect}}while(null!==Ys);Ys=null,Fa(),Ps=a}else e.current=n;if(Js)Js=!1,ec=e,tc=t;else for(Ys=r;null!==Ys;)t=Ys.nextEffect,Ys.nextEffect=null,8&Ys.flags&&((k=Ys).sibling=null,k.stateNode=null),Ys=t;if(0===(r=e.pendingLanes)&&(Qs=null),1===r?e===oc?ic++:(ic=0,oc=e):ic=0,n=n.stateNode,ka&&"function"==typeof ka.onCommitFiberRoot)try{ka.onCommitFiberRoot(Sa,n,void 0,64==(64&n.current.flags))}catch(C){}if(gc(e,Ua()),Ks)throw Ks=!1,e=Xs,Xs=null,e;return 0!=(8&Ps)||Wa(),null}function Rc(){for(;null!==Ys;){var e=Ys.alternate;dc||null===uc||(0!=(8&Ys.flags)?Je(Ys,uc)&&(dc=!0):13===Ys.tag&&Ls(e,Ys)&&Je(Ys,uc)&&(dc=!0));var t=Ys.flags;0!=(256&t)&&gs(e,Ys),0==(512&t)||Js||(Js=!0,Va(97,(function(){return Mc(),null}))),Ys=Ys.nextEffect}}function Mc(){if(90!==tc){var e=97<tc?97:tc;return tc=90,Ha(e,Bc)}return!1}function Dc(e,t){nc.push(t,e),Js||(Js=!0,Va(97,(function(){return Mc(),null})))}function Fc(e,t){rc.push(t,e),Js||(Js=!0,Va(97,(function(){return Mc(),null})))}function Bc(){if(null===ec)return!1;var e=ec;if(ec=null,0!=(48&Ps))throw Error(o(331));var t=Ps;Ps|=32;var n=rc;rc=[];for(var r=0;r<n.length;r+=2){var a=n[r],i=n[r+1],s=a.destroy;if(a.destroy=void 0,"function"==typeof s)try{s()}catch(l){if(null===i)throw Error(o(330));$c(i,l)}}for(n=nc,nc=[],r=0;r<n.length;r+=2){a=n[r],i=n[r+1];try{var c=a.create;a.destroy=c()}catch(l){if(null===i)throw Error(o(330));$c(i,l)}}for(c=e.current.firstEffect;null!==c;)e=c.nextEffect,c.nextEffect=null,8&c.flags&&(c.sibling=null,c.stateNode=null),c=e;return Ps=t,Wa(),!0}function jc(e,t,n){ui(e,t=ps(0,t=ls(n,t),1)),t=pc(),null!==(e=hc(e,1))&&(Ut(e,1,t),gc(e,t))}function $c(e,t){if(3===e.tag)jc(e,e,t);else for(var n=e.return;null!==n;){if(3===n.tag){jc(n,e,t);break}if(1===n.tag){var r=n.stateNode;if("function"==typeof n.type.getDerivedStateFromError||"function"==typeof r.componentDidCatch&&(null===Qs||!Qs.has(r))){var a=fs(n,e=ls(t,e),1);if(ui(n,a),a=pc(),null!==(n=hc(n,1)))Ut(n,1,a),gc(n,a);else if("function"==typeof r.componentDidCatch&&(null===Qs||!Qs.has(r)))try{r.componentDidCatch(t,e)}catch(i){}break}}n=n.return}}function zc(e,t,n){var r=e.pingCache;null!==r&&r.delete(t),t=pc(),e.pingedLanes|=e.suspendedLanes&n,Is===e&&(Ms&n)===n&&(4===Bs||3===Bs&&(62914560&Ms)===Ms&&500>Ua()-Hs?Ec(e,0):qs|=n),gc(e,t)}function Uc(e,t){var n=e.stateNode;null!==n&&n.delete(t),0===(t=0)&&(0==(2&(t=e.mode))?t=1:0==(4&t)?t=99===qa()?1:2:(0===cc&&(cc=$s),0===(t=$t(62914560&~cc))&&(t=4194304))),n=pc(),null!==(e=hc(e,t))&&(Ut(e,t,n),gc(e,n))}function qc(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.flags=0,this.lastEffect=this.firstEffect=this.nextEffect=null,this.childLanes=this.lanes=0,this.alternate=null}function Zc(e,t,n,r){return new qc(e,t,n,r)}function Hc(e){return!(!(e=e.prototype)||!e.isReactComponent)}function Vc(e,t){var n=e.alternate;return null===n?((n=Zc(e.tag,t,e.key,e.mode)).elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.nextEffect=null,n.firstEffect=null,n.lastEffect=null),n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=null===t?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Wc(e,t,n,r,a,i){var s=2;if(r=e,"function"==typeof e)Hc(e)&&(s=1);else if("string"==typeof e)s=5;else e:switch(e){case E:return Gc(n.children,a,i,t);case D:s=8,a|=16;break;case x:s=8,a|=1;break;case C:return(e=Zc(12,n,t,8|a)).elementType=C,e.type=C,e.lanes=i,e;case N:return(e=Zc(13,n,t,a)).type=N,e.elementType=N,e.lanes=i,e;case O:return(e=Zc(19,n,t,a)).elementType=O,e.lanes=i,e;case F:return Yc(n,a,i,t);case B:return(e=Zc(24,n,t,a)).elementType=B,e.lanes=i,e;default:if("object"==typeof e&&null!==e)switch(e.$$typeof){case T:s=10;break e;case L:s=9;break e;case A:s=11;break e;case P:s=14;break e;case I:s=16,r=null;break e;case R:s=22;break e}throw Error(o(130,null==e?e:typeof e,""))}return(t=Zc(s,n,t,a)).elementType=e,t.type=r,t.lanes=i,t}function Gc(e,t,n,r){return(e=Zc(7,e,r,t)).lanes=n,e}function Yc(e,t,n,r){return(e=Zc(23,e,r,t)).elementType=F,e.lanes=n,e}function Kc(e,t,n){return(e=Zc(6,e,null,t)).lanes=n,e}function Xc(e,t,n){return(t=Zc(4,null!==e.children?e.children:[],e.key,t)).lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Qc(e,t,n){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.pendingContext=this.context=null,this.hydrate=n,this.callbackNode=null,this.callbackPriority=0,this.eventTimes=zt(0),this.expirationTimes=zt(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=zt(0),this.mutableSourceEagerHydrationData=null}function Jc(e,t,n,r){var a=t.current,i=pc(),s=fc(a);e:if(n){t:{if(Ye(n=n._reactInternals)!==n||1!==n.tag)throw Error(o(170));var c=n;do{switch(c.tag){case 3:c=c.stateNode.context;break t;case 1:if(ga(c.type)){c=c.stateNode.__reactInternalMemoizedMergedChildContext;break t}}c=c.return}while(null!==c);throw Error(o(171))}if(1===n.tag){var l=n.type;if(ga(l)){n=ba(n,l,c);break e}}n=c}else n=da;return null===t.context?t.context=n:t.pendingContext=n,(t=li(i,s)).payload={element:e},null!==(r=void 0===r?null:r)&&(t.callback=r),ui(a,t),mc(a,s,i),s}function el(e){return(e=e.current).child?(e.child.tag,e.child.stateNode):null}function tl(e,t){if(null!==(e=e.memoizedState)&&null!==e.dehydrated){var n=e.retryLane;e.retryLane=0!==n&&n<t?n:t}}function nl(e,t){tl(e,t),(e=e.alternate)&&tl(e,t)}function rl(e,t,n){var r=null!=n&&null!=n.hydrationOptions&&n.hydrationOptions.mutableSources||null;if(n=new Qc(e,t,null!=n&&!0===n.hydrate),t=Zc(3,null,null,2===t?7:1===t?3:0),n.current=t,t.stateNode=n,si(t),e[Jr]=n.current,Or(8===e.nodeType?e.parentNode:e),r)for(e=0;e<r.length;e++){var a=(t=r[e])._getVersion;a=a(t._source),null==n.mutableSourceEagerHydrationData?n.mutableSourceEagerHydrationData=[t,a]:n.mutableSourceEagerHydrationData.push(t,a)}this._internalRoot=n}function al(e){return!(!e||1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType&&(8!==e.nodeType||" react-mount-point-unstable "!==e.nodeValue))}function il(e,t,n,r,a){var i=n._reactRootContainer;if(i){var o=i._internalRoot;if("function"==typeof a){var s=a;a=function(){var e=el(o);s.call(e)}}Jc(t,o,e,a)}else{if(i=n._reactRootContainer=function(e,t){if(t||(t=!(!(t=e?9===e.nodeType?e.documentElement:e.firstChild:null)||1!==t.nodeType||!t.hasAttribute("data-reactroot"))),!t)for(var n;n=e.lastChild;)e.removeChild(n);return new rl(e,0,t?{hydrate:!0}:void 0)}(n,r),o=i._internalRoot,"function"==typeof a){var c=a;a=function(){var e=el(o);c.call(e)}}_c((function(){Jc(t,o,e,a)}))}return el(o)}function ol(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null;if(!al(t))throw Error(o(200));return function(e,t,n){var r=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null;return{$$typeof:k,key:null==r?null:""+r,children:e,containerInfo:t,implementation:n}}(e,t,null,n)}Gs=function(e,t,n){var r=t.lanes;if(null!==e)if(e.memoizedProps!==t.pendingProps||fa.current)Do=!0;else{if(0==(n&r)){switch(Do=!1,t.tag){case 3:Vo(t),Vi();break;case 5:Ri(t);break;case 1:ga(t.type)&&wa(t);break;case 4:Pi(t,t.stateNode.containerInfo);break;case 10:r=t.memoizedProps.value;var a=t.type._context;ua(Xa,a._currentValue),a._currentValue=r;break;case 13:if(null!==t.memoizedState)return 0!=(n&t.child.childLanes)?Qo(e,t,n):(ua(Di,1&Di.current),null!==(t=is(e,t,n))?t.sibling:null);ua(Di,1&Di.current);break;case 19:if(r=0!=(n&t.childLanes),0!=(64&e.flags)){if(r)return as(e,t,n);t.flags|=64}if(null!==(a=t.memoizedState)&&(a.rendering=null,a.tail=null,a.lastEffect=null),ua(Di,Di.current),r)break;return null;case 23:case 24:return t.lanes=0,zo(e,t,n)}return is(e,t,n)}Do=0!=(16384&e.flags)}else Do=!1;switch(t.lanes=0,t.tag){case 2:if(r=t.type,null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),e=t.pendingProps,a=ha(t,pa.current),ai(t,n),a=io(null,t,r,e,a,n),t.flags|=1,"object"==typeof a&&null!==a&&"function"==typeof a.render&&void 0===a.$$typeof){if(t.tag=1,t.memoizedState=null,t.updateQueue=null,ga(r)){var i=!0;wa(t)}else i=!1;t.memoizedState=null!==a.state&&void 0!==a.state?a.state:null,si(t);var s=r.getDerivedStateFromProps;"function"==typeof s&&hi(t,r,s,e),a.updater=gi,t.stateNode=a,a._reactInternals=t,wi(t,r,e,n),t=Ho(null,t,r,!0,i,n)}else t.tag=0,Fo(null,t,a,n),t=t.child;return t;case 16:a=t.elementType;e:{switch(null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),e=t.pendingProps,a=(i=a._init)(a._payload),t.type=a,i=t.tag=function(e){if("function"==typeof e)return Hc(e)?1:0;if(null!=e){if((e=e.$$typeof)===A)return 11;if(e===P)return 14}return 2}(a),e=Ka(a,e),i){case 0:t=qo(null,t,a,e,n);break e;case 1:t=Zo(null,t,a,e,n);break e;case 11:t=Bo(null,t,a,e,n);break e;case 14:t=jo(null,t,a,Ka(a.type,e),r,n);break e}throw Error(o(306,a,""))}return t;case 0:return r=t.type,a=t.pendingProps,qo(e,t,r,a=t.elementType===r?a:Ka(r,a),n);case 1:return r=t.type,a=t.pendingProps,Zo(e,t,r,a=t.elementType===r?a:Ka(r,a),n);case 3:if(Vo(t),r=t.updateQueue,null===e||null===r)throw Error(o(282));if(r=t.pendingProps,a=null!==(a=t.memoizedState)?a.element:null,ci(e,t),pi(t,r,null,n),(r=t.memoizedState.element)===a)Vi(),t=is(e,t,n);else{if((i=(a=t.stateNode).hydrate)&&(ji=Wr(t.stateNode.containerInfo.firstChild),Bi=t,i=$i=!0),i){if(null!=(e=a.mutableSourceEagerHydrationData))for(a=0;a<e.length;a+=2)(i=e[a])._workInProgressVersionPrimary=e[a+1],Wi.push(i);for(n=Ci(t,null,r,n),t.child=n;n;)n.flags=-3&n.flags|1024,n=n.sibling}else Fo(e,t,r,n),Vi();t=t.child}return t;case 5:return Ri(t),null===e&&qi(t),r=t.type,a=t.pendingProps,i=null!==e?e.memoizedProps:null,s=a.children,qr(r,a)?s=null:null!==i&&qr(r,i)&&(t.flags|=16),Uo(e,t),Fo(e,t,s,n),t.child;case 6:return null===e&&qi(t),null;case 13:return Qo(e,t,n);case 4:return Pi(t,t.stateNode.containerInfo),r=t.pendingProps,null===e?t.child=xi(t,null,r,n):Fo(e,t,r,n),t.child;case 11:return r=t.type,a=t.pendingProps,Bo(e,t,r,a=t.elementType===r?a:Ka(r,a),n);case 7:return Fo(e,t,t.pendingProps,n),t.child;case 8:case 12:return Fo(e,t,t.pendingProps.children,n),t.child;case 10:e:{r=t.type._context,a=t.pendingProps,s=t.memoizedProps,i=a.value;var c=t.type._context;if(ua(Xa,c._currentValue),c._currentValue=i,null!==s)if(c=s.value,0===(i=lr(c,i)?0:0|("function"==typeof r._calculateChangedBits?r._calculateChangedBits(c,i):1073741823))){if(s.children===a.children&&!fa.current){t=is(e,t,n);break e}}else for(null!==(c=t.child)&&(c.return=t);null!==c;){var l=c.dependencies;if(null!==l){s=c.child;for(var u=l.firstContext;null!==u;){if(u.context===r&&0!=(u.observedBits&i)){1===c.tag&&((u=li(-1,n&-n)).tag=2,ui(c,u)),c.lanes|=n,null!==(u=c.alternate)&&(u.lanes|=n),ri(c.return,n),l.lanes|=n;break}u=u.next}}else s=10===c.tag&&c.type===t.type?null:c.child;if(null!==s)s.return=c;else for(s=c;null!==s;){if(s===t){s=null;break}if(null!==(c=s.sibling)){c.return=s.return,s=c;break}s=s.return}c=s}Fo(e,t,a.children,n),t=t.child}return t;case 9:return a=t.type,r=(i=t.pendingProps).children,ai(t,n),r=r(a=ii(a,i.unstable_observedBits)),t.flags|=1,Fo(e,t,r,n),t.child;case 14:return i=Ka(a=t.type,t.pendingProps),jo(e,t,a,i=Ka(a.type,i),r,n);case 15:return $o(e,t,t.type,t.pendingProps,r,n);case 17:return r=t.type,a=t.pendingProps,a=t.elementType===r?a:Ka(r,a),null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),t.tag=1,ga(r)?(e=!0,wa(t)):e=!1,ai(t,n),yi(t,r,a),wi(t,r,a,n),Ho(null,t,r,!0,e,n);case 19:return as(e,t,n);case 23:case 24:return zo(e,t,n)}throw Error(o(156,t.tag))},rl.prototype.render=function(e){Jc(e,this._internalRoot,null,null)},rl.prototype.unmount=function(){var e=this._internalRoot,t=e.containerInfo;Jc(null,e,null,(function(){t[Jr]=null}))},et=function(e){13===e.tag&&(mc(e,4,pc()),nl(e,4))},tt=function(e){13===e.tag&&(mc(e,67108864,pc()),nl(e,67108864))},nt=function(e){if(13===e.tag){var t=pc(),n=fc(e);mc(e,n,t),nl(e,n)}},rt=function(e,t){return t()},Ce=function(e,t,n){switch(t){case"input":if(ne(e,n),t=n.name,"radio"===n.type&&null!=t){for(n=e;n.parentNode;)n=n.parentNode;for(n=n.querySelectorAll("input[name="+JSON.stringify(""+t)+'][type="radio"]'),t=0;t<n.length;t++){var r=n[t];if(r!==e&&r.form===e.form){var a=aa(r);if(!a)throw Error(o(90));X(r),ne(r,a)}}}break;case"textarea":le(e,n);break;case"select":null!=(t=n.value)&&oe(e,!!n.multiple,t,!1)}},Pe=wc,Ie=function(e,t,n,r,a){var i=Ps;Ps|=4;try{return Ha(98,e.bind(null,t,n,r,a))}finally{0===(Ps=i)&&(Ws(),Wa())}},Re=function(){0==(49&Ps)&&(function(){if(null!==ac){var e=ac;ac=null,e.forEach((function(e){e.expiredLanes|=24&e.pendingLanes,gc(e,Ua())}))}Wa()}(),Mc())},Me=function(e,t){var n=Ps;Ps|=2;try{return e(t)}finally{0===(Ps=n)&&(Ws(),Wa())}};var sl={Events:[na,ra,aa,Ne,Oe,Mc,{current:!1}]},cl={findFiberByHostInstance:ta,bundleType:0,version:"17.0.2",rendererPackageName:"react-dom"},ll={bundleType:cl.bundleType,version:cl.version,rendererPackageName:cl.rendererPackageName,rendererConfig:cl.rendererConfig,overrideHookState:null,overrideHookStateDeletePath:null,overrideHookStateRenamePath:null,overrideProps:null,overridePropsDeletePath:null,overridePropsRenamePath:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:_.ReactCurrentDispatcher,findHostInstanceByFiber:function(e){return null===(e=Qe(e))?null:e.stateNode},findFiberByHostInstance:cl.findFiberByHostInstance||function(){return null},findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null};if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__){var ul=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(!ul.isDisabled&&ul.supportsFiber)try{Sa=ul.inject(ll),ka=ul}catch(he){}}t.hydrate=function(e,t,n){if(!al(t))throw Error(o(200));return il(null,e,t,!0,n)}},3935:(e,t,n)=>{"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}(),e.exports=n(4448)},9590:e=>{var t="undefined"!=typeof Element,n="function"==typeof Map,r="function"==typeof Set,a="function"==typeof ArrayBuffer&&!!ArrayBuffer.isView;function i(e,o){if(e===o)return!0;if(e&&o&&"object"==typeof e&&"object"==typeof o){if(e.constructor!==o.constructor)return!1;var s,c,l,u;if(Array.isArray(e)){if((s=e.length)!=o.length)return!1;for(c=s;0!=c--;)if(!i(e[c],o[c]))return!1;return!0}if(n&&e instanceof Map&&o instanceof Map){if(e.size!==o.size)return!1;for(u=e.entries();!(c=u.next()).done;)if(!o.has(c.value[0]))return!1;for(u=e.entries();!(c=u.next()).done;)if(!i(c.value[1],o.get(c.value[0])))return!1;return!0}if(r&&e instanceof Set&&o instanceof Set){if(e.size!==o.size)return!1;for(u=e.entries();!(c=u.next()).done;)if(!o.has(c.value[0]))return!1;return!0}if(a&&ArrayBuffer.isView(e)&&ArrayBuffer.isView(o)){if((s=e.length)!=o.length)return!1;for(c=s;0!=c--;)if(e[c]!==o[c])return!1;return!0}if(e.constructor===RegExp)return e.source===o.source&&e.flags===o.flags;if(e.valueOf!==Object.prototype.valueOf)return e.valueOf()===o.valueOf();if(e.toString!==Object.prototype.toString)return e.toString()===o.toString();if((s=(l=Object.keys(e)).length)!==Object.keys(o).length)return!1;for(c=s;0!=c--;)if(!Object.prototype.hasOwnProperty.call(o,l[c]))return!1;if(t&&e instanceof Element)return!1;for(c=s;0!=c--;)if(("_owner"!==l[c]&&"__v"!==l[c]&&"__o"!==l[c]||!e.$$typeof)&&!i(e[l[c]],o[l[c]]))return!1;return!0}return e!=e&&o!=o}e.exports=function(e,t){try{return i(e,t)}catch(n){if((n.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw n}}},405:(e,t,n)=>{"use strict";n.d(t,{B6:()=>H,ql:()=>J});var r=n(7294),a=n(5697),i=n.n(a),o=n(9590),s=n.n(o),c=n(1143),l=n.n(c),u=n(6774),d=n.n(u);function p(){return p=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},p.apply(this,arguments)}function f(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,m(e,t)}function m(e,t){return m=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},m(e,t)}function h(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)t.indexOf(n=i[r])>=0||(a[n]=e[n]);return a}var g={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title",FRAGMENT:"Symbol(react.fragment)"},v={rel:["amphtml","canonical","alternate"]},y={type:["application/ld+json"]},b={charset:"",name:["robots","description"],property:["og:type","og:title","og:url","og:image","og:image:alt","og:description","twitter:url","twitter:title","twitter:description","twitter:image","twitter:image:alt","twitter:card","twitter:site"]},w=Object.keys(g).map((function(e){return g[e]})),_={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"},S=Object.keys(_).reduce((function(e,t){return e[_[t]]=t,e}),{}),k=function(e,t){for(var n=e.length-1;n>=0;n-=1){var r=e[n];if(Object.prototype.hasOwnProperty.call(r,t))return r[t]}return null},E=function(e){var t=k(e,g.TITLE),n=k(e,"titleTemplate");if(Array.isArray(t)&&(t=t.join("")),n&&t)return n.replace(/%s/g,(function(){return t}));var r=k(e,"defaultTitle");return t||r||void 0},x=function(e){return k(e,"onChangeClientState")||function(){}},C=function(e,t){return t.filter((function(t){return void 0!==t[e]})).map((function(t){return t[e]})).reduce((function(e,t){return p({},e,t)}),{})},T=function(e,t){return t.filter((function(e){return void 0!==e[g.BASE]})).map((function(e){return e[g.BASE]})).reverse().reduce((function(t,n){if(!t.length)for(var r=Object.keys(n),a=0;a<r.length;a+=1){var i=r[a].toLowerCase();if(-1!==e.indexOf(i)&&n[i])return t.concat(n)}return t}),[])},L=function(e,t,n){var r={};return n.filter((function(t){return!!Array.isArray(t[e])||(void 0!==t[e]&&console&&"function"==typeof console.warn&&console.warn("Helmet: "+e+' should be of type "Array". Instead found type "'+typeof t[e]+'"'),!1)})).map((function(t){return t[e]})).reverse().reduce((function(e,n){var a={};n.filter((function(e){for(var n,i=Object.keys(e),o=0;o<i.length;o+=1){var s=i[o],c=s.toLowerCase();-1===t.indexOf(c)||"rel"===n&&"canonical"===e[n].toLowerCase()||"rel"===c&&"stylesheet"===e[c].toLowerCase()||(n=c),-1===t.indexOf(s)||"innerHTML"!==s&&"cssText"!==s&&"itemprop"!==s||(n=s)}if(!n||!e[n])return!1;var l=e[n].toLowerCase();return r[n]||(r[n]={}),a[n]||(a[n]={}),!r[n][l]&&(a[n][l]=!0,!0)})).reverse().forEach((function(t){return e.push(t)}));for(var i=Object.keys(a),o=0;o<i.length;o+=1){var s=i[o],c=p({},r[s],a[s]);r[s]=c}return e}),[]).reverse()},A=function(e,t){if(Array.isArray(e)&&e.length)for(var n=0;n<e.length;n+=1)if(e[n][t])return!0;return!1},N=function(e){return Array.isArray(e)?e.join(""):e},O=function(e,t){return Array.isArray(e)?e.reduce((function(e,n){return function(e,t){for(var n=Object.keys(e),r=0;r<n.length;r+=1)if(t[n[r]]&&t[n[r]].includes(e[n[r]]))return!0;return!1}(n,t)?e.priority.push(n):e.default.push(n),e}),{priority:[],default:[]}):{default:e}},P=function(e,t){var n;return p({},e,((n={})[t]=void 0,n))},I=[g.NOSCRIPT,g.SCRIPT,g.STYLE],R=function(e,t){return void 0===t&&(t=!0),!1===t?String(e):String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")},M=function(e){return Object.keys(e).reduce((function(t,n){var r=void 0!==e[n]?n+'="'+e[n]+'"':""+n;return t?t+" "+r:r}),"")},D=function(e,t){return void 0===t&&(t={}),Object.keys(e).reduce((function(t,n){return t[_[n]||n]=e[n],t}),t)},F=function(e,t){return t.map((function(t,n){var a,i=((a={key:n})["data-rh"]=!0,a);return Object.keys(t).forEach((function(e){var n=_[e]||e;"innerHTML"===n||"cssText"===n?i.dangerouslySetInnerHTML={__html:t.innerHTML||t.cssText}:i[n]=t[e]})),r.createElement(e,i)}))},B=function(e,t,n){switch(e){case g.TITLE:return{toComponent:function(){return n=t.titleAttributes,(a={key:e=t.title})["data-rh"]=!0,i=D(n,a),[r.createElement(g.TITLE,i,e)];var e,n,a,i},toString:function(){return function(e,t,n,r){var a=M(n),i=N(t);return a?"<"+e+' data-rh="true" '+a+">"+R(i,r)+"</"+e+">":"<"+e+' data-rh="true">'+R(i,r)+"</"+e+">"}(e,t.title,t.titleAttributes,n)}};case"bodyAttributes":case"htmlAttributes":return{toComponent:function(){return D(t)},toString:function(){return M(t)}};default:return{toComponent:function(){return F(e,t)},toString:function(){return function(e,t,n){return t.reduce((function(t,r){var a=Object.keys(r).filter((function(e){return!("innerHTML"===e||"cssText"===e)})).reduce((function(e,t){var a=void 0===r[t]?t:t+'="'+R(r[t],n)+'"';return e?e+" "+a:a}),""),i=r.innerHTML||r.cssText||"",o=-1===I.indexOf(e);return t+"<"+e+' data-rh="true" '+a+(o?"/>":">"+i+"</"+e+">")}),"")}(e,t,n)}}}},j=function(e){var t=e.baseTag,n=e.bodyAttributes,r=e.encode,a=e.htmlAttributes,i=e.noscriptTags,o=e.styleTags,s=e.title,c=void 0===s?"":s,l=e.titleAttributes,u=e.linkTags,d=e.metaTags,p=e.scriptTags,f={toComponent:function(){},toString:function(){return""}};if(e.prioritizeSeoTags){var m=function(e){var t=e.linkTags,n=e.scriptTags,r=e.encode,a=O(e.metaTags,b),i=O(t,v),o=O(n,y);return{priorityMethods:{toComponent:function(){return[].concat(F(g.META,a.priority),F(g.LINK,i.priority),F(g.SCRIPT,o.priority))},toString:function(){return B(g.META,a.priority,r)+" "+B(g.LINK,i.priority,r)+" "+B(g.SCRIPT,o.priority,r)}},metaTags:a.default,linkTags:i.default,scriptTags:o.default}}(e);f=m.priorityMethods,u=m.linkTags,d=m.metaTags,p=m.scriptTags}return{priority:f,base:B(g.BASE,t,r),bodyAttributes:B("bodyAttributes",n,r),htmlAttributes:B("htmlAttributes",a,r),link:B(g.LINK,u,r),meta:B(g.META,d,r),noscript:B(g.NOSCRIPT,i,r),script:B(g.SCRIPT,p,r),style:B(g.STYLE,o,r),title:B(g.TITLE,{title:c,titleAttributes:l},r)}},$=[],z=function(e,t){var n=this;void 0===t&&(t="undefined"!=typeof document),this.instances=[],this.value={setHelmet:function(e){n.context.helmet=e},helmetInstances:{get:function(){return n.canUseDOM?$:n.instances},add:function(e){(n.canUseDOM?$:n.instances).push(e)},remove:function(e){var t=(n.canUseDOM?$:n.instances).indexOf(e);(n.canUseDOM?$:n.instances).splice(t,1)}}},this.context=e,this.canUseDOM=t,t||(e.helmet=j({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}}))},U=r.createContext({}),q=i().shape({setHelmet:i().func,helmetInstances:i().shape({get:i().func,add:i().func,remove:i().func})}),Z="undefined"!=typeof document,H=function(e){function t(n){var r;return(r=e.call(this,n)||this).helmetData=new z(r.props.context,t.canUseDOM),r}return f(t,e),t.prototype.render=function(){return r.createElement(U.Provider,{value:this.helmetData.value},this.props.children)},t}(r.Component);H.canUseDOM=Z,H.propTypes={context:i().shape({helmet:i().shape()}),children:i().node.isRequired},H.defaultProps={context:{}},H.displayName="HelmetProvider";var V=function(e,t){var n,r=document.head||document.querySelector(g.HEAD),a=r.querySelectorAll(e+"[data-rh]"),i=[].slice.call(a),o=[];return t&&t.length&&t.forEach((function(t){var r=document.createElement(e);for(var a in t)Object.prototype.hasOwnProperty.call(t,a)&&("innerHTML"===a?r.innerHTML=t.innerHTML:"cssText"===a?r.styleSheet?r.styleSheet.cssText=t.cssText:r.appendChild(document.createTextNode(t.cssText)):r.setAttribute(a,void 0===t[a]?"":t[a]));r.setAttribute("data-rh","true"),i.some((function(e,t){return n=t,r.isEqualNode(e)}))?i.splice(n,1):o.push(r)})),i.forEach((function(e){return e.parentNode.removeChild(e)})),o.forEach((function(e){return r.appendChild(e)})),{oldTags:i,newTags:o}},W=function(e,t){var n=document.getElementsByTagName(e)[0];if(n){for(var r=n.getAttribute("data-rh"),a=r?r.split(","):[],i=[].concat(a),o=Object.keys(t),s=0;s<o.length;s+=1){var c=o[s],l=t[c]||"";n.getAttribute(c)!==l&&n.setAttribute(c,l),-1===a.indexOf(c)&&a.push(c);var u=i.indexOf(c);-1!==u&&i.splice(u,1)}for(var d=i.length-1;d>=0;d-=1)n.removeAttribute(i[d]);a.length===i.length?n.removeAttribute("data-rh"):n.getAttribute("data-rh")!==o.join(",")&&n.setAttribute("data-rh",o.join(","))}},G=function(e,t){var n=e.baseTag,r=e.htmlAttributes,a=e.linkTags,i=e.metaTags,o=e.noscriptTags,s=e.onChangeClientState,c=e.scriptTags,l=e.styleTags,u=e.title,d=e.titleAttributes;W(g.BODY,e.bodyAttributes),W(g.HTML,r),function(e,t){void 0!==e&&document.title!==e&&(document.title=N(e)),W(g.TITLE,t)}(u,d);var p={baseTag:V(g.BASE,n),linkTags:V(g.LINK,a),metaTags:V(g.META,i),noscriptTags:V(g.NOSCRIPT,o),scriptTags:V(g.SCRIPT,c),styleTags:V(g.STYLE,l)},f={},m={};Object.keys(p).forEach((function(e){var t=p[e],n=t.newTags,r=t.oldTags;n.length&&(f[e]=n),r.length&&(m[e]=p[e].oldTags)})),t&&t(),s(e,f,m)},Y=null,K=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(t=e.call.apply(e,[this].concat(r))||this).rendered=!1,t}f(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!d()(e,this.props)},n.componentDidUpdate=function(){this.emitChange()},n.componentWillUnmount=function(){this.props.context.helmetInstances.remove(this),this.emitChange()},n.emitChange=function(){var e,t,n=this.props.context,r=n.setHelmet,a=null,i=(e=n.helmetInstances.get().map((function(e){var t=p({},e.props);return delete t.context,t})),{baseTag:T(["href"],e),bodyAttributes:C("bodyAttributes",e),defer:k(e,"defer"),encode:k(e,"encodeSpecialCharacters"),htmlAttributes:C("htmlAttributes",e),linkTags:L(g.LINK,["rel","href"],e),metaTags:L(g.META,["name","charset","http-equiv","property","itemprop"],e),noscriptTags:L(g.NOSCRIPT,["innerHTML"],e),onChangeClientState:x(e),scriptTags:L(g.SCRIPT,["src","innerHTML"],e),styleTags:L(g.STYLE,["cssText"],e),title:E(e),titleAttributes:C("titleAttributes",e),prioritizeSeoTags:A(e,"prioritizeSeoTags")});H.canUseDOM?(t=i,Y&&cancelAnimationFrame(Y),t.defer?Y=requestAnimationFrame((function(){G(t,(function(){Y=null}))})):(G(t),Y=null)):j&&(a=j(i)),r(a)},n.init=function(){this.rendered||(this.rendered=!0,this.props.context.helmetInstances.add(this),this.emitChange())},n.render=function(){return this.init(),null},t}(r.Component);K.propTypes={context:q.isRequired},K.displayName="HelmetDispatcher";var X=["children"],Q=["children"],J=function(e){function t(){return e.apply(this,arguments)||this}f(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!s()(P(this.props,"helmetData"),P(e,"helmetData"))},n.mapNestedChildrenToProps=function(e,t){if(!t)return null;switch(e.type){case g.SCRIPT:case g.NOSCRIPT:return{innerHTML:t};case g.STYLE:return{cssText:t};default:throw new Error("<"+e.type+" /> elements are self-closing and can not contain children. Refer to our API for more information.")}},n.flattenArrayTypeChildren=function(e){var t,n=e.child,r=e.arrayTypeChildren;return p({},r,((t={})[n.type]=[].concat(r[n.type]||[],[p({},e.newChildProps,this.mapNestedChildrenToProps(n,e.nestedChildren))]),t))},n.mapObjectTypeChildren=function(e){var t,n,r=e.child,a=e.newProps,i=e.newChildProps,o=e.nestedChildren;switch(r.type){case g.TITLE:return p({},a,((t={})[r.type]=o,t.titleAttributes=p({},i),t));case g.BODY:return p({},a,{bodyAttributes:p({},i)});case g.HTML:return p({},a,{htmlAttributes:p({},i)});default:return p({},a,((n={})[r.type]=p({},i),n))}},n.mapArrayTypeChildrenToProps=function(e,t){var n=p({},t);return Object.keys(e).forEach((function(t){var r;n=p({},n,((r={})[t]=e[t],r))})),n},n.warnOnInvalidChildren=function(e,t){return l()(w.some((function(t){return e.type===t})),"function"==typeof e.type?"You may be attempting to nest <Helmet> components within each other, which is not allowed. Refer to our API for more information.":"Only elements types "+w.join(", ")+" are allowed. Helmet does not support rendering <"+e.type+"> elements. Refer to our API for more information."),l()(!t||"string"==typeof t||Array.isArray(t)&&!t.some((function(e){return"string"!=typeof e})),"Helmet expects a string as a child of <"+e.type+">. Did you forget to wrap your children in braces? ( <"+e.type+">{``}</"+e.type+"> ) Refer to our API for more information."),!0},n.mapChildrenToProps=function(e,t){var n=this,a={};return r.Children.forEach(e,(function(e){if(e&&e.props){var r=e.props,i=r.children,o=h(r,X),s=Object.keys(o).reduce((function(e,t){return e[S[t]||t]=o[t],e}),{}),c=e.type;switch("symbol"==typeof c?c=c.toString():n.warnOnInvalidChildren(e,i),c){case g.FRAGMENT:t=n.mapChildrenToProps(i,t);break;case g.LINK:case g.META:case g.NOSCRIPT:case g.SCRIPT:case g.STYLE:a=n.flattenArrayTypeChildren({child:e,arrayTypeChildren:a,newChildProps:s,nestedChildren:i});break;default:t=n.mapObjectTypeChildren({child:e,newProps:t,newChildProps:s,nestedChildren:i})}}})),this.mapArrayTypeChildrenToProps(a,t)},n.render=function(){var e=this.props,t=e.children,n=h(e,Q),a=p({},n),i=n.helmetData;return t&&(a=this.mapChildrenToProps(t,a)),!i||i instanceof z||(i=new z(i.context,i.instances)),i?r.createElement(K,p({},a,{context:i.value,helmetData:void 0})):r.createElement(U.Consumer,null,(function(e){return r.createElement(K,p({},a,{context:e}))}))},t}(r.Component);J.propTypes={base:i().object,bodyAttributes:i().object,children:i().oneOfType([i().arrayOf(i().node),i().node]),defaultTitle:i().string,defer:i().bool,encodeSpecialCharacters:i().bool,htmlAttributes:i().object,link:i().arrayOf(i().object),meta:i().arrayOf(i().object),noscript:i().arrayOf(i().object),onChangeClientState:i().func,script:i().arrayOf(i().object),style:i().arrayOf(i().object),title:i().string,titleAttributes:i().object,titleTemplate:i().string,prioritizeSeoTags:i().bool,helmetData:i().object},J.defaultProps={defer:!0,encodeSpecialCharacters:!0,prioritizeSeoTags:!1},J.displayName="Helmet"},9921:(e,t)=>{"use strict";var n="function"==typeof Symbol&&Symbol.for,r=n?Symbol.for("react.element"):60103,a=n?Symbol.for("react.portal"):60106,i=n?Symbol.for("react.fragment"):60107,o=n?Symbol.for("react.strict_mode"):60108,s=n?Symbol.for("react.profiler"):60114,c=n?Symbol.for("react.provider"):60109,l=n?Symbol.for("react.context"):60110,u=n?Symbol.for("react.async_mode"):60111,d=n?Symbol.for("react.concurrent_mode"):60111,p=n?Symbol.for("react.forward_ref"):60112,f=n?Symbol.for("react.suspense"):60113,m=n?Symbol.for("react.suspense_list"):60120,h=n?Symbol.for("react.memo"):60115,g=n?Symbol.for("react.lazy"):60116,v=n?Symbol.for("react.block"):60121,y=n?Symbol.for("react.fundamental"):60117,b=n?Symbol.for("react.responder"):60118,w=n?Symbol.for("react.scope"):60119;function _(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case r:switch(e=e.type){case u:case d:case i:case s:case o:case f:return e;default:switch(e=e&&e.$$typeof){case l:case p:case g:case h:case c:return e;default:return t}}case a:return t}}}function S(e){return _(e)===d}t.AsyncMode=u,t.ConcurrentMode=d,t.ContextConsumer=l,t.ContextProvider=c,t.Element=r,t.ForwardRef=p,t.Fragment=i,t.Lazy=g,t.Memo=h,t.Portal=a,t.Profiler=s,t.StrictMode=o,t.Suspense=f,t.isAsyncMode=function(e){return S(e)||_(e)===u},t.isConcurrentMode=S,t.isContextConsumer=function(e){return _(e)===l},t.isContextProvider=function(e){return _(e)===c},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===r},t.isForwardRef=function(e){return _(e)===p},t.isFragment=function(e){return _(e)===i},t.isLazy=function(e){return _(e)===g},t.isMemo=function(e){return _(e)===h},t.isPortal=function(e){return _(e)===a},t.isProfiler=function(e){return _(e)===s},t.isStrictMode=function(e){return _(e)===o},t.isSuspense=function(e){return _(e)===f},t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===i||e===d||e===s||e===o||e===f||e===m||"object"==typeof e&&null!==e&&(e.$$typeof===g||e.$$typeof===h||e.$$typeof===c||e.$$typeof===l||e.$$typeof===p||e.$$typeof===y||e.$$typeof===b||e.$$typeof===w||e.$$typeof===v)},t.typeOf=_},9864:(e,t,n)=>{"use strict";e.exports=n(9921)},8356:(e,t,n)=>{"use strict";function r(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}function a(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(){return o=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},o.apply(this,arguments)}var s=n(7294),c=n(5697),l=[],u=[];function d(e){var t=e(),n={loading:!0,loaded:null,error:null};return n.promise=t.then((function(e){return n.loading=!1,n.loaded=e,e})).catch((function(e){throw n.loading=!1,n.error=e,e})),n}function p(e){var t={loading:!1,loaded:{},error:null},n=[];try{Object.keys(e).forEach((function(r){var a=d(e[r]);a.loading?t.loading=!0:(t.loaded[r]=a.loaded,t.error=a.error),n.push(a.promise),a.promise.then((function(e){t.loaded[r]=e})).catch((function(e){t.error=e}))}))}catch(r){t.error=r}return t.promise=Promise.all(n).then((function(e){return t.loading=!1,e})).catch((function(e){throw t.loading=!1,e})),t}function f(e,t){return s.createElement((n=e)&&n.__esModule?n.default:n,t);var n}function m(e,t){var d,p;if(!t.loading)throw new Error("react-loadable requires a `loading` component");var m=o({loader:null,loading:null,delay:200,timeout:null,render:f,webpack:null,modules:null},t),h=null;function g(){return h||(h=e(m.loader)),h.promise}return l.push(g),"function"==typeof m.webpack&&u.push((function(){if((0,m.webpack)().every((function(e){return void 0!==e&&void 0!==n.m[e]})))return g()})),p=d=function(t){function n(n){var r;return i(a(a(r=t.call(this,n)||this)),"retry",(function(){r.setState({error:null,loading:!0,timedOut:!1}),h=e(m.loader),r._loadModule()})),g(),r.state={error:h.error,pastDelay:!1,timedOut:!1,loading:h.loading,loaded:h.loaded},r}r(n,t),n.preload=function(){return g()};var o=n.prototype;return o.UNSAFE_componentWillMount=function(){this._loadModule()},o.componentDidMount=function(){this._mounted=!0},o._loadModule=function(){var e=this;if(this.context.loadable&&Array.isArray(m.modules)&&m.modules.forEach((function(t){e.context.loadable.report(t)})),h.loading){var t=function(t){e._mounted&&e.setState(t)};"number"==typeof m.delay&&(0===m.delay?this.setState({pastDelay:!0}):this._delay=setTimeout((function(){t({pastDelay:!0})}),m.delay)),"number"==typeof m.timeout&&(this._timeout=setTimeout((function(){t({timedOut:!0})}),m.timeout));var n=function(){t({error:h.error,loaded:h.loaded,loading:h.loading}),e._clearTimeouts()};h.promise.then((function(){return n(),null})).catch((function(e){return n(),null}))}},o.componentWillUnmount=function(){this._mounted=!1,this._clearTimeouts()},o._clearTimeouts=function(){clearTimeout(this._delay),clearTimeout(this._timeout)},o.render=function(){return this.state.loading||this.state.error?s.createElement(m.loading,{isLoading:this.state.loading,pastDelay:this.state.pastDelay,timedOut:this.state.timedOut,error:this.state.error,retry:this.retry}):this.state.loaded?m.render(this.state.loaded,this.props):null},n}(s.Component),i(d,"contextTypes",{loadable:c.shape({report:c.func.isRequired})}),p}function h(e){return m(d,e)}h.Map=function(e){if("function"!=typeof e.render)throw new Error("LoadableMap requires a `render(loaded, props)` function");return m(p,e)};var g=function(e){function t(){return e.apply(this,arguments)||this}r(t,e);var n=t.prototype;return n.getChildContext=function(){return{loadable:{report:this.props.report}}},n.render=function(){return s.Children.only(this.props.children)},t}(s.Component);function v(e){for(var t=[];e.length;){var n=e.pop();t.push(n())}return Promise.all(t).then((function(){if(e.length)return v(e)}))}i(g,"propTypes",{report:c.func.isRequired}),i(g,"childContextTypes",{loadable:c.shape({report:c.func.isRequired}).isRequired}),h.Capture=g,h.preloadAll=function(){return new Promise((function(e,t){v(l).then(e,t)}))},h.preloadReady=function(){return new Promise((function(e,t){v(u).then(e,e)}))},e.exports=h},8790:(e,t,n)=>{"use strict";n.d(t,{H:()=>s,f:()=>o});var r=n(6550),a=n(7462),i=n(7294);function o(e,t,n){return void 0===n&&(n=[]),e.some((function(e){var a=e.path?(0,r.LX)(t,e):n.length?n[n.length-1].match:r.F0.computeRootMatch(t);return a&&(n.push({route:e,match:a}),e.routes&&o(e.routes,t,n)),a})),n}function s(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),e?i.createElement(r.rs,n,e.map((function(e,n){return i.createElement(r.AW,{key:e.key||n,path:e.path,exact:e.exact,strict:e.strict,render:function(n){return e.render?e.render((0,a.Z)({},n,{},t,{route:e})):i.createElement(e.component,(0,a.Z)({},n,t,{route:e}))}})}))):null}},3727:(e,t,n)=>{"use strict";n.d(t,{OL:()=>b,VK:()=>u,rU:()=>g});var r=n(6550),a=n(5068),i=n(7294),o=n(9318),s=n(7462),c=n(3366),l=n(8776),u=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(t=e.call.apply(e,[this].concat(r))||this).history=(0,o.lX)(t.props),t}return(0,a.Z)(t,e),t.prototype.render=function(){return i.createElement(r.F0,{history:this.history,children:this.props.children})},t}(i.Component);i.Component;var d=function(e,t){return"function"==typeof e?e(t):e},p=function(e,t){return"string"==typeof e?(0,o.ob)(e,null,null,t):e},f=function(e){return e},m=i.forwardRef;void 0===m&&(m=f);var h=m((function(e,t){var n=e.innerRef,r=e.navigate,a=e.onClick,o=(0,c.Z)(e,["innerRef","navigate","onClick"]),l=o.target,u=(0,s.Z)({},o,{onClick:function(e){try{a&&a(e)}catch(t){throw e.preventDefault(),t}e.defaultPrevented||0!==e.button||l&&"_self"!==l||function(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}(e)||(e.preventDefault(),r())}});return u.ref=f!==m&&t||n,i.createElement("a",u)}));var g=m((function(e,t){var n=e.component,a=void 0===n?h:n,u=e.replace,g=e.to,v=e.innerRef,y=(0,c.Z)(e,["component","replace","to","innerRef"]);return i.createElement(r.s6.Consumer,null,(function(e){e||(0,l.Z)(!1);var n=e.history,r=p(d(g,e.location),e.location),c=r?n.createHref(r):"",h=(0,s.Z)({},y,{href:c,navigate:function(){var t=d(g,e.location),r=(0,o.Ep)(e.location)===(0,o.Ep)(p(t));(u||r?n.replace:n.push)(t)}});return f!==m?h.ref=t||v:h.innerRef=v,i.createElement(a,h)}))})),v=function(e){return e},y=i.forwardRef;void 0===y&&(y=v);var b=y((function(e,t){var n=e["aria-current"],a=void 0===n?"page":n,o=e.activeClassName,u=void 0===o?"active":o,f=e.activeStyle,m=e.className,h=e.exact,b=e.isActive,w=e.location,_=e.sensitive,S=e.strict,k=e.style,E=e.to,x=e.innerRef,C=(0,c.Z)(e,["aria-current","activeClassName","activeStyle","className","exact","isActive","location","sensitive","strict","style","to","innerRef"]);return i.createElement(r.s6.Consumer,null,(function(e){e||(0,l.Z)(!1);var n=w||e.location,o=p(d(E,n),n),c=o.pathname,T=c&&c.replace(/([.+*?=^!:${}()[\]|/\\])/g,"\\$1"),L=T?(0,r.LX)(n.pathname,{path:T,exact:h,sensitive:_,strict:S}):null,A=!!(b?b(L,n):L),N="function"==typeof m?m(A):m,O="function"==typeof k?k(A):k;A&&(N=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.filter((function(e){return e})).join(" ")}(N,u),O=(0,s.Z)({},O,f));var P=(0,s.Z)({"aria-current":A&&a||null,className:N,style:O,to:o},C);return v!==y?P.ref=t||x:P.innerRef=x,i.createElement(g,P)}))}))},6550:(e,t,n)=>{"use strict";n.d(t,{AW:()=>E,F0:()=>b,LX:()=>k,TH:()=>I,k6:()=>P,rs:()=>N,s6:()=>y});var r=n(5068),a=n(7294),i=n(5697),o=n.n(i),s=n(9318),c=n(8776),l=n(7462),u=n(4779),d=n.n(u),p=(n(9864),n(3366)),f=(n(8679),1073741823),m="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==n.g?n.g:{};var h=a.createContext||function(e,t){var n,i,s="__create-react-context-"+function(){var e="__global_unique_id__";return m[e]=(m[e]||0)+1}()+"__",c=function(e){function n(){for(var t,n,r,a=arguments.length,i=new Array(a),o=0;o<a;o++)i[o]=arguments[o];return(t=e.call.apply(e,[this].concat(i))||this).emitter=(n=t.props.value,r=[],{on:function(e){r.push(e)},off:function(e){r=r.filter((function(t){return t!==e}))},get:function(){return n},set:function(e,t){n=e,r.forEach((function(e){return e(n,t)}))}}),t}(0,r.Z)(n,e);var a=n.prototype;return a.getChildContext=function(){var e;return(e={})[s]=this.emitter,e},a.componentWillReceiveProps=function(e){if(this.props.value!==e.value){var n,r=this.props.value,a=e.value;((i=r)===(o=a)?0!==i||1/i==1/o:i!=i&&o!=o)?n=0:(n="function"==typeof t?t(r,a):f,0!==(n|=0)&&this.emitter.set(e.value,n))}var i,o},a.render=function(){return this.props.children},n}(a.Component);c.childContextTypes=((n={})[s]=o().object.isRequired,n);var l=function(t){function n(){for(var e,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(e=t.call.apply(t,[this].concat(r))||this).observedBits=void 0,e.state={value:e.getValue()},e.onUpdate=function(t,n){0!=((0|e.observedBits)&n)&&e.setState({value:e.getValue()})},e}(0,r.Z)(n,t);var a=n.prototype;return a.componentWillReceiveProps=function(e){var t=e.observedBits;this.observedBits=null==t?f:t},a.componentDidMount=function(){this.context[s]&&this.context[s].on(this.onUpdate);var e=this.props.observedBits;this.observedBits=null==e?f:e},a.componentWillUnmount=function(){this.context[s]&&this.context[s].off(this.onUpdate)},a.getValue=function(){return this.context[s]?this.context[s].get():e},a.render=function(){return(e=this.props.children,Array.isArray(e)?e[0]:e)(this.state.value);var e},n}(a.Component);return l.contextTypes=((i={})[s]=o().object,i),{Provider:c,Consumer:l}},g=function(e){var t=h();return t.displayName=e,t},v=g("Router-History"),y=g("Router"),b=function(e){function t(t){var n;return(n=e.call(this,t)||this).state={location:t.history.location},n._isMounted=!1,n._pendingLocation=null,t.staticContext||(n.unlisten=t.history.listen((function(e){n._pendingLocation=e}))),n}(0,r.Z)(t,e),t.computeRootMatch=function(e){return{path:"/",url:"/",params:{},isExact:"/"===e}};var n=t.prototype;return n.componentDidMount=function(){var e=this;this._isMounted=!0,this.unlisten&&this.unlisten(),this.props.staticContext||(this.unlisten=this.props.history.listen((function(t){e._isMounted&&e.setState({location:t})}))),this._pendingLocation&&this.setState({location:this._pendingLocation})},n.componentWillUnmount=function(){this.unlisten&&(this.unlisten(),this._isMounted=!1,this._pendingLocation=null)},n.render=function(){return a.createElement(y.Provider,{value:{history:this.props.history,location:this.state.location,match:t.computeRootMatch(this.state.location.pathname),staticContext:this.props.staticContext}},a.createElement(v.Provider,{children:this.props.children||null,value:this.props.history}))},t}(a.Component);a.Component;a.Component;var w={},_=1e4,S=0;function k(e,t){void 0===t&&(t={}),("string"==typeof t||Array.isArray(t))&&(t={path:t});var n=t,r=n.path,a=n.exact,i=void 0!==a&&a,o=n.strict,s=void 0!==o&&o,c=n.sensitive,l=void 0!==c&&c;return[].concat(r).reduce((function(t,n){if(!n&&""!==n)return null;if(t)return t;var r=function(e,t){var n=""+t.end+t.strict+t.sensitive,r=w[n]||(w[n]={});if(r[e])return r[e];var a=[],i={regexp:d()(e,a,t),keys:a};return S<_&&(r[e]=i,S++),i}(n,{end:i,strict:s,sensitive:l}),a=r.regexp,o=r.keys,c=a.exec(e);if(!c)return null;var u=c[0],p=c.slice(1),f=e===u;return i&&!f?null:{path:n,url:"/"===n&&""===u?"/":u,isExact:f,params:o.reduce((function(e,t,n){return e[t.name]=p[n],e}),{})}}),null)}var E=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.Z)(t,e),t.prototype.render=function(){var e=this;return a.createElement(y.Consumer,null,(function(t){t||(0,c.Z)(!1);var n=e.props.location||t.location,r=e.props.computedMatch?e.props.computedMatch:e.props.path?k(n.pathname,e.props):t.match,i=(0,l.Z)({},t,{location:n,match:r}),o=e.props,s=o.children,u=o.component,d=o.render;return Array.isArray(s)&&function(e){return 0===a.Children.count(e)}(s)&&(s=null),a.createElement(y.Provider,{value:i},i.match?s?"function"==typeof s?s(i):s:u?a.createElement(u,i):d?d(i):null:"function"==typeof s?s(i):null)}))},t}(a.Component);function x(e){return"/"===e.charAt(0)?e:"/"+e}function C(e,t){if(!e)return t;var n=x(e);return 0!==t.pathname.indexOf(n)?t:(0,l.Z)({},t,{pathname:t.pathname.substr(n.length)})}function T(e){return"string"==typeof e?e:(0,s.Ep)(e)}function L(e){return function(){(0,c.Z)(!1)}}function A(){}a.Component;var N=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.Z)(t,e),t.prototype.render=function(){var e=this;return a.createElement(y.Consumer,null,(function(t){t||(0,c.Z)(!1);var n,r,i=e.props.location||t.location;return a.Children.forEach(e.props.children,(function(e){if(null==r&&a.isValidElement(e)){n=e;var o=e.props.path||e.props.from;r=o?k(i.pathname,(0,l.Z)({},e.props,{path:o})):t.match}})),r?a.cloneElement(n,{location:i,computedMatch:r}):null}))},t}(a.Component);var O=a.useContext;function P(){return O(v)}function I(){return O(y).location}},2408:(e,t,n)=>{"use strict";var r=n(7418),a=60103,i=60106;t.Fragment=60107,t.StrictMode=60108,t.Profiler=60114;var o=60109,s=60110,c=60112;t.Suspense=60113;var l=60115,u=60116;if("function"==typeof Symbol&&Symbol.for){var d=Symbol.for;a=d("react.element"),i=d("react.portal"),t.Fragment=d("react.fragment"),t.StrictMode=d("react.strict_mode"),t.Profiler=d("react.profiler"),o=d("react.provider"),s=d("react.context"),c=d("react.forward_ref"),t.Suspense=d("react.suspense"),l=d("react.memo"),u=d("react.lazy")}var p="function"==typeof Symbol&&Symbol.iterator;function f(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var m={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},h={};function g(e,t,n){this.props=e,this.context=t,this.refs=h,this.updater=n||m}function v(){}function y(e,t,n){this.props=e,this.context=t,this.refs=h,this.updater=n||m}g.prototype.isReactComponent={},g.prototype.setState=function(e,t){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error(f(85));this.updater.enqueueSetState(this,e,t,"setState")},g.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},v.prototype=g.prototype;var b=y.prototype=new v;b.constructor=y,r(b,g.prototype),b.isPureReactComponent=!0;var w={current:null},_=Object.prototype.hasOwnProperty,S={key:!0,ref:!0,__self:!0,__source:!0};function k(e,t,n){var r,i={},o=null,s=null;if(null!=t)for(r in void 0!==t.ref&&(s=t.ref),void 0!==t.key&&(o=""+t.key),t)_.call(t,r)&&!S.hasOwnProperty(r)&&(i[r]=t[r]);var c=arguments.length-2;if(1===c)i.children=n;else if(1<c){for(var l=Array(c),u=0;u<c;u++)l[u]=arguments[u+2];i.children=l}if(e&&e.defaultProps)for(r in c=e.defaultProps)void 0===i[r]&&(i[r]=c[r]);return{$$typeof:a,type:e,key:o,ref:s,props:i,_owner:w.current}}function E(e){return"object"==typeof e&&null!==e&&e.$$typeof===a}var x=/\/+/g;function C(e,t){return"object"==typeof e&&null!==e&&null!=e.key?function(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,(function(e){return t[e]}))}(""+e.key):t.toString(36)}function T(e,t,n,r,o){var s=typeof e;"undefined"!==s&&"boolean"!==s||(e=null);var c=!1;if(null===e)c=!0;else switch(s){case"string":case"number":c=!0;break;case"object":switch(e.$$typeof){case a:case i:c=!0}}if(c)return o=o(c=e),e=""===r?"."+C(c,0):r,Array.isArray(o)?(n="",null!=e&&(n=e.replace(x,"$&/")+"/"),T(o,t,n,"",(function(e){return e}))):null!=o&&(E(o)&&(o=function(e,t){return{$$typeof:a,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}(o,n+(!o.key||c&&c.key===o.key?"":(""+o.key).replace(x,"$&/")+"/")+e)),t.push(o)),1;if(c=0,r=""===r?".":r+":",Array.isArray(e))for(var l=0;l<e.length;l++){var u=r+C(s=e[l],l);c+=T(s,t,n,u,o)}else if(u=function(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=p&&e[p]||e["@@iterator"])?e:null}(e),"function"==typeof u)for(e=u.call(e),l=0;!(s=e.next()).done;)c+=T(s=s.value,t,n,u=r+C(s,l++),o);else if("object"===s)throw t=""+e,Error(f(31,"[object Object]"===t?"object with keys {"+Object.keys(e).join(", ")+"}":t));return c}function L(e,t,n){if(null==e)return e;var r=[],a=0;return T(e,r,"","",(function(e){return t.call(n,e,a++)})),r}function A(e){if(-1===e._status){var t=e._result;t=t(),e._status=0,e._result=t,t.then((function(t){0===e._status&&(t=t.default,e._status=1,e._result=t)}),(function(t){0===e._status&&(e._status=2,e._result=t)}))}if(1===e._status)return e._result;throw e._result}var N={current:null};function O(){var e=N.current;if(null===e)throw Error(f(321));return e}var P={ReactCurrentDispatcher:N,ReactCurrentBatchConfig:{transition:0},ReactCurrentOwner:w,IsSomeRendererActing:{current:!1},assign:r};t.Children={map:L,forEach:function(e,t,n){L(e,(function(){t.apply(this,arguments)}),n)},count:function(e){var t=0;return L(e,(function(){t++})),t},toArray:function(e){return L(e,(function(e){return e}))||[]},only:function(e){if(!E(e))throw Error(f(143));return e}},t.Component=g,t.PureComponent=y,t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=P,t.cloneElement=function(e,t,n){if(null==e)throw Error(f(267,e));var i=r({},e.props),o=e.key,s=e.ref,c=e._owner;if(null!=t){if(void 0!==t.ref&&(s=t.ref,c=w.current),void 0!==t.key&&(o=""+t.key),e.type&&e.type.defaultProps)var l=e.type.defaultProps;for(u in t)_.call(t,u)&&!S.hasOwnProperty(u)&&(i[u]=void 0===t[u]&&void 0!==l?l[u]:t[u])}var u=arguments.length-2;if(1===u)i.children=n;else if(1<u){l=Array(u);for(var d=0;d<u;d++)l[d]=arguments[d+2];i.children=l}return{$$typeof:a,type:e.type,key:o,ref:s,props:i,_owner:c}},t.createContext=function(e,t){return void 0===t&&(t=null),(e={$$typeof:s,_calculateChangedBits:t,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null}).Provider={$$typeof:o,_context:e},e.Consumer=e},t.createElement=k,t.createFactory=function(e){var t=k.bind(null,e);return t.type=e,t},t.createRef=function(){return{current:null}},t.forwardRef=function(e){return{$$typeof:c,render:e}},t.isValidElement=E,t.lazy=function(e){return{$$typeof:u,_payload:{_status:-1,_result:e},_init:A}},t.memo=function(e,t){return{$$typeof:l,type:e,compare:void 0===t?null:t}},t.useCallback=function(e,t){return O().useCallback(e,t)},t.useContext=function(e,t){return O().useContext(e,t)},t.useDebugValue=function(){},t.useEffect=function(e,t){return O().useEffect(e,t)},t.useImperativeHandle=function(e,t,n){return O().useImperativeHandle(e,t,n)},t.useLayoutEffect=function(e,t){return O().useLayoutEffect(e,t)},t.useMemo=function(e,t){return O().useMemo(e,t)},t.useReducer=function(e,t,n){return O().useReducer(e,t,n)},t.useRef=function(e){return O().useRef(e)},t.useState=function(e){return O().useState(e)},t.version="17.0.2"},7294:(e,t,n)=>{"use strict";e.exports=n(2408)},53:(e,t)=>{"use strict";var n,r,a,i;if("object"==typeof performance&&"function"==typeof performance.now){var o=performance;t.unstable_now=function(){return o.now()}}else{var s=Date,c=s.now();t.unstable_now=function(){return s.now()-c}}if("undefined"==typeof window||"function"!=typeof MessageChannel){var l=null,u=null,d=function(){if(null!==l)try{var e=t.unstable_now();l(!0,e),l=null}catch(n){throw setTimeout(d,0),n}};n=function(e){null!==l?setTimeout(n,0,e):(l=e,setTimeout(d,0))},r=function(e,t){u=setTimeout(e,t)},a=function(){clearTimeout(u)},t.unstable_shouldYield=function(){return!1},i=t.unstable_forceFrameRate=function(){}}else{var p=window.setTimeout,f=window.clearTimeout;if("undefined"!=typeof console){var m=window.cancelAnimationFrame;"function"!=typeof window.requestAnimationFrame&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills"),"function"!=typeof m&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills")}var h=!1,g=null,v=-1,y=5,b=0;t.unstable_shouldYield=function(){return t.unstable_now()>=b},i=function(){},t.unstable_forceFrameRate=function(e){0>e||125<e?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):y=0<e?Math.floor(1e3/e):5};var w=new MessageChannel,_=w.port2;w.port1.onmessage=function(){if(null!==g){var e=t.unstable_now();b=e+y;try{g(!0,e)?_.postMessage(null):(h=!1,g=null)}catch(n){throw _.postMessage(null),n}}else h=!1},n=function(e){g=e,h||(h=!0,_.postMessage(null))},r=function(e,n){v=p((function(){e(t.unstable_now())}),n)},a=function(){f(v),v=-1}}function S(e,t){var n=e.length;e.push(t);e:for(;;){var r=n-1>>>1,a=e[r];if(!(void 0!==a&&0<x(a,t)))break e;e[r]=t,e[n]=a,n=r}}function k(e){return void 0===(e=e[0])?null:e}function E(e){var t=e[0];if(void 0!==t){var n=e.pop();if(n!==t){e[0]=n;e:for(var r=0,a=e.length;r<a;){var i=2*(r+1)-1,o=e[i],s=i+1,c=e[s];if(void 0!==o&&0>x(o,n))void 0!==c&&0>x(c,o)?(e[r]=c,e[s]=n,r=s):(e[r]=o,e[i]=n,r=i);else{if(!(void 0!==c&&0>x(c,n)))break e;e[r]=c,e[s]=n,r=s}}}return t}return null}function x(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var C=[],T=[],L=1,A=null,N=3,O=!1,P=!1,I=!1;function R(e){for(var t=k(T);null!==t;){if(null===t.callback)E(T);else{if(!(t.startTime<=e))break;E(T),t.sortIndex=t.expirationTime,S(C,t)}t=k(T)}}function M(e){if(I=!1,R(e),!P)if(null!==k(C))P=!0,n(D);else{var t=k(T);null!==t&&r(M,t.startTime-e)}}function D(e,n){P=!1,I&&(I=!1,a()),O=!0;var i=N;try{for(R(n),A=k(C);null!==A&&(!(A.expirationTime>n)||e&&!t.unstable_shouldYield());){var o=A.callback;if("function"==typeof o){A.callback=null,N=A.priorityLevel;var s=o(A.expirationTime<=n);n=t.unstable_now(),"function"==typeof s?A.callback=s:A===k(C)&&E(C),R(n)}else E(C);A=k(C)}if(null!==A)var c=!0;else{var l=k(T);null!==l&&r(M,l.startTime-n),c=!1}return c}finally{A=null,N=i,O=!1}}var F=i;t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_continueExecution=function(){P||O||(P=!0,n(D))},t.unstable_getCurrentPriorityLevel=function(){return N},t.unstable_getFirstCallbackNode=function(){return k(C)},t.unstable_next=function(e){switch(N){case 1:case 2:case 3:var t=3;break;default:t=N}var n=N;N=t;try{return e()}finally{N=n}},t.unstable_pauseExecution=function(){},t.unstable_requestPaint=F,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=N;N=e;try{return t()}finally{N=n}},t.unstable_scheduleCallback=function(e,i,o){var s=t.unstable_now();switch("object"==typeof o&&null!==o?o="number"==typeof(o=o.delay)&&0<o?s+o:s:o=s,e){case 1:var c=-1;break;case 2:c=250;break;case 5:c=1073741823;break;case 4:c=1e4;break;default:c=5e3}return e={id:L++,callback:i,priorityLevel:e,startTime:o,expirationTime:c=o+c,sortIndex:-1},o>s?(e.sortIndex=o,S(T,e),null===k(C)&&e===k(T)&&(I?a():I=!0,r(M,o-s))):(e.sortIndex=c,S(C,e),P||O||(P=!0,n(D))),e},t.unstable_wrapCallback=function(e){var t=N;return function(){var n=N;N=t;try{return e.apply(this,arguments)}finally{N=n}}}},3840:(e,t,n)=>{"use strict";e.exports=n(53)},6774:e=>{e.exports=function(e,t,n,r){var a=n?n.call(r,e,t):void 0;if(void 0!==a)return!!a;if(e===t)return!0;if("object"!=typeof e||!e||"object"!=typeof t||!t)return!1;var i=Object.keys(e),o=Object.keys(t);if(i.length!==o.length)return!1;for(var s=Object.prototype.hasOwnProperty.bind(t),c=0;c<i.length;c++){var l=i[c];if(!s(l))return!1;var u=e[l],d=t[l];if(!1===(a=n?n.call(r,u,d,l):void 0)||void 0===a&&u!==d)return!1}return!0}},3250:(e,t,n)=>{"use strict";var r=n(7294);var a="function"==typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t},i=r.useState,o=r.useEffect,s=r.useLayoutEffect,c=r.useDebugValue;function l(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!a(e,n)}catch(r){return!0}}var u="undefined"==typeof window||void 0===window.document||void 0===window.document.createElement?function(e,t){return t()}:function(e,t){var n=t(),r=i({inst:{value:n,getSnapshot:t}}),a=r[0].inst,u=r[1];return s((function(){a.value=n,a.getSnapshot=t,l(a)&&u({inst:a})}),[e,n,t]),o((function(){return l(a)&&u({inst:a}),e((function(){l(a)&&u({inst:a})}))}),[e]),c(n),n};void 0!==r.useSyncExternalStore&&r.useSyncExternalStore},1688:(e,t,n)=>{"use strict";n(3250)},6809:(e,t,n)=>{"use strict";n.d(t,{Z:()=>r});const r={title:"Interchain Security",tagline:"Interchain Security is a project to build a security layer for the Cosmos ecosystem.",url:"https://cosmos.github.io",baseUrl:"/interchain-security/legacy/",onBrokenLinks:"warn",onBrokenMarkdownLinks:"warn",favicon:"img/favicon.svg",trailingSlash:!1,organizationName:"cosmos",projectName:"interchain-security",i18n:{defaultLocale:"en",locales:["en"],path:"i18n",localeConfigs:{}},presets:[["classic",{docs:{sidebarPath:"/Users/msalopek/informal/interchain-security/docs/sidebars.js",routeBasePath:"/",versions:{current:{path:"/"}}},theme:{customCss:"/Users/msalopek/informal/interchain-security/docs/src/css/custom.css"}}]],themeConfig:{image:"img/banner.jpg",docs:{sidebar:{autoCollapseCategories:!0,hideable:!1},versionPersistence:"localStorage"},colorMode:{defaultMode:"dark",disableSwitch:!0,respectPrefersColorScheme:!1},navbar:{title:"Interchain Security",hideOnScroll:!1,items:[{href:"https://github.com/cosmos/interchain-security",html:'<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="github-icon">\n <path fill-rule="evenodd" clip-rule="evenodd" d="M12 0.300049C5.4 0.300049 0 5.70005 0 12.3001C0 17.6001 3.4 22.1001 8.2 23.7001C8.8 23.8001 9 23.4001 9 23.1001C9 22.8001 9 22.1001 9 21.1001C5.7 21.8001 5 19.5001 5 19.5001C4.5 18.1001 3.7 17.7001 3.7 17.7001C2.5 17.0001 3.7 17.0001 3.7 17.0001C4.9 17.1001 5.5 18.2001 5.5 18.2001C6.6 20.0001 8.3 19.5001 9 19.2001C9.1 18.4001 9.4 17.9001 9.8 17.6001C7.1 17.3001 4.3 16.3001 4.3 11.7001C4.3 10.4001 4.8 9.30005 5.5 8.50005C5.5 8.10005 5 6.90005 5.7 5.30005C5.7 5.30005 6.7 5.00005 9 6.50005C10 6.20005 11 6.10005 12 6.10005C13 6.10005 14 6.20005 15 6.50005C17.3 4.90005 18.3 5.30005 18.3 5.30005C19 7.00005 18.5 8.20005 18.4 8.50005C19.2 9.30005 19.6 10.4001 19.6 11.7001C19.6 16.3001 16.8 17.3001 14.1 17.6001C14.5 18.0001 14.9 18.7001 14.9 19.8001C14.9 21.4001 14.9 22.7001 14.9 23.1001C14.9 23.4001 15.1 23.8001 15.7 23.7001C20.5 22.1001 23.9 17.6001 23.9 12.3001C24 5.70005 18.6 0.300049 12 0.300049Z" fill="currentColor"/>\n </svg>\n ',position:"right"},{type:"docsVersionDropdown",position:"left",dropdownActiveClassDisabled:!1,dropdownItemsBefore:[],dropdownItemsAfter:[]}]},footer:{links:[{items:[{html:'<a href="https://cosmos.network"><img src="/img/logo-bw.svg" alt="Cosmos Logo"></a>'}],title:null},{title:"Documentation",items:[{label:"Cosmos Hub",href:"https://hub.cosmos.network"},{label:"Cosmos SDK",href:"https://docs.cosmos.network"},{label:"Tendermint Core",href:"https://docs.tendermint.com"},{label:"IBC Go",href:"https://ibc.cosmos.network"}]},{title:"Community",items:[{label:"Blog",href:"https://blog.cosmos.network"},{label:"Forum",href:"https://forum.cosmos.network"},{label:"Discord",href:"https://discord.gg/cosmosnetwork"},{label:"Reddit",href:"https://reddit.com/r/cosmosnetwork"}]},{title:"Social",items:[{label:"Discord",href:"https://discord.gg/cosmosnetwork"},{label:"Twitter",href:"https://twitter.com/cosmos"},{label:"Youtube",href:"https://www.youtube.com/c/CosmosProject"},{label:"Telegram",href:"https://t.me/cosmosproject"}]}],copyright:"Informal Systems",style:"light"},prism:{theme:{plain:{color:"#393A34",backgroundColor:"#f6f8fa"},styles:[{types:["comment","prolog","doctype","cdata"],style:{color:"#999988",fontStyle:"italic"}},{types:["namespace"],style:{opacity:.7}},{types:["string","attr-value"],style:{color:"#e3116c"}},{types:["punctuation","operator"],style:{color:"#393A34"}},{types:["entity","url","symbol","number","boolean","variable","constant","property","regex","inserted"],style:{color:"#36acaa"}},{types:["atrule","keyword","attr-name","selector"],style:{color:"#00a4db"}},{types:["function","deleted","tag"],style:{color:"#d73a49"}},{types:["function-variable"],style:{color:"#6f42c1"}},{types:["tag","selector","keyword"],style:{color:"#00009f"}}]},darkTheme:{plain:{color:"#F8F8F2",backgroundColor:"#282A36"},styles:[{types:["prolog","constant","builtin"],style:{color:"rgb(189, 147, 249)"}},{types:["inserted","function"],style:{color:"rgb(80, 250, 123)"}},{types:["deleted"],style:{color:"rgb(255, 85, 85)"}},{types:["changed"],style:{color:"rgb(255, 184, 108)"}},{types:["punctuation","symbol"],style:{color:"rgb(248, 248, 242)"}},{types:["string","char","tag","selector"],style:{color:"rgb(255, 121, 198)"}},{types:["keyword","variable"],style:{color:"rgb(189, 147, 249)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(98, 114, 164)"}},{types:["attr-name"],style:{color:"rgb(241, 250, 140)"}}]},additionalLanguages:["protobuf","go-module"],magicComments:[{className:"theme-code-block-highlighted-line",line:"highlight-next-line",block:{start:"highlight-start",end:"highlight-end"}}]},metadata:[],tableOfContents:{minHeadingLevel:2,maxHeadingLevel:3}},themes:["@you54f/theme-github-codeblock"],plugins:[null,["@docusaurus/plugin-client-redirects",{fromExtensions:["html"],toExtensions:["html"],redirects:[{from:["/main"],to:"/"}]}]],baseUrlIssueBanner:!0,onDuplicateRoutes:"warn",staticDirectories:["static"],customFields:{},scripts:[],headTags:[],stylesheets:[],clientModules:[],titleDelimiter:"|",noIndex:!1,markdown:{mermaid:!1}}},7462:(e,t,n)=>{"use strict";function r(){return r=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},r.apply(this,arguments)}n.d(t,{Z:()=>r})},5068:(e,t,n)=>{"use strict";function r(e,t){return r=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},r(e,t)}function a(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,r(e,t)}n.d(t,{Z:()=>a})},3366:(e,t,n)=>{"use strict";function r(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}n.d(t,{Z:()=>r})},8776:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=!0,a="Invariant failed";function i(e,t){if(!e){if(r)throw new Error(a);var n="function"==typeof t?t():t,i=n?"".concat(a,": ").concat(n):a;throw new Error(i)}}},7529:e=>{"use strict";e.exports={}},6887:e=>{"use strict";e.exports=JSON.parse('{"/interchain-security/legacy/v2.0.0-1ff":{"__comp":"1be78505","__context":{"plugin":"32783f50"},"versionMetadata":"07a13505"},"/interchain-security/legacy/v2.0.0-623":{"__comp":"17896441","content":"05354274"},"/interchain-security/legacy/v2.0.0/adrs/adr-001-key-assignment-941":{"__comp":"17896441","content":"1560cd4f"},"/interchain-security/legacy/v2.0.0/adrs/adr-002-throttle-91d":{"__comp":"17896441","content":"d67a6454"},"/interchain-security/legacy/v2.0.0/adrs/adr-003-equivocation-gov-proposal-f38":{"__comp":"17896441","content":"6441912e"},"/interchain-security/legacy/v2.0.0/adrs/adr-template-089":{"__comp":"17896441","content":"b1ce16c0"},"/interchain-security/legacy/v2.0.0/adrs/intro-583":{"__comp":"17896441","content":"b9eeacc5"},"/interchain-security/legacy/v2.0.0/consumer-development/app-integration-5b5":{"__comp":"17896441","content":"7c1fc285"},"/interchain-security/legacy/v2.0.0/consumer-development/consumer-chain-governance-5d8":{"__comp":"17896441","content":"3e7b8ec9"},"/interchain-security/legacy/v2.0.0/consumer-development/consumer-chain-upgrade-procedure-a22":{"__comp":"17896441","content":"11e17b14"},"/interchain-security/legacy/v2.0.0/consumer-development/offboarding-b91":{"__comp":"17896441","content":"db091dad"},"/interchain-security/legacy/v2.0.0/consumer-development/onboarding-986":{"__comp":"17896441","content":"04f38623"},"/interchain-security/legacy/v2.0.0/faq-be2":{"__comp":"17896441","content":"1a276578"},"/interchain-security/legacy/v2.0.0/features/key-assignment-188":{"__comp":"17896441","content":"811ce3c2"},"/interchain-security/legacy/v2.0.0/features/proposals-61c":{"__comp":"17896441","content":"81762141"},"/interchain-security/legacy/v2.0.0/features/reward-distribution-957":{"__comp":"17896441","content":"f249e987"},"/interchain-security/legacy/v2.0.0/features/slashing-cfe":{"__comp":"17896441","content":"d411b146"},"/interchain-security/legacy/v2.0.0/introduction/overview-a87":{"__comp":"17896441","content":"fe5d7ad2"},"/interchain-security/legacy/v2.0.0/introduction/params-30e":{"__comp":"17896441","content":"6a7358b5"},"/interchain-security/legacy/v2.0.0/introduction/technical-specification-413":{"__comp":"17896441","content":"4c855390"},"/interchain-security/legacy/v2.0.0/introduction/terminology-3cf":{"__comp":"17896441","content":"5f35bbec"},"/interchain-security/legacy/v2.0.0/validators/joining-testnet-2d2":{"__comp":"17896441","content":"9b3ea85c"},"/interchain-security/legacy/v2.0.0/validators/overview-c31":{"__comp":"17896441","content":"e23b6b4c"},"/interchain-security/legacy/v2.0.0/validators/withdraw_rewards-eff":{"__comp":"17896441","content":"8fb9dc62"},"/interchain-security/legacy/v2.4.0-lsm-1b8":{"__comp":"1be78505","__context":{"plugin":"32783f50"},"versionMetadata":"6c7cd03d"},"/interchain-security/legacy/v2.4.0-lsm-9bc":{"__comp":"17896441","content":"e1611597"},"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-001-key-assignment-c87":{"__comp":"17896441","content":"fc1c61d3"},"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-002-throttle-c8b":{"__comp":"17896441","content":"dca8d7c6"},"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposal-dcc":{"__comp":"17896441","content":"3299f073"},"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verification-be7":{"__comp":"17896441","content":"4b0243dd"},"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-013-equivocation-slashing-411":{"__comp":"17896441","content":"ff887390"},"/interchain-security/legacy/v2.4.0-lsm/adrs/adr-template-03e":{"__comp":"17896441","content":"1d3f4228"},"/interchain-security/legacy/v2.4.0-lsm/adrs/intro-58f":{"__comp":"17896441","content":"7a380eb1"},"/interchain-security/legacy/v2.4.0-lsm/consumer-development/app-integration-af1":{"__comp":"17896441","content":"07e666cb"},"/interchain-security/legacy/v2.4.0-lsm/consumer-development/consumer-chain-governance-be1":{"__comp":"17896441","content":"65076e0d"},"/interchain-security/legacy/v2.4.0-lsm/consumer-development/consumer-chain-upgrade-procedure-925":{"__comp":"17896441","content":"bc17315d"},"/interchain-security/legacy/v2.4.0-lsm/consumer-development/offboarding-052":{"__comp":"17896441","content":"ff39e481"},"/interchain-security/legacy/v2.4.0-lsm/consumer-development/onboarding-ff4":{"__comp":"17896441","content":"d88536eb"},"/interchain-security/legacy/v2.4.0-lsm/faq-9e7":{"__comp":"17896441","content":"8565b213"},"/interchain-security/legacy/v2.4.0-lsm/features/key-assignment-f8a":{"__comp":"17896441","content":"f8317958"},"/interchain-security/legacy/v2.4.0-lsm/features/proposals-7c0":{"__comp":"17896441","content":"1bdc04ff"},"/interchain-security/legacy/v2.4.0-lsm/features/reward-distribution-05f":{"__comp":"17896441","content":"d63ae50e"},"/interchain-security/legacy/v2.4.0-lsm/features/slashing-855":{"__comp":"17896441","content":"25dc14a6"},"/interchain-security/legacy/v2.4.0-lsm/introduction/overview-6ed":{"__comp":"17896441","content":"1ca03be8"},"/interchain-security/legacy/v2.4.0-lsm/introduction/params-e14":{"__comp":"17896441","content":"c57e97ca"},"/interchain-security/legacy/v2.4.0-lsm/introduction/technical-specification-2a0":{"__comp":"17896441","content":"d4f67fc8"},"/interchain-security/legacy/v2.4.0-lsm/introduction/terminology-e9b":{"__comp":"17896441","content":"2ee035c9"},"/interchain-security/legacy/v2.4.0-lsm/validators/joining-testnet-70b":{"__comp":"17896441","content":"4cc37eaf"},"/interchain-security/legacy/v2.4.0-lsm/validators/overview-c17":{"__comp":"17896441","content":"b74a2173"},"/interchain-security/legacy/v2.4.0-lsm/validators/withdraw_rewards-e41":{"__comp":"17896441","content":"29f8b3e7"},"/interchain-security/legacy/v3.1.0-e82":{"__comp":"1be78505","__context":{"plugin":"32783f50"},"versionMetadata":"9b050cce"},"/interchain-security/legacy/v3.1.0-905":{"__comp":"17896441","content":"ee6b1b56"},"/interchain-security/legacy/v3.1.0/adrs/adr-001-key-assignment-138":{"__comp":"17896441","content":"44efc911"},"/interchain-security/legacy/v3.1.0/adrs/adr-002-throttle-391":{"__comp":"17896441","content":"eb02ef83"},"/interchain-security/legacy/v3.1.0/adrs/adr-003-equivocation-gov-proposal-593":{"__comp":"17896441","content":"ebdc1949"},"/interchain-security/legacy/v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-prop-3af":{"__comp":"17896441","content":"14ce44a3"},"/interchain-security/legacy/v3.1.0/adrs/adr-008-throttle-retries-029":{"__comp":"17896441","content":"bc700a7c"},"/interchain-security/legacy/v3.1.0/adrs/adr-009-soft-opt-out-65e":{"__comp":"17896441","content":"08757149"},"/interchain-security/legacy/v3.1.0/adrs/adr-template-d1f":{"__comp":"17896441","content":"67f96001"},"/interchain-security/legacy/v3.1.0/adrs/intro-727":{"__comp":"17896441","content":"d73929d1"},"/interchain-security/legacy/v3.1.0/consumer-development/app-integration-c88":{"__comp":"17896441","content":"4c058ddf"},"/interchain-security/legacy/v3.1.0/consumer-development/consumer-chain-governance-cad":{"__comp":"17896441","content":"c2da6a7e"},"/interchain-security/legacy/v3.1.0/consumer-development/consumer-chain-upgrade-procedure-064":{"__comp":"17896441","content":"b4bb90a1"},"/interchain-security/legacy/v3.1.0/consumer-development/offboarding-d07":{"__comp":"17896441","content":"afe2e479"},"/interchain-security/legacy/v3.1.0/consumer-development/onboarding-b9c":{"__comp":"17896441","content":"57c82761"},"/interchain-security/legacy/v3.1.0/faq-659":{"__comp":"17896441","content":"3a65a150"},"/interchain-security/legacy/v3.1.0/features/key-assignment-003":{"__comp":"17896441","content":"1bcdc660"},"/interchain-security/legacy/v3.1.0/features/proposals-ee4":{"__comp":"17896441","content":"c99bfd69"},"/interchain-security/legacy/v3.1.0/features/reward-distribution-34c":{"__comp":"17896441","content":"fbda1364"},"/interchain-security/legacy/v3.1.0/features/slashing-320":{"__comp":"17896441","content":"d262fdd7"},"/interchain-security/legacy/v3.1.0/introduction/overview-b7f":{"__comp":"17896441","content":"ffd4165d"},"/interchain-security/legacy/v3.1.0/introduction/params-bb2":{"__comp":"17896441","content":"aede9d74"},"/interchain-security/legacy/v3.1.0/introduction/technical-specification-311":{"__comp":"17896441","content":"1a009efd"},"/interchain-security/legacy/v3.1.0/introduction/terminology-ed9":{"__comp":"17896441","content":"84bd924c"},"/interchain-security/legacy/v3.1.0/validators/joining-testnet-b27":{"__comp":"17896441","content":"2eef71dd"},"/interchain-security/legacy/v3.1.0/validators/overview-900":{"__comp":"17896441","content":"875b184f"},"/interchain-security/legacy/v3.1.0/validators/withdraw_rewards-12e":{"__comp":"17896441","content":"bb11f0e8"},"/interchain-security/legacy/v3.2.0-c46":{"__comp":"1be78505","__context":{"plugin":"32783f50"},"versionMetadata":"b2effb50"},"/interchain-security/legacy/v3.2.0-640":{"__comp":"17896441","content":"f0becab0"},"/interchain-security/legacy/v3.2.0/adrs/adr-001-key-assignment-464":{"__comp":"17896441","content":"bb7b1385"},"/interchain-security/legacy/v3.2.0/adrs/adr-002-throttle-0cb":{"__comp":"17896441","content":"3739a4c2"},"/interchain-security/legacy/v3.2.0/adrs/adr-003-equivocation-gov-proposal-512":{"__comp":"17896441","content":"1f0eef20"},"/interchain-security/legacy/v3.2.0/adrs/adr-005-cryptographic-equivocation-verification-f41":{"__comp":"17896441","content":"dd2dc399"},"/interchain-security/legacy/v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop-51d":{"__comp":"17896441","content":"01ff7a4e"},"/interchain-security/legacy/v3.2.0/adrs/adr-008-throttle-retries-885":{"__comp":"17896441","content":"c566c0a4"},"/interchain-security/legacy/v3.2.0/adrs/adr-009-soft-opt-out-38a":{"__comp":"17896441","content":"e9d00230"},"/interchain-security/legacy/v3.2.0/adrs/adr-010-standalone-changeover-a5e":{"__comp":"17896441","content":"2ddaef92"},"/interchain-security/legacy/v3.2.0/adrs/adr-011-improving-test-confidence-257":{"__comp":"17896441","content":"57203821"},"/interchain-security/legacy/v3.2.0/adrs/adr-012-separate-releasing-5cc":{"__comp":"17896441","content":"2e2fcf7b"},"/interchain-security/legacy/v3.2.0/adrs/adr-013-equivocation-slashing-dd5":{"__comp":"17896441","content":"3d02a384"},"/interchain-security/legacy/v3.2.0/adrs/adr-template-5d8":{"__comp":"17896441","content":"91cc339f"},"/interchain-security/legacy/v3.2.0/adrs/intro-bad":{"__comp":"17896441","content":"455b0b19"},"/interchain-security/legacy/v3.2.0/consumer-development/app-integration-b98":{"__comp":"17896441","content":"46dddd35"},"/interchain-security/legacy/v3.2.0/consumer-development/changeover-procedure-82c":{"__comp":"17896441","content":"0b7cd1ab"},"/interchain-security/legacy/v3.2.0/consumer-development/consumer-chain-governance-fb8":{"__comp":"17896441","content":"f37bbee8"},"/interchain-security/legacy/v3.2.0/consumer-development/offboarding-5cc":{"__comp":"17896441","content":"4bec4d8c"},"/interchain-security/legacy/v3.2.0/consumer-development/onboarding-930":{"__comp":"17896441","content":"0c7ba0cc"},"/interchain-security/legacy/v3.2.0/faq-d72":{"__comp":"17896441","content":"c5de07d7"},"/interchain-security/legacy/v3.2.0/features/key-assignment-e02":{"__comp":"17896441","content":"972fb3fd"},"/interchain-security/legacy/v3.2.0/features/proposals-3d6":{"__comp":"17896441","content":"7670b92c"},"/interchain-security/legacy/v3.2.0/features/reward-distribution-827":{"__comp":"17896441","content":"ed4bc87d"},"/interchain-security/legacy/v3.2.0/features/slashing-452":{"__comp":"17896441","content":"863c9ec3"},"/interchain-security/legacy/v3.2.0/introduction/overview-18d":{"__comp":"17896441","content":"ccd1c519"},"/interchain-security/legacy/v3.2.0/introduction/params-5d1":{"__comp":"17896441","content":"62a5ef54"},"/interchain-security/legacy/v3.2.0/introduction/technical-specification-e88":{"__comp":"17896441","content":"f496e447"},"/interchain-security/legacy/v3.2.0/introduction/terminology-b1d":{"__comp":"17896441","content":"ee5432e5"},"/interchain-security/legacy/v3.2.0/validators/changeover-procedure-749":{"__comp":"17896441","content":"f143d156"},"/interchain-security/legacy/v3.2.0/validators/joining-neutron-17a":{"__comp":"17896441","content":"c9ae8e5c"},"/interchain-security/legacy/v3.2.0/validators/joining-stride-f3e":{"__comp":"17896441","content":"a31f1e88"},"/interchain-security/legacy/v3.2.0/validators/joining-testnet-333":{"__comp":"17896441","content":"dee569d7"},"/interchain-security/legacy/v3.2.0/validators/overview-2bb":{"__comp":"17896441","content":"56185081"},"/interchain-security/legacy/v3.2.0/validators/withdraw_rewards-d5a":{"__comp":"17896441","content":"5fdaaf8d"},"/interchain-security/legacy/v3.3.0-9cf":{"__comp":"1be78505","__context":{"plugin":"32783f50"},"versionMetadata":"e3e9e529"},"/interchain-security/legacy/v3.3.0-f70":{"__comp":"17896441","content":"a9646977"},"/interchain-security/legacy/v3.3.0/adrs/adr-001-key-assignment-48c":{"__comp":"17896441","content":"df89b832"},"/interchain-security/legacy/v3.3.0/adrs/adr-002-throttle-d72":{"__comp":"17896441","content":"1833c00d"},"/interchain-security/legacy/v3.3.0/adrs/adr-003-equivocation-gov-proposal-f17":{"__comp":"17896441","content":"90a8ce65"},"/interchain-security/legacy/v3.3.0/adrs/adr-005-cryptographic-equivocation-verification-f75":{"__comp":"17896441","content":"681cd12f"},"/interchain-security/legacy/v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-prop-6bd":{"__comp":"17896441","content":"f4495aae"},"/interchain-security/legacy/v3.3.0/adrs/adr-008-throttle-retries-a7f":{"__comp":"17896441","content":"dc875b45"},"/interchain-security/legacy/v3.3.0/adrs/adr-009-soft-opt-out-ab2":{"__comp":"17896441","content":"e181537f"},"/interchain-security/legacy/v3.3.0/adrs/adr-010-standalone-changeover-236":{"__comp":"17896441","content":"0613ea9d"},"/interchain-security/legacy/v3.3.0/adrs/adr-011-improving-test-confidence-102":{"__comp":"17896441","content":"437cf289"},"/interchain-security/legacy/v3.3.0/adrs/adr-012-separate-releasing-ee8":{"__comp":"17896441","content":"75331c0b"},"/interchain-security/legacy/v3.3.0/adrs/adr-013-equivocation-slashing-f7e":{"__comp":"17896441","content":"20543744"},"/interchain-security/legacy/v3.3.0/adrs/adr-template-5f0":{"__comp":"17896441","content":"b06966f1"},"/interchain-security/legacy/v3.3.0/adrs/intro-496":{"__comp":"17896441","content":"9fe5be76"},"/interchain-security/legacy/v3.3.0/consumer-development/app-integration-fb3":{"__comp":"17896441","content":"98c1c075"},"/interchain-security/legacy/v3.3.0/consumer-development/changeover-procedure-8d0":{"__comp":"17896441","content":"2cf1b2f2"},"/interchain-security/legacy/v3.3.0/consumer-development/consumer-chain-governance-ee6":{"__comp":"17896441","content":"9c1db290"},"/interchain-security/legacy/v3.3.0/consumer-development/consumer-genesis-transformation-5e3":{"__comp":"17896441","content":"45f2a265"},"/interchain-security/legacy/v3.3.0/consumer-development/offboarding-be8":{"__comp":"17896441","content":"d925e878"},"/interchain-security/legacy/v3.3.0/consumer-development/onboarding-28d":{"__comp":"17896441","content":"0251db3a"},"/interchain-security/legacy/v3.3.0/faq-282":{"__comp":"17896441","content":"d9aa5843"},"/interchain-security/legacy/v3.3.0/features/key-assignment-272":{"__comp":"17896441","content":"f5746d50"},"/interchain-security/legacy/v3.3.0/features/proposals-013":{"__comp":"17896441","content":"8e91dc0c"},"/interchain-security/legacy/v3.3.0/features/reward-distribution-019":{"__comp":"17896441","content":"7cd5f60b"},"/interchain-security/legacy/v3.3.0/features/slashing-10c":{"__comp":"17896441","content":"774a0fba"},"/interchain-security/legacy/v3.3.0/introduction/overview-496":{"__comp":"17896441","content":"22c24bfe"},"/interchain-security/legacy/v3.3.0/introduction/params-eb9":{"__comp":"17896441","content":"432d4f39"},"/interchain-security/legacy/v3.3.0/introduction/technical-specification-280":{"__comp":"17896441","content":"02951439"},"/interchain-security/legacy/v3.3.0/introduction/terminology-a84":{"__comp":"17896441","content":"c880b3c7"},"/interchain-security/legacy/v3.3.0/validators/changeover-procedure-77f":{"__comp":"17896441","content":"df2bbb5c"},"/interchain-security/legacy/v3.3.0/validators/joining-neutron-24b":{"__comp":"17896441","content":"3be89897"},"/interchain-security/legacy/v3.3.0/validators/joining-stride-8cc":{"__comp":"17896441","content":"e6400f0f"},"/interchain-security/legacy/v3.3.0/validators/joining-testnet-e9f":{"__comp":"17896441","content":"306f1d5d"},"/interchain-security/legacy/v3.3.0/validators/overview-8ee":{"__comp":"17896441","content":"2ce37f2a"},"/interchain-security/legacy/v3.3.0/validators/withdraw_rewards-099":{"__comp":"17896441","content":"fee5bc5e"},"/interchain-security/legacy/-d62":{"__comp":"1be78505","__context":{"plugin":"32783f50"},"versionMetadata":"935f2afb"},"/interchain-security/legacy/-58a":{"__comp":"17896441","content":"4edc808e"},"/interchain-security/legacy/adrs/adr-001-key-assignment-732":{"__comp":"17896441","content":"54e4400b"},"/interchain-security/legacy/adrs/adr-002-throttle-f62":{"__comp":"17896441","content":"bbea31d2"},"/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposal-152":{"__comp":"17896441","content":"46057b98"},"/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification-562":{"__comp":"17896441","content":"4c7d82ee"},"/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop-3a0":{"__comp":"17896441","content":"ded36896"},"/interchain-security/legacy/adrs/adr-008-throttle-retries-680":{"__comp":"17896441","content":"775e2592"},"/interchain-security/legacy/adrs/adr-009-soft-opt-out-03f":{"__comp":"17896441","content":"903c2771"},"/interchain-security/legacy/adrs/adr-010-standalone-changeover-db5":{"__comp":"17896441","content":"d0d0ba0d"},"/interchain-security/legacy/adrs/adr-011-improving-test-confidence-291":{"__comp":"17896441","content":"68191a78"},"/interchain-security/legacy/adrs/adr-012-separate-releasing-f11":{"__comp":"17896441","content":"d21f9ede"},"/interchain-security/legacy/adrs/adr-013-equivocation-slashing-f27":{"__comp":"17896441","content":"6f71328c"},"/interchain-security/legacy/adrs/adr-template-cb2":{"__comp":"17896441","content":"c37f2705"},"/interchain-security/legacy/adrs/intro-5f0":{"__comp":"17896441","content":"a2707102"},"/interchain-security/legacy/consumer-development/app-integration-48d":{"__comp":"17896441","content":"d784d738"},"/interchain-security/legacy/consumer-development/changeover-procedure-396":{"__comp":"17896441","content":"70938a03"},"/interchain-security/legacy/consumer-development/consumer-chain-governance-781":{"__comp":"17896441","content":"f5589540"},"/interchain-security/legacy/consumer-development/consumer-genesis-transformation-33c":{"__comp":"17896441","content":"425bba28"},"/interchain-security/legacy/consumer-development/offboarding-9fa":{"__comp":"17896441","content":"dc9efaba"},"/interchain-security/legacy/consumer-development/onboarding-cba":{"__comp":"17896441","content":"95875ea0"},"/interchain-security/legacy/faq-5c6":{"__comp":"17896441","content":"00147ff4"},"/interchain-security/legacy/features/key-assignment-b63":{"__comp":"17896441","content":"07d76e7d"},"/interchain-security/legacy/features/proposals-723":{"__comp":"17896441","content":"d1daeca6"},"/interchain-security/legacy/features/reward-distribution-c52":{"__comp":"17896441","content":"578fb1aa"},"/interchain-security/legacy/features/slashing-f1b":{"__comp":"17896441","content":"4106f1c5"},"/interchain-security/legacy/introduction/overview-266":{"__comp":"17896441","content":"7616f23a"},"/interchain-security/legacy/introduction/params-f1d":{"__comp":"17896441","content":"3672b5b7"},"/interchain-security/legacy/introduction/technical-specification-7d6":{"__comp":"17896441","content":"cf411473"},"/interchain-security/legacy/introduction/terminology-c3d":{"__comp":"17896441","content":"bc8b8418"},"/interchain-security/legacy/validators/changeover-procedure-b84":{"__comp":"17896441","content":"c2cfb320"},"/interchain-security/legacy/validators/joining-neutron-748":{"__comp":"17896441","content":"0cb1d302"},"/interchain-security/legacy/validators/joining-stride-1b1":{"__comp":"17896441","content":"ae63551b"},"/interchain-security/legacy/validators/joining-testnet-fed":{"__comp":"17896441","content":"4f50acdf"},"/interchain-security/legacy/validators/overview-f2e":{"__comp":"17896441","content":"f6addb2b"},"/interchain-security/legacy/validators/withdraw_rewards-ee9":{"__comp":"17896441","content":"758625d4"},"/interchain-security/legacy/-e1e":{"__comp":"1be78505","__context":{"plugin":"32783f50"},"versionMetadata":"f7a87f6d"},"/interchain-security/legacy/-5c8":{"__comp":"17896441","content":"b2cefb99"},"/interchain-security/legacy/adrs/adr-001-key-assignment-37f":{"__comp":"17896441","content":"b1bce14b"},"/interchain-security/legacy/adrs/adr-002-throttle-07f":{"__comp":"17896441","content":"97c83118"},"/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposal-5c0":{"__comp":"17896441","content":"b7347dde"},"/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verification-f98":{"__comp":"17896441","content":"665374cc"},"/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-prop-9b1":{"__comp":"17896441","content":"ceabb0b9"},"/interchain-security/legacy/adrs/adr-008-throttle-retries-82c":{"__comp":"17896441","content":"50036eb1"},"/interchain-security/legacy/adrs/adr-009-soft-opt-out-89d":{"__comp":"17896441","content":"1ec51b74"},"/interchain-security/legacy/adrs/adr-010-standalone-changeover-2a8":{"__comp":"17896441","content":"568ca951"},"/interchain-security/legacy/adrs/adr-011-improving-test-confidence-281":{"__comp":"17896441","content":"9fecc647"},"/interchain-security/legacy/adrs/adr-012-separate-releasing-e45":{"__comp":"17896441","content":"6700d82f"},"/interchain-security/legacy/adrs/adr-013-equivocation-slashing-66d":{"__comp":"17896441","content":"545e4084"},"/interchain-security/legacy/adrs/adr-template-cfe":{"__comp":"17896441","content":"834888be"},"/interchain-security/legacy/adrs/intro-6dd":{"__comp":"17896441","content":"5f3b723a"},"/interchain-security/legacy/consumer-development/app-integration-07c":{"__comp":"17896441","content":"40105847"},"/interchain-security/legacy/consumer-development/changeover-procedure-cbe":{"__comp":"17896441","content":"8782d4a8"},"/interchain-security/legacy/consumer-development/consumer-chain-governance-de2":{"__comp":"17896441","content":"10e700ac"},"/interchain-security/legacy/consumer-development/consumer-genesis-transformation-585":{"__comp":"17896441","content":"f4ce0483"},"/interchain-security/legacy/consumer-development/offboarding-60b":{"__comp":"17896441","content":"fcd25e9d"},"/interchain-security/legacy/consumer-development/onboarding-1b2":{"__comp":"17896441","content":"609d3cd8"},"/interchain-security/legacy/faq-401":{"__comp":"17896441","content":"cdc1959e"},"/interchain-security/legacy/features/key-assignment-17f":{"__comp":"17896441","content":"358d35ce"},"/interchain-security/legacy/features/proposals-fc4":{"__comp":"17896441","content":"220c87fe"},"/interchain-security/legacy/features/reward-distribution-6fe":{"__comp":"17896441","content":"4255538f"},"/interchain-security/legacy/features/slashing-534":{"__comp":"17896441","content":"a486c914"},"/interchain-security/legacy/introduction/overview-32a":{"__comp":"17896441","content":"2b87464d"},"/interchain-security/legacy/introduction/params-022":{"__comp":"17896441","content":"2c7ea566"},"/interchain-security/legacy/introduction/technical-specification-82e":{"__comp":"17896441","content":"27d4dd38"},"/interchain-security/legacy/introduction/terminology-e3d":{"__comp":"17896441","content":"a8d2c030"},"/interchain-security/legacy/validators/changeover-procedure-a77":{"__comp":"17896441","content":"1f170e32"},"/interchain-security/legacy/validators/joining-neutron-2bd":{"__comp":"17896441","content":"37744218"},"/interchain-security/legacy/validators/joining-stride-bba":{"__comp":"17896441","content":"89638eb3"},"/interchain-security/legacy/validators/joining-testnet-8dc":{"__comp":"17896441","content":"7b7e6708"},"/interchain-security/legacy/validators/overview-fbc":{"__comp":"17896441","content":"dca56be7"},"/interchain-security/legacy/validators/withdraw_rewards-b4f":{"__comp":"17896441","content":"2d2c570d"}}')}},e=>{e.O(0,[532],(()=>{return t=9383,e(e.s=t);var t}));e.O()}]); \ No newline at end of file diff --git a/legacy/assets/js/main.206ddac4.js.LICENSE.txt b/legacy/assets/js/main.206ddac4.js.LICENSE.txt new file mode 100644 index 0000000000..eb75d69107 --- /dev/null +++ b/legacy/assets/js/main.206ddac4.js.LICENSE.txt @@ -0,0 +1,63 @@ +/* +object-assign +(c) Sindre Sorhus +@license MIT +*/ + +/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress + * @license MIT */ + +/** + * @license React + * use-sync-external-store-shim.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Prism: Lightweight, robust, elegant syntax highlighting + * + * @license MIT <https://opensource.org/licenses/MIT> + * @author Lea Verou <https://lea.verou.me> + * @namespace + * @public + */ + +/** @license React v0.20.2 + * scheduler.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** @license React v16.13.1 + * react-is.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** @license React v17.0.2 + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** @license React v17.0.2 + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ diff --git a/legacy/assets/js/runtime~main.6dc179b3.js b/legacy/assets/js/runtime~main.6dc179b3.js new file mode 100644 index 0000000000..abdd2c5bb1 --- /dev/null +++ b/legacy/assets/js/runtime~main.6dc179b3.js @@ -0,0 +1 @@ +(()=>{"use strict";var e,c,d,f,b,a={},t={};function r(e){var c=t[e];if(void 0!==c)return c.exports;var d=t[e]={exports:{}};return a[e].call(d.exports,d,d.exports,r),d.exports}r.m=a,e=[],r.O=(c,d,f,b)=>{if(!d){var a=1/0;for(i=0;i<e.length;i++){d=e[i][0],f=e[i][1],b=e[i][2];for(var t=!0,o=0;o<d.length;o++)(!1&b||a>=b)&&Object.keys(r.O).every((e=>r.O[e](d[o])))?d.splice(o--,1):(t=!1,b<a&&(a=b));if(t){e.splice(i--,1);var n=f();void 0!==n&&(c=n)}}return c}b=b||0;for(var i=e.length;i>0&&e[i-1][2]>b;i--)e[i]=e[i-1];e[i]=[d,f,b]},r.n=e=>{var c=e&&e.__esModule?()=>e.default:()=>e;return r.d(c,{a:c}),c},d=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,f){if(1&f&&(e=this(e)),8&f)return e;if("object"==typeof e&&e){if(4&f&&e.__esModule)return e;if(16&f&&"function"==typeof e.then)return e}var b=Object.create(null);r.r(b);var a={};c=c||[null,d({}),d([]),d(d)];for(var t=2&f&&e;"object"==typeof t&&!~c.indexOf(t);t=d(t))Object.getOwnPropertyNames(t).forEach((c=>a[c]=()=>e[c]));return a.default=()=>e,r.d(b,a),b},r.d=(e,c)=>{for(var d in c)r.o(c,d)&&!r.o(e,d)&&Object.defineProperty(e,d,{enumerable:!0,get:c[d]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((c,d)=>(r.f[d](e,c),c)),[])),r.u=e=>"assets/js/"+({35:"f6addb2b",53:"935f2afb",74:"c5de07d7",109:"bbea31d2",137:"a8d2c030",141:"ee6b1b56",146:"ff887390",155:"c2da6a7e",222:"f0becab0",320:"3672b5b7",321:"758625d4",324:"1a009efd",333:"4c058ddf",375:"4c855390",379:"6c7cd03d",414:"7b7e6708",457:"a2707102",468:"f4ce0483",492:"455b0b19",495:"0613ea9d",524:"7a380eb1",542:"1833c00d",544:"f496e447",608:"a9646977",692:"9b050cce",766:"3e7b8ec9",818:"89638eb3",842:"4106f1c5",847:"1f170e32",863:"1d3f4228",872:"44efc911",915:"ebdc1949",918:"2e2fcf7b",947:"dca8d7c6",1043:"1ca03be8",1064:"e6400f0f",1081:"d411b146",1085:"0cb1d302",1087:"aede9d74",1118:"425bba28",1136:"4b0243dd",1289:"437cf289",1298:"91cc339f",1324:"dc9efaba",1409:"81762141",1429:"c2cfb320",1534:"bc17315d",1535:"4255538f",1564:"c880b3c7",1585:"5f3b723a",1614:"05354274",1657:"eb02ef83",1849:"6441912e",1878:"dee569d7",1962:"8565b213",2002:"20543744",2068:"863c9ec3",2082:"98c1c075",2087:"1a276578",2098:"8e91dc0c",2110:"00147ff4",2117:"f7a87f6d",2148:"1bcdc660",2181:"3a65a150",2189:"07d76e7d",2247:"7616f23a",2293:"bb11f0e8",2323:"578fb1aa",2344:"54e4400b",2361:"32783f50",2384:"665374cc",2454:"2ddaef92",2584:"3d02a384",2589:"65076e0d",2715:"d9aa5843",2745:"75331c0b",2749:"90a8ce65",2777:"84bd924c",2784:"b7347dde",2813:"22c24bfe",2845:"b74a2173",2876:"ee5432e5",2979:"2ce37f2a",3153:"cf411473",3159:"46057b98",3302:"e3e9e529",3422:"57c82761",3493:"10e700ac",3612:"dca56be7",3631:"c99bfd69",3734:"02951439",3739:"f37bbee8",3813:"95875ea0",3842:"d262fdd7",3845:"d1daeca6",3858:"1560cd4f",3913:"08757149",3932:"ed4bc87d",3938:"97c83118",3943:"b2cefb99",3986:"29f8b3e7",4077:"0c7ba0cc",4115:"ccd1c519",4150:"fc1c61d3",4158:"e9d00230",4173:"4edc808e",4220:"0251db3a",4322:"4cc37eaf",4343:"358d35ce",4360:"db091dad",4391:"9fe5be76",4438:"68191a78",4457:"545e4084",4520:"2d2c570d",4645:"7c1fc285",4675:"609d3cd8",4676:"9b3ea85c",4695:"c37f2705",4704:"bc8b8418",4738:"d67a6454",4868:"2b87464d",4895:"1f0eef20",4932:"d21f9ede",5011:"b06966f1",5022:"ffd4165d",5045:"f4495aae",5056:"ae63551b",5059:"df89b832",5101:"8782d4a8",5202:"bc700a7c",5349:"e23b6b4c",5357:"7cd5f60b",5457:"70938a03",5464:"2eef71dd",5474:"46dddd35",5626:"b2effb50",5627:"220c87fe",5680:"e181537f",5685:"5fdaaf8d",5721:"40105847",5731:"c57e97ca",5831:"834888be",5863:"fe5d7ad2",5864:"45f2a265",5868:"fbda1364",5964:"07a13505",6054:"903c2771",6108:"afe2e479",6181:"ff39e481",6239:"432d4f39",6255:"a31f1e88",6318:"d63ae50e",6322:"5f35bbec",6398:"11e17b14",6438:"568ca951",6499:"f5589540",6501:"62a5ef54",6550:"d925e878",6703:"ceabb0b9",6725:"972fb3fd",6755:"0b7cd1ab",6894:"dc875b45",6938:"67f96001",6960:"8fb9dc62",6986:"cdc1959e",7116:"37744218",7209:"27d4dd38",7249:"50036eb1",7333:"d784d738",7335:"774a0fba",7372:"9c1db290",7375:"775e2592",7428:"c9ae8e5c",7429:"ded36896",7443:"681cd12f",7511:"f143d156",7567:"b9eeacc5",7646:"25dc14a6",7649:"4c7d82ee",7652:"b1ce16c0",7762:"b1bce14b",7918:"17896441",7988:"a486c914",8055:"6700d82f",8087:"56185081",8124:"4bec4d8c",8130:"306f1d5d",8186:"bb7b1385",8194:"9fecc647",8219:"01ff7a4e",8281:"875b184f",8313:"f5746d50",8330:"d88536eb",8560:"6f71328c",8646:"57203821",8661:"fee5bc5e",8685:"1bdc04ff",8756:"3299f073",8763:"3be89897",8772:"d0d0ba0d",8779:"1ec51b74",8795:"d73929d1",8930:"f8317958",8935:"3739a4c2",8956:"04f38623",8973:"dd2dc399",8976:"c566c0a4",8990:"b4bb90a1",9029:"2ee035c9",9117:"f249e987",9124:"2c7ea566",9242:"2cf1b2f2",9300:"e1611597",9474:"fcd25e9d",9514:"1be78505",9552:"7670b92c",9701:"811ce3c2",9743:"6a7358b5",9759:"14ce44a3",9783:"07e666cb",9815:"4f50acdf",9832:"df2bbb5c",9980:"d4f67fc8"}[e]||e)+"."+{35:"507409b8",53:"64bd8468",74:"9759b93a",109:"bd6600ce",137:"3892c3ef",141:"6b17dbc1",146:"dc7e3908",155:"9945fe6d",222:"b3d4183e",320:"3b15d5c8",321:"273190c7",324:"75aaa0fa",333:"3688d9f0",375:"3b0f05f7",379:"695e3b04",414:"18df0ce5",457:"645ad012",468:"d7b208a3",492:"4415e5b6",495:"808de359",524:"83f2cce9",542:"1278baf4",544:"958e6164",608:"2a0404d5",692:"4f7d54a6",766:"62220d7f",818:"c12ace70",842:"f7020cca",847:"5eb3a801",863:"5d264fe1",872:"285ae205",915:"59e9d9fa",918:"b6f4a559",947:"b9f5d0fc",1043:"5d6bad63",1064:"e3e0a98b",1081:"4015c836",1085:"664303dc",1087:"6d8e2449",1118:"bf7a9987",1136:"91644af8",1289:"dbfb2a08",1298:"5ff44e54",1324:"43a93fd3",1409:"ff37e79d",1429:"c4803ac7",1534:"f9026ef2",1535:"d2560f60",1564:"b3d9e09c",1585:"67a2780a",1614:"54e3067a",1657:"484e8e31",1849:"ca22e873",1878:"9ec14372",1962:"798e93c8",2002:"c24270e7",2068:"48c51999",2082:"825c69fd",2087:"896dcb3b",2098:"36e2e9b4",2110:"3569d3ae",2117:"bb9958dd",2148:"1290b87e",2181:"9e3ed84d",2189:"fd454a42",2247:"fe758987",2293:"aa98b53c",2323:"43e0b978",2344:"a869b7ad",2361:"071d53c7",2384:"fbe2de3b",2454:"9ebd2053",2584:"3955deea",2589:"34ce332b",2715:"661bb45b",2745:"8235ad0a",2749:"0ab58bcb",2777:"97d868f9",2784:"cdacfbbc",2813:"f284dc6c",2845:"0d9b82cf",2876:"78f242e9",2979:"dfc4924c",3153:"6073d7f0",3159:"3691d884",3302:"4655caa7",3422:"afd24b48",3493:"642210c3",3612:"8e46da4b",3631:"92afb3d3",3734:"f3f01a29",3739:"118148f8",3813:"6ffcab52",3842:"67fecee7",3845:"9aed11ad",3858:"1afd62f5",3913:"630ce891",3932:"1be93e7e",3938:"9dbb4c6e",3943:"aa9036e6",3986:"1d3ce1e7",4077:"5f25b7fc",4115:"e31286c5",4150:"764fc729",4158:"ef9e3baa",4173:"20fd5a0c",4220:"3cde3e2b",4322:"1fce0a56",4343:"dadf7286",4360:"0a75cee6",4391:"d25fa769",4438:"0ac8aa89",4457:"ea4e8960",4520:"19d0db57",4645:"13bcbb37",4675:"d053c91e",4676:"9d0d730c",4695:"419e8a23",4704:"390b8795",4738:"f96dac3e",4868:"2ca9d156",4895:"67ec7875",4932:"ffa95316",4972:"9374abde",5011:"7bb1f6c3",5022:"dcb45328",5045:"7cec05a4",5056:"e7e90402",5059:"6fe61836",5101:"ed4f52f3",5202:"65ce008c",5349:"19be60c2",5357:"0f1e5e23",5457:"227a4d05",5464:"68939c94",5474:"04e8e182",5626:"acdda8b6",5627:"3606b286",5680:"5447d3b6",5685:"eb3bafef",5721:"a4dd3ddb",5731:"bb70d7e1",5831:"5b1bcc44",5863:"9e3601c3",5864:"8cbf978c",5868:"213bf4e3",5964:"5d186dd7",6054:"ebeb1a28",6108:"1b9ff36d",6181:"477a6c6b",6239:"d0758794",6255:"25172256",6318:"b2d5797e",6322:"c4fbb0a0",6398:"970968fa",6438:"5df0b615",6499:"6c0ad7d0",6501:"698335d4",6550:"cf4495d8",6703:"11d69bef",6725:"1cc68b7b",6755:"04a31874",6894:"7203e3b3",6938:"79e68eb4",6960:"61dd95c4",6986:"fecc2b5f",7116:"00a8a74e",7209:"4cac5e7f",7249:"2765b1a3",7333:"43cc64b4",7335:"a14158d6",7372:"2111d933",7375:"f3f5f0d3",7428:"765b1dd1",7429:"d40f5dbf",7443:"dfc08d34",7511:"8e2b8300",7567:"e10e338f",7646:"52fe37dc",7649:"da063855",7652:"7130eb69",7762:"e249808f",7918:"a6244cb7",7988:"4dc177eb",8055:"6e956d4b",8087:"6b064da2",8124:"a17acccd",8130:"74edbf3e",8186:"f09fc6a6",8194:"8f3743c2",8219:"8ba03b4e",8281:"2edbe09d",8313:"6a4430ce",8330:"610c4cdc",8560:"b0a51530",8646:"5604c344",8661:"c989bfaf",8685:"80430411",8756:"cf4a49c3",8763:"d5956040",8772:"1e2f89a5",8779:"060236b9",8795:"71420f3f",8930:"137ca363",8935:"c9f8167e",8956:"0b0a20d5",8973:"3809744d",8976:"3e13bfdc",8990:"06f97b20",9029:"06127535",9117:"cf824747",9124:"795b742d",9242:"5323a352",9300:"55aa8324",9474:"359f4087",9514:"9ab70eac",9552:"94ffb81a",9701:"901b6dd1",9743:"5cf848d2",9759:"f1e70d90",9783:"a5f5aa7e",9815:"f48be075",9832:"245ed571",9980:"1e4b370d"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,c)=>Object.prototype.hasOwnProperty.call(e,c),f={},b="website:",r.l=(e,c,d,a)=>{if(f[e])f[e].push(c);else{var t,o;if(void 0!==d)for(var n=document.getElementsByTagName("script"),i=0;i<n.length;i++){var u=n[i];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==b+d){t=u;break}}t||(o=!0,(t=document.createElement("script")).charset="utf-8",t.timeout=120,r.nc&&t.setAttribute("nonce",r.nc),t.setAttribute("data-webpack",b+d),t.src=e),f[e]=[c];var l=(c,d)=>{t.onerror=t.onload=null,clearTimeout(s);var b=f[e];if(delete f[e],t.parentNode&&t.parentNode.removeChild(t),b&&b.forEach((e=>e(d))),c)return c(d)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:t}),12e4);t.onerror=l.bind(null,t.onerror),t.onload=l.bind(null,t.onload),o&&document.head.appendChild(t)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/interchain-security/legacy/",r.gca=function(e){return e={17896441:"7918",20543744:"2002",37744218:"7116",40105847:"5721",56185081:"8087",57203821:"8646",81762141:"1409",f6addb2b:"35","935f2afb":"53",c5de07d7:"74",bbea31d2:"109",a8d2c030:"137",ee6b1b56:"141",ff887390:"146",c2da6a7e:"155",f0becab0:"222","3672b5b7":"320","758625d4":"321","1a009efd":"324","4c058ddf":"333","4c855390":"375","6c7cd03d":"379","7b7e6708":"414",a2707102:"457",f4ce0483:"468","455b0b19":"492","0613ea9d":"495","7a380eb1":"524","1833c00d":"542",f496e447:"544",a9646977:"608","9b050cce":"692","3e7b8ec9":"766","89638eb3":"818","4106f1c5":"842","1f170e32":"847","1d3f4228":"863","44efc911":"872",ebdc1949:"915","2e2fcf7b":"918",dca8d7c6:"947","1ca03be8":"1043",e6400f0f:"1064",d411b146:"1081","0cb1d302":"1085",aede9d74:"1087","425bba28":"1118","4b0243dd":"1136","437cf289":"1289","91cc339f":"1298",dc9efaba:"1324",c2cfb320:"1429",bc17315d:"1534","4255538f":"1535",c880b3c7:"1564","5f3b723a":"1585","05354274":"1614",eb02ef83:"1657","6441912e":"1849",dee569d7:"1878","8565b213":"1962","863c9ec3":"2068","98c1c075":"2082","1a276578":"2087","8e91dc0c":"2098","00147ff4":"2110",f7a87f6d:"2117","1bcdc660":"2148","3a65a150":"2181","07d76e7d":"2189","7616f23a":"2247",bb11f0e8:"2293","578fb1aa":"2323","54e4400b":"2344","32783f50":"2361","665374cc":"2384","2ddaef92":"2454","3d02a384":"2584","65076e0d":"2589",d9aa5843:"2715","75331c0b":"2745","90a8ce65":"2749","84bd924c":"2777",b7347dde:"2784","22c24bfe":"2813",b74a2173:"2845",ee5432e5:"2876","2ce37f2a":"2979",cf411473:"3153","46057b98":"3159",e3e9e529:"3302","57c82761":"3422","10e700ac":"3493",dca56be7:"3612",c99bfd69:"3631","02951439":"3734",f37bbee8:"3739","95875ea0":"3813",d262fdd7:"3842",d1daeca6:"3845","1560cd4f":"3858","08757149":"3913",ed4bc87d:"3932","97c83118":"3938",b2cefb99:"3943","29f8b3e7":"3986","0c7ba0cc":"4077",ccd1c519:"4115",fc1c61d3:"4150",e9d00230:"4158","4edc808e":"4173","0251db3a":"4220","4cc37eaf":"4322","358d35ce":"4343",db091dad:"4360","9fe5be76":"4391","68191a78":"4438","545e4084":"4457","2d2c570d":"4520","7c1fc285":"4645","609d3cd8":"4675","9b3ea85c":"4676",c37f2705:"4695",bc8b8418:"4704",d67a6454:"4738","2b87464d":"4868","1f0eef20":"4895",d21f9ede:"4932",b06966f1:"5011",ffd4165d:"5022",f4495aae:"5045",ae63551b:"5056",df89b832:"5059","8782d4a8":"5101",bc700a7c:"5202",e23b6b4c:"5349","7cd5f60b":"5357","70938a03":"5457","2eef71dd":"5464","46dddd35":"5474",b2effb50:"5626","220c87fe":"5627",e181537f:"5680","5fdaaf8d":"5685",c57e97ca:"5731","834888be":"5831",fe5d7ad2:"5863","45f2a265":"5864",fbda1364:"5868","07a13505":"5964","903c2771":"6054",afe2e479:"6108",ff39e481:"6181","432d4f39":"6239",a31f1e88:"6255",d63ae50e:"6318","5f35bbec":"6322","11e17b14":"6398","568ca951":"6438",f5589540:"6499","62a5ef54":"6501",d925e878:"6550",ceabb0b9:"6703","972fb3fd":"6725","0b7cd1ab":"6755",dc875b45:"6894","67f96001":"6938","8fb9dc62":"6960",cdc1959e:"6986","27d4dd38":"7209","50036eb1":"7249",d784d738:"7333","774a0fba":"7335","9c1db290":"7372","775e2592":"7375",c9ae8e5c:"7428",ded36896:"7429","681cd12f":"7443",f143d156:"7511",b9eeacc5:"7567","25dc14a6":"7646","4c7d82ee":"7649",b1ce16c0:"7652",b1bce14b:"7762",a486c914:"7988","6700d82f":"8055","4bec4d8c":"8124","306f1d5d":"8130",bb7b1385:"8186","9fecc647":"8194","01ff7a4e":"8219","875b184f":"8281",f5746d50:"8313",d88536eb:"8330","6f71328c":"8560",fee5bc5e:"8661","1bdc04ff":"8685","3299f073":"8756","3be89897":"8763",d0d0ba0d:"8772","1ec51b74":"8779",d73929d1:"8795",f8317958:"8930","3739a4c2":"8935","04f38623":"8956",dd2dc399:"8973",c566c0a4:"8976",b4bb90a1:"8990","2ee035c9":"9029",f249e987:"9117","2c7ea566":"9124","2cf1b2f2":"9242",e1611597:"9300",fcd25e9d:"9474","1be78505":"9514","7670b92c":"9552","811ce3c2":"9701","6a7358b5":"9743","14ce44a3":"9759","07e666cb":"9783","4f50acdf":"9815",df2bbb5c:"9832",d4f67fc8:"9980"}[e]||e,r.p+r.u(e)},(()=>{var e={1303:0,532:0};r.f.j=(c,d)=>{var f=r.o(e,c)?e[c]:void 0;if(0!==f)if(f)d.push(f[2]);else if(/^(1303|532)$/.test(c))e[c]=0;else{var b=new Promise(((d,b)=>f=e[c]=[d,b]));d.push(f[2]=b);var a=r.p+r.u(c),t=new Error;r.l(a,(d=>{if(r.o(e,c)&&(0!==(f=e[c])&&(e[c]=void 0),f)){var b=d&&("load"===d.type?"missing":d.type),a=d&&d.target&&d.target.src;t.message="Loading chunk "+c+" failed.\n("+b+": "+a+")",t.name="ChunkLoadError",t.type=b,t.request=a,f[1](t)}}),"chunk-"+c,c)}},r.O.j=c=>0===e[c];var c=(c,d)=>{var f,b,a=d[0],t=d[1],o=d[2],n=0;if(a.some((c=>0!==e[c]))){for(f in t)r.o(t,f)&&(r.m[f]=t[f]);if(o)var i=o(r)}for(c&&c(d);n<a.length;n++)b=a[n],r.o(e,b)&&e[b]&&e[b][0](),e[b]=0;return r.O(i)},d=self.webpackChunkwebsite=self.webpackChunkwebsite||[];d.forEach(c.bind(null,0)),d.push=c.bind(null,d.push.bind(d))})()})(); \ No newline at end of file diff --git a/legacy/consumer-development/app-integration.html b/legacy/consumer-development/app-integration.html new file mode 100644 index 0000000000..6a58448e52 --- /dev/null +++ b/legacy/consumer-development/app-integration.html @@ -0,0 +1,23 @@ +<!doctype html> +<html lang="en" dir="ltr" class="docs-wrapper docs-doc-page docs-version-current plugin-docs plugin-id-default docs-doc-id-consumer-development/app-integration"> +<head> +<meta charset="UTF-8"> +<meta name="generator" content="Docusaurus v2.4.1"> +<title data-rh="true">Developing an ICS consumer chain | Interchain Security + + + + +
+
Version: Next

Developing an ICS consumer chain

When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol. +To help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications.

Basic consumer chain

The source code for the example app can be found here.

Please note that consumer chains do not implement the staking module - the validator set is replicated from the provider, meaning that the provider and the consumer use the same validator set and their stake on the provider directly determines their stake on the consumer. +At present there is no opt-in mechanism available, so all validators of the provider must also validate on the provider chain.

Your chain should import the consumer module from x/consumer and register it in the correct places in your app.go. +The x/consumer module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in. +You should not need to manage or override any code from the x/consumer module.

Democracy consumer chain

The source code for the example app can be found here.

This type of consumer chain wraps the basic CosmosSDK x/distribution, x/staking and x/governance modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system.

This allows the consumer chain to leverage those modules while also using the x/consumer module.

With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.

Standalone chain to consumer chain changeover

This feature is being actively worked on. Information will be provided at a later time.

+ + + + \ No newline at end of file diff --git a/legacy/consumer-development/app-integration.html.html b/legacy/consumer-development/app-integration.html.html new file mode 100644 index 0000000000..5cf4242e4b --- /dev/null +++ b/legacy/consumer-development/app-integration.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/consumer-development/changeover-procedure.html b/legacy/consumer-development/changeover-procedure.html new file mode 100644 index 0000000000..440dce79b3 --- /dev/null +++ b/legacy/consumer-development/changeover-procedure.html @@ -0,0 +1,19 @@ + + + + + +Changeover Procedure | Interchain Security + + + + +
+
Version: Next

Changeover Procedure

Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.

The relevant protocol specifications are available below:

Overview

Standalone to consumer changeover procedure can rougly be separated into 4 parts:

1. ConsumerAddition proposal submitted to the provider chain

The proposal is equivalent to the "normal" ConsumerAddition proposal submitted by new consumer chains.

However, here are the most important notes and differences between a new consumer chain and a standalone chain performing a changeover:

  • chain_id must be equal to the standalone chain id
  • initial_height field has additional rules to abide by:
caution
{
...
"initial_height" : {
// must correspond to current revision number of standalone chain
// e.g. stride-1 => "revision_number": 1
"revision_number": 1,

// must correspond to a height that is at least 1 block after the upgrade
// that will add the `consumer` module to the standalone chain
// e.g. "upgrade_height": 100 => "revision_height": 101
"revision_height": 1,
},
...
}

RevisionNumber: 0, RevisionHeight: 111

  • genesis_hash can be safely ignored because the chain is already running. A hash of the standalone chain's initial genesis may be used

  • binary_hash may not be available ahead of time. All chains performing the changeover go through rigorous testing - if bugs are caught and fixed the hash listed in the proposal may not be the most recent one.

  • spawn_time listed in the proposal MUST be before the upgrade_height listed in the the upgrade proposal on the standalone chain.

    caution

    spawn_time must occur before the upgrade_height on the standalone chain is reached because the provider chain must generate the ConsumerGenesis that contains the validator set that will be used after the changeover.

  • unbonding_period must correspond to the value used on the standalone chain. Otherwise, the clients used for the ccv protocol may be incorrectly initialized.

  • distribution_transmission_channel should be set.

note

Populating distribution_transmission_channel will enable the standalone chain to re-use one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ibc denom that may already be in use.

If the parameter is not set, a new channel will be created.

  • ccv_timeout_period has no important notes

  • transfer_timeout_period has no important notes

  • consumer_redistribution_fraction has no important notes

  • blocks_per_distribution_transmission has no important notes

  • historical_entries has no important notes

2. upgrade proposal on standalone chain

The standalone chain creates an upgrade proposal to include the interchain-security/x/ccv/consumer module.

caution

The upgrade height in the proposal should correspond to a height that is after the spawn_time in the consumer addition proposal submitted to the provider chain.

Otherwise, the upgrade is indistinguishable from a regular on-chain upgrade proposal.

3. spawn time is reached

When the spawn_time is reached on the provider it will generate a ConsumerGenesis that contains the validator set that will supercede the standalone validator set.

This ConsumerGenesis must be available on the standalone chain during the on-chain upgrade.

4. standalone chain upgrade

Performing the on-chain upgrade on the standalone chain will add the ccv/consumer module and allow the chain to become a consumer of replicated security.

caution

The ConsumerGenesis must be exported to a file and placed in the correct folder on the standalone chain before the upgade.

The file must be placed at the exact specified location, otherwise the upgrade will not be executed correctly.

Usually the file is placed in $NODE_HOME/config, but the file name and the exact directory is dictated by the upgrade code on the standalone chain.

  • please check exact instructions provided by the standalone chain team

After the genesis.json file has been made available, the process is equivalent to a normal on-chain upgrade. The standalone validator set will sign the next couple of blocks before transferring control to provider validator set.

The standalone validator set can still be slashed for any infractions if evidence is submitted within the unboding_period.

Notes

The changeover procedure may be updated in the future to create a seamless way of providing the validator set information to the standalone chain.

Onboarding Checklist

This onboarding checklist is slightly different from the one under Onboarding

Additionally, you can check the testnet repo for a comprehensive guide on preparing and launching consumer chains.

1. Complete testing & integration

  • test integration with gaia
  • test your protocol with supported relayer versions (minimum hermes 1.4.1)
  • test the changeover procedure
  • reach out to the ICS team if you are facing issues

2. Create an Onboarding Repository

To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain.

This should include (at minimum):

  • genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see Transform Consumer Genesis)
  • information about relevant seed/peer nodes you are running
  • relayer information (compatible versions)
  • copy of your governance proposal (as JSON)
  • a script showing how to start your chain and connect to peers (optional)
  • take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable

Example of such a repository can be found here.

3. Submit a ConsumerChainAddition Governance Proposal to the provider

Before you submit a ConsumerChainAddition proposal, please provide a spawn_time that is before the the upgrade_height of the upgrade that will introduce the ccv module to your chain.

danger

If the spawn_time happens after your upgrade_height the provider will not be able to communicate the new validator set to be used after the changeover.

Additionally, reach out to the community via the forum to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers.

  • determine your chain's spawn time
  • determine consumer chain parameters to be put in the proposal
  • take note to include a link to your onboarding repository

Example of a consumer chain addition proposal.

// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain or add a standalone chain.
// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.
// It is recommended that spawn time occurs after the proposal end time and that it is scheduled to happen before the standalone chain upgrade
// that sill introduce the ccv module.
{
// Title of the proposal
"title": "Changeover Standalone chain",
// Description of the proposal
// format the text as a .md file and include the file in your onboarding repository
"description": ".md description of your chain and all other relevant information",
// Proposed chain-id of the new consumer chain.
// Must be unique from all other consumer chain ids of the executing provider chain.
"chain_id": "standalone-1",
// Initial height of new consumer chain.
// For a completely new chain, this will be {0,1}.
"initial_height" : {
// must correspond to current revision number of standalone chain
// e.g. standalone-1 => "revision_number": 1
"revision_number": 1,

// must correspond to a height that is at least 1 block after the upgrade
// that will add the `consumer` module to the standalone chain
// e.g. "upgrade_height": 100 => "revision_height": 101
"revision_number": 1,
},
// Hash of the consumer chain genesis state without the consumer CCV module genesis params.
// => not relevant for changeover procedure
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
// Hash of the consumer chain binary that should be run by validators on standalone chain upgrade
// => not relevant for changeover procedure as it may become stale
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
// Unbonding period for the consumer chain.
// It should should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
// IBC transfer packets will timeout after this interval elapses.
"transfer_timeout_period": 1800000000000,
// The fraction of tokens allocated to the consumer redistribution address during distribution events.
// The fraction is a string representing a decimal number. For example "0.75" would represent 75%.
// The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.
"consumer_redistribution_fraction": "0.75",
// BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.
// eg. send rewards to the provider every 1000 blocks
"blocks_per_distribution_transmission": 1000,
// The number of historical info entries to persist in store.
// This param is a part of the cosmos sdk staking module. In the case of
// a ccv enabled consumer chain, the ccv module acts as the staking module.
"historical_entries": 10000,
// The ID of a token transfer channel used for the Reward Distribution
// sub-protocol. If DistributionTransmissionChannel == "", a new transfer
// channel is created on top of the same connection as the CCV channel.
// Note that transfer_channel_id is the ID of the channel end on the consumer chain.
// it is most relevant for chains performing a standalone to consumer changeover
// in order to maintan the existing ibc transfer channel
"distribution_transmission_channel": "channel-123" // NOTE: use existing transfer channel if available
}

3. Submit an Upgrade Proposal & Prepare for Changeover

This proposal should add the ccv consumer module to your chain.

  • proposal upgrade_height must happen after spawn_time in the ConsumerAdditionProposal
  • advise validators about the exact procedure for your chain and point them to your onboarding repository

4. Upgrade time 🚀

  • after spawn_time, request ConsumerGenesis from the provider and place it in <CURRENT_USER_HOME_DIR>/.sovereign/config/genesis.json
  • upgrade the binary to the one listed in your UpgradeProposal

The chain starts after at least 66.67% of standalone voting power comes online. The consumer chain is considered interchain secured once the "old" validator set signs a couple of blocks and transfers control to the provider validator set.

  • provide a repo with onboarding instructions for validators (it should already be listed in the proposal)
  • genesis.json after spawn_time obtained from provider (MUST contain the initial validator set)
  • maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)
+ + + + \ No newline at end of file diff --git a/legacy/consumer-development/changeover-procedure.html.html b/legacy/consumer-development/changeover-procedure.html.html new file mode 100644 index 0000000000..83be031ed2 --- /dev/null +++ b/legacy/consumer-development/changeover-procedure.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/consumer-development/consumer-chain-governance.html b/legacy/consumer-development/consumer-chain-governance.html new file mode 100644 index 0000000000..78d70094ea --- /dev/null +++ b/legacy/consumer-development/consumer-chain-governance.html @@ -0,0 +1,19 @@ + + + + + +Consumer Chain Governance | Interchain Security + + + + +
+
Version: Next

Consumer Chain Governance

Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We'll cover what these are in the "Whitelist" section below.

Democracy module

The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy.

Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus.

For an example, see the Democracy Consumer

CosmWasm

There are several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain.

For an example, see Neutron.

The Whitelist

Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see Neutron's whitelist.

+ + + + \ No newline at end of file diff --git a/legacy/consumer-development/consumer-chain-governance.html.html b/legacy/consumer-development/consumer-chain-governance.html.html new file mode 100644 index 0000000000..0a07dbfda4 --- /dev/null +++ b/legacy/consumer-development/consumer-chain-governance.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/consumer-development/consumer-genesis-transformation.html b/legacy/consumer-development/consumer-genesis-transformation.html new file mode 100644 index 0000000000..7ba38c0656 --- /dev/null +++ b/legacy/consumer-development/consumer-genesis-transformation.html @@ -0,0 +1,22 @@ + + + + + +Consumer Genesis Transformation | Interchain Security + + + + +
+
Version: Next

Consumer Genesis Transformation

Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentaion on Onboarding and Changeover). +In case that the provider chain is running an older version of the InterChainSecurity (ICS) module than the consumer chain the exported CCV data might need to be transformed to the format supported by the ICS implementation run on the consumer chain. This is the case if the cosumer chain runs version 4 of ICS or later and the provider is running version 3 or older of the ICS module.

To transform such CCV data follow the instructions below

1. Prerequisite

  • Provider chain is running version 3 or older of the ICS provider module
  • Consumer is running version 4 or later of the ICS consumer module.
  • interchain-security-cd application complies to the version run on the consumer chain

2. Export the CCV data

Export the CCV data from the provider chain as descibed in the Onboarding and Changeover) your following. +As a result the CCV data will be stored in a file in JSON format.

3. Transform CCV data

To transform the CCV data to the newer format run the following command.

interchain-security-cd genesis transform [genesis-file]

where 'genesis-file' is the path to the file containing the CCV data exported in step 2. +As a result the CCV data in the new format will be written to standard output.

Use the new CCV data as described in the procedure you're following.

+ + + + \ No newline at end of file diff --git a/legacy/consumer-development/consumer-genesis-transformation.html.html b/legacy/consumer-development/consumer-genesis-transformation.html.html new file mode 100644 index 0000000000..e208b52a6d --- /dev/null +++ b/legacy/consumer-development/consumer-genesis-transformation.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/consumer-development/offboarding.html b/legacy/consumer-development/offboarding.html new file mode 100644 index 0000000000..213b3c4d75 --- /dev/null +++ b/legacy/consumer-development/offboarding.html @@ -0,0 +1,19 @@ + + + + + +Offboarding Checklist | Interchain Security + + + + +
+
Version: Next

Consumer Offboarding

To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).

// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.
// If it passes, all the consumer chain's state is removed from the provider chain. The outstanding unbonding
// operation funds are released.
{
// the title of the proposal
"title": "This was a great chain",
"description": "Here is a .md formatted string specifying removal details",
// the chain-id of the consumer chain to be stopped
"chain_id": "consumerchain-1",
// the time on the provider chain at which all validators are responsible to stop their consumer chain validator node
"stop_time": "2023-03-07T12:40:00.000000Z",
}

More information will be listed in a future version of this document.

+ + + + \ No newline at end of file diff --git a/legacy/consumer-development/offboarding.html.html b/legacy/consumer-development/offboarding.html.html new file mode 100644 index 0000000000..655e3280ab --- /dev/null +++ b/legacy/consumer-development/offboarding.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/consumer-development/onboarding.html b/legacy/consumer-development/onboarding.html new file mode 100644 index 0000000000..cfa98a172c --- /dev/null +++ b/legacy/consumer-development/onboarding.html @@ -0,0 +1,20 @@ + + + + + +Onboarding Checklist | Interchain Security + + + + +
+
Version: Next

Consumer Onboarding Checklist

The following checklists will aid in onboarding a new consumer chain to replicated security.

Additionally, you can check the testnet repo for a comprehensive guide on preparing and launching consumer chains.

1. Complete testing & integration

  • test integration with gaia
  • test your protocol with supported relayer versions (minimum hermes 1.4.1)
  • reach out to the ICS team if you are facing issues

2. Create an Onboarding Repository

To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain.

This should include (at minimum):

  • genesis.json without CCV data (before the proposal passes)
  • genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see Transform Consumer Genesis)
  • information about relevant seed/peer nodes you are running
  • relayer information (compatible versions)
  • copy of your governance proposal (as JSON)
  • a script showing how to start your chain and connect to peers (optional)
  • take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable

Example of such a repository can be found here.

3. Submit a Governance Proposal

Before you submit a ConsumerChainAddition proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch. +If possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues.

Additionally, reach out to the community via the forum to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers.

  • determine your chain's spawn time
  • determine consumer chain parameters to be put in the proposal
  • take note to include a link to your onboarding repository
  • describe the purpose and benefits of running your chain

Example of a consumer chain addition proposal.

// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.
// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.
// It is recommended that spawn time occurs after the proposal end time.
{
// Title of the proposal
"title": "Add consumer chain",
// Description of the proposal
// format the text as a .md file and include the file in your onboarding repository
"description": ".md description of your chain and all other relevant information",
// Proposed chain-id of the new consumer chain.
// Must be unique from all other consumer chain ids of the executing provider chain.
"chain_id": "newchain-1",
// Initial height of new consumer chain.
// For a completely new chain, this will be {0,1}.
"initial_height" : {
"revision_height": 0,
"revision_number": 1,
},
// Hash of the consumer chain genesis state without the consumer CCV module genesis params.
// It is used for off-chain confirmation of genesis.json validity by validators and other parties.
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
// Hash of the consumer chain binary that should be run by validators on chain initialization.
// It is used for off-chain confirmation of binary validity by validators and other parties.
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
// Unbonding period for the consumer chain.
// It should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
// IBC transfer packets will timeout after this interval elapses.
"transfer_timeout_period": 1800000000000,
// The fraction of tokens allocated to the consumer redistribution address during distribution events.
// The fraction is a string representing a decimal number. For example "0.75" would represent 75%.
// The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.
"consumer_redistribution_fraction": "0.75",
// BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.
// eg. send rewards to the provider every 1000 blocks
"blocks_per_distribution_transmission": 1000,
// The number of historical info entries to persist in store.
// This param is a part of the cosmos sdk staking module. In the case of
// a ccv enabled consumer chain, the ccv module acts as the staking module.
"historical_entries": 10000,
// The ID of a token transfer channel used for the Reward Distribution
// sub-protocol. If DistributionTransmissionChannel == "", a new transfer
// channel is created on top of the same connection as the CCV channel.
// Note that transfer_channel_id is the ID of the channel end on the consumer chain.
// it is most relevant for chains performing a sovereign to consumer changeover
// in order to maintain the existing ibc transfer channel
"distribution_transmission_channel": "channel-123"
}

4. Launch

The consumer chain starts after at least 66.67% of all provider's voting power comes online. The consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer

  • provide a repo with onboarding instructions for validators (it should already be listed in the proposal)
  • genesis.json with ccv data populated (MUST contain the initial validator set)
  • maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)
  • have a block explorer in place to track chain activity & health
+ + + + \ No newline at end of file diff --git a/legacy/consumer-development/onboarding.html.html b/legacy/consumer-development/onboarding.html.html new file mode 100644 index 0000000000..8c2cd82112 --- /dev/null +++ b/legacy/consumer-development/onboarding.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/faq.html b/legacy/faq.html new file mode 100644 index 0000000000..c148f071cc --- /dev/null +++ b/legacy/faq.html @@ -0,0 +1,24 @@ + + + + + +Frequently Asked Questions | Interchain Security + + + + +
+
Version: Next

Frequently Asked Questions

What is the meaning of Validator Set Replication?

VSR simply means that the same validator set is used to secure both the provider and consumer chains. VSR is ensured through ICS protocol which keeps consumers up to date with the validator set of the provider.

What is a consumer chain?

Consumer chain is blockchain operated by the same validator operators as the provider chain. The ICS protocol ensures the validator set replication properties (informs consumer chain about the current state of the validator set on the provider)

Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements.

What happens to consumer if provider is down?

In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set.

The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness.

However, if the trusting_period (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain. +This means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about.

Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point. +At the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.

What happens to provider if consumer is down?

Consumer chains do not impact the provider chain. +The ICS protocol is concerned only with validator set replication and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events).

Can I run the provider and consumer chains on the same machine?

Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation.

Can the consumer chain have its own token?

As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees.

How are Tx fees paid on consumer?

The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations.

Are there any restrictions the consumer chains need to abide by?

No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way. +The only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain.

What's in it for the validators and stakers?

The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by consumer_redistribution_fraction. The rewards are distributed (sent to the provider) every blocks_per_distribution_transmission.

note

consumer_redistribution_fraction and blocks_per_distribution_transmission are parameters defined in the ConsumerAdditionProposal used to create the consumer chain. These parameters can be changed via consumer chain governance.

Can the consumer chain have its own governance?

Yes.

In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.

Validators can also be representatives but representatives are not required to run validator nodes.

This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance.

Can validators opt-out of replicated security?

At present, the validators cannot opt-out of validating consumer chains.

There are multiple opt-out mechanisms under active research.

How does Equivocation Governance Slashing work?

To avoid potential attacks directed at provider chain validators, a new mechanism was introduced:

When a validator double-signs on the consumer chain, a special type of slash packet is relayed to the provider chain. The provider will store information about the double signing validator and allow a governance proposal to be submitted. +If the double-signing proposal passes, the offending validator will be slashed on the provider chain and tombstoned. Tombstoning will permanently exclude the validator from the active set of the provider.

caution

An equivocation proposal cannot be submitted for a validator that did not double sign on any of the consumer chains.

Can Consumer Chains perform Software Upgrades?

Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM).

Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module.

How can I connect to the testnets?

Check out the Joining Replicated Security testnet section.

How do I start using ICS?

To become a consumer chain use this checklist and check the App integration section

Which relayers are supported?

Currently supported versions:

  • Hermes 1.4.1
  • Support for the CCV module was added to the Go relayer in v2.2.0 but v2.4.0 has significant performance fixes which makes it the earliest suggested version to use.

How does key delegation work in ICS?

You can check the Key Assignment Guide for specific instructions.

+ + + + \ No newline at end of file diff --git a/legacy/faq.html.html b/legacy/faq.html.html new file mode 100644 index 0000000000..5bf8f2f57f --- /dev/null +++ b/legacy/faq.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/features/key-assignment.html b/legacy/features/key-assignment.html new file mode 100644 index 0000000000..a68d3941ac --- /dev/null +++ b/legacy/features/key-assignment.html @@ -0,0 +1,20 @@ + + + + + +Key Assignment | Interchain Security + + + + +
+
Version: Next

Key Assignment

Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate. +There are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains.

The feature is outlined in this ADR-001

By sending an AssignConsumerKey transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator.

tip

Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity.

Rules

  • a key can be assigned before the consumer addition proposal passes on the provider
  • validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider
  • validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X
  • a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain
tip

Validators can use a different key for each consumer chain.

Adding a key

First, create a new node on the consumer chain using the equivalent:

consumerd init <moniker>

Then query your node for the consensus key.

consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}

Then, make an assign-consensus-key transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain.

gaiad tx provider assign-consensus-key <consumer-chain-id> '<pubkey>' --from <tx-signer> --home <home_dir> --gas 900000 -b sync -y -o json
  • consumer-chain-id is the string identifier of the consumer chain, as assigned on the provider chain
  • consumer-pub-key has the following format {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}

Check that the key was assigned correctly by querying the provider:

gaiad query provider validator-consumer-key <consumer-chain-id> cosmosvalcons1e....3xsj3ayzf4uv6

You must use a valcons address. You can obtain it by querying your node on the provider gaiad tendermint show-address

OR

gaiad query provider validator-provider-key <consumer-chain-id> consumervalcons1e....123asdnoaisdao

You must use a valcons address. You can obtain it by querying your node on the consumer consumerd tendermint show-address

Changing a key

To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied

Removing a key

To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the Adding a key section and using your provider consensus key.

+ + + + \ No newline at end of file diff --git a/legacy/features/key-assignment.html.html b/legacy/features/key-assignment.html.html new file mode 100644 index 0000000000..7f88dd4190 --- /dev/null +++ b/legacy/features/key-assignment.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/features/proposals.html b/legacy/features/proposals.html new file mode 100644 index 0000000000..f9dd0f7b43 --- /dev/null +++ b/legacy/features/proposals.html @@ -0,0 +1,26 @@ + + + + + +ICS Provider Proposals | Interchain Security + + + + +
+
Version: Next

ICS Provider Proposals

Interchain security module introduces 3 new proposal types to the provider.

The proposals are used to propose upcoming interchain security events through governance.

ConsumerAdditionProposal

info

If you are preparing a ConsumerAdditionProposal you can find more information in the consumer onboarding checklist.

Proposal type used to suggest adding a new consumer chain.

When proposals of this type are passed and the spawn_time specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain.

Minimal example:

{
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
"title": "Add consumer chain",
"description": ".md description of your chain and all other relevant information",
"chain_id": "newchain-1",
"initial_height" : {
"revision_height": 0,
"revision_number": 1,
},
// Unbonding period for the consumer chain.
// It should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
"transfer_timeout_period": 1800000000000,
"consumer_redistribution_fraction": "0.75",
"blocks_per_distribution_transmission": 1000,
"historical_entries": 10000,
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1"
// relevant for chains performing a sovereign to consumer changeover
// in order to maintain the existing ibc transfer channel
"distribution_transmission_channel": "channel-123"
}

More examples can be found in the replicated security testnet repository here and here.

ConsumerRemovalProposal

Proposal type used to suggest removing an existing consumer chain.

When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain. +After the consumer chain removal, the chain in question will no longer be secured by the provider's validator set.

info

The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain. +Additional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set. +More information will be made available in the Consumer Offboarding Checklist.

Minimal example:

{
// the time on the provider chain at which all validators are responsible to stop their consumer chain validator node
"stop_time": "2023-03-07T12:40:00.000000Z",
// the chain-id of the consumer chain to be stopped
"chain_id": "consumerchain-1",
"title": "This was a great chain",
"description": "Here is a .md formatted string specifying removal details"
}

EquivocationProposal

tip

EquivocationProposal will only be accepted on the provider chain if at least one of the consumer chains submits equivocation evidence to the provider. +Sending equivocation evidence to the provider is handled automatically by the interchain security protocol when an equivocation infraction is detected on the consumer chain.

Proposal type used to suggest slashing a validator for double signing on consumer chain. +When proposals of this type are passed, the validator in question will be slashed for equivocation on the provider chain.

danger

Take note that an equivocation slash causes a validator to be tombstoned (can never re-enter the active set). +Tombstoning a validator on the provider chain will remove the validator from the validator set of all consumer chains.

Minimal example:

{
"title": "Validator-1 double signed on consumerchain-1",
"description": "Here is more information about the infraction so you can verify it yourself",
// the list of equivocations that will be processed
"equivocations": [
{
"height": 14444680,
"time": "2023-02-28T20:40:00.000000Z",
"power": 5500000,
"consensus_address": "<consensus address ON THE PROVIDER>"
}
]
}

ChangeRewardDenomProposal

tip

ChangeRewardDenomProposal will only be accepted on the provider chain if at least one of the denomsToAdd or denomsToRemove fields is populated with at least one denom. Also, a denom cannot be repeated in both sets.

Proposal type used to mutate the set of denoms accepted by the provider as rewards.

Minimal example:

{
"title": "Add untrn as a reward denom",
"description": "Here is more information about the proposal",
"denomsToAdd": ["untrn"],
"denomsToRemove": []
}

Notes

When submitting equivocation evidence through an EquivocationProposal please take note that you need to use the consensus address (valcons) of the offending validator on the provider chain. +Besides that, the height and the time fields should be mapped to the provider chain to avoid your evidence being rejected.

Before submitting the proposal please check that the evidence is not outdated by comparing the infraction height with the max_age_duration and max_age_num_blocks consensus parameters of the provider chain.

Gaia example:

➜  ~ cat genesis.json | jq ".consensus_params"
{
"block": {
...
},
"evidence": {
"max_age_duration": "172800000000000",
"max_age_num_blocks": "1000000",
"max_bytes": "50000"
},
"validator": {
...
},
"version": {}
}

Any EquivocationProposal transactions that submit evidence with height older than max_age_num_blocks and time older than max_age_duration will be considered invalid.

+ + + + \ No newline at end of file diff --git a/legacy/features/proposals.html.html b/legacy/features/proposals.html.html new file mode 100644 index 0000000000..f9e8a09db3 --- /dev/null +++ b/legacy/features/proposals.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/features/reward-distribution.html b/legacy/features/reward-distribution.html new file mode 100644 index 0000000000..280fa2450f --- /dev/null +++ b/legacy/features/reward-distribution.html @@ -0,0 +1,25 @@ + + + + + +Reward distribution | Interchain Security + + + + +
+
Version: Next

Reward distribution

Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators. +In replicated security block rewards and fees are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel that gets created during consumer chain initialization.

Reward distribution on the provider is handled by the distribution module - validators and delegators receive a fraction of the consumer chain tokens as staking rewards. +The distributed reward tokens are IBC tokens and therefore cannot be staked on the provider chain.

Sending and distributing rewards from consumer chains to provider chain is handled by the Reward Distribution sub-protocol.

Note

The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the ConsumerRewardsPool. +There is a new transaction type called RegisterConsumerRewardDenom. This transaction allows consumer chains to register denoms to be used as consumer chain rewards on the provider. +The cost to register a denom is configurable (ConsumerRewardDenomRegistrationFee chain param) and the full amount of this fee is transferred to the community pool of the provider chain. Only denoms registered through this transaction are then transferred from the ConsumerRewardsPool to the FeePoolAddress, to be distributed out to delegators and validators.

Instructions for adding a denom

The transaction must be carried out on the provider chain. Please use the ibc/* denom trace format.

tip
# reward denoms must be registered on the provider chain (gaia in this example)
gaiad tx provider register-consumer-reward-denom ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9 --from mykey

Parameters

tip

The following chain parameters dictate consumer chain distribution amount and frequency. +They are set at consumer genesis and blocks_per_distribution_transmission, consumer_redistribution_fraction +transfer_timeout_period must be provided in every ConsumerChainAddition proposal.

consumer_redistribution_fraction

The fraction of tokens allocated to the consumer redistribution address during distribution events. The fraction is a string representing a decimal number. For example "0.75" would represent 75%.

tip

Example:

With consumer_redistribution_fraction set to 0.75 the consumer chain would send 75% of its block rewards and accumulated fees to the consumer redistribution address, and the remaining 25% to the provider chain every n blocks where n == blocks_per_distribution_transmission.

blocks_per_distribution_transmission

The number of blocks between IBC token transfers from the consumer chain to the provider chain.

transfer_timeout_period

Timeout period for consumer chain reward distribution IBC packets.

distribution_transmission_channel

Provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.

provider_fee_pool_addr_str

Provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.

+ + + + \ No newline at end of file diff --git a/legacy/features/reward-distribution.html.html b/legacy/features/reward-distribution.html.html new file mode 100644 index 0000000000..660b7ed24c --- /dev/null +++ b/legacy/features/reward-distribution.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/features/slashing.html b/legacy/features/slashing.html new file mode 100644 index 0000000000..1df65ad5f1 --- /dev/null +++ b/legacy/features/slashing.html @@ -0,0 +1,22 @@ + + + + + +Consumer Initiated Slashing | Interchain Security + + + + +
+
Version: Next

Consumer Initiated Slashing

A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain. +In essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake).

To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized. +Any infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains.

In the current implementation there are 2 important changes brought by the interchain security module:

Downtime infractions

reported by consumer chains are acted upon on the provider as soon as the provider receives the infraction evidence.

Instead of slashing, the provider will only jail offending validator for the duration of time established in the chain parameters.

info

Slash throttling (sometimes called jail throttling) mechanism ensures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider.

Double-signing (equivocation)

infractions are not acted upon immediately.

Upon receiving double signing evidence, the provider chain will take note of the evidence and allow for EquivocationProposal to be submitted to slash the offending validator. +Any EquivocationProposals to slash a validator that has not double signed on any of the consumer chains will be automatically rejected by the provider chain.

info

The offending validator will only be slashed (and tombstoned) if an EquivocationProposal is accepted and passed through governance.

The offending validator will effectively get slashed and tombstoned on all consumer chains.

You can find instructions on creating EquivocationProposals here.

+ + + + \ No newline at end of file diff --git a/legacy/features/slashing.html.html b/legacy/features/slashing.html.html new file mode 100644 index 0000000000..07995c0ada --- /dev/null +++ b/legacy/features/slashing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/fonts/inter/Inter-Black.woff b/legacy/fonts/inter/Inter-Black.woff new file mode 100644 index 0000000000..a18593a096 Binary files /dev/null and b/legacy/fonts/inter/Inter-Black.woff differ diff --git a/legacy/fonts/inter/Inter-Black.woff2 b/legacy/fonts/inter/Inter-Black.woff2 new file mode 100644 index 0000000000..68f64c9ed9 Binary files /dev/null and b/legacy/fonts/inter/Inter-Black.woff2 differ diff --git a/legacy/fonts/inter/Inter-BlackItalic.woff b/legacy/fonts/inter/Inter-BlackItalic.woff new file mode 100644 index 0000000000..b6b01943d9 Binary files /dev/null and b/legacy/fonts/inter/Inter-BlackItalic.woff differ diff --git a/legacy/fonts/inter/Inter-BlackItalic.woff2 b/legacy/fonts/inter/Inter-BlackItalic.woff2 new file mode 100644 index 0000000000..1c9c7ca8b0 Binary files /dev/null and b/legacy/fonts/inter/Inter-BlackItalic.woff2 differ diff --git a/legacy/fonts/inter/Inter-Bold.woff b/legacy/fonts/inter/Inter-Bold.woff new file mode 100644 index 0000000000..eaf3d4bfd7 Binary files /dev/null and b/legacy/fonts/inter/Inter-Bold.woff differ diff --git a/legacy/fonts/inter/Inter-Bold.woff2 b/legacy/fonts/inter/Inter-Bold.woff2 new file mode 100644 index 0000000000..2846f29cc8 Binary files /dev/null and b/legacy/fonts/inter/Inter-Bold.woff2 differ diff --git a/legacy/fonts/inter/Inter-BoldItalic.woff b/legacy/fonts/inter/Inter-BoldItalic.woff new file mode 100644 index 0000000000..3275076164 Binary files /dev/null and b/legacy/fonts/inter/Inter-BoldItalic.woff differ diff --git a/legacy/fonts/inter/Inter-BoldItalic.woff2 b/legacy/fonts/inter/Inter-BoldItalic.woff2 new file mode 100644 index 0000000000..0b1fe8e125 Binary files /dev/null and b/legacy/fonts/inter/Inter-BoldItalic.woff2 differ diff --git a/legacy/fonts/inter/Inter-ExtraBold.woff b/legacy/fonts/inter/Inter-ExtraBold.woff new file mode 100644 index 0000000000..c2c17edead Binary files /dev/null and b/legacy/fonts/inter/Inter-ExtraBold.woff differ diff --git a/legacy/fonts/inter/Inter-ExtraBold.woff2 b/legacy/fonts/inter/Inter-ExtraBold.woff2 new file mode 100644 index 0000000000..c24c2bdc2f Binary files /dev/null and b/legacy/fonts/inter/Inter-ExtraBold.woff2 differ diff --git a/legacy/fonts/inter/Inter-ExtraBoldItalic.woff b/legacy/fonts/inter/Inter-ExtraBoldItalic.woff new file mode 100644 index 0000000000..c42f70526c Binary files /dev/null and b/legacy/fonts/inter/Inter-ExtraBoldItalic.woff differ diff --git a/legacy/fonts/inter/Inter-ExtraBoldItalic.woff2 b/legacy/fonts/inter/Inter-ExtraBoldItalic.woff2 new file mode 100644 index 0000000000..4a81dc7982 Binary files /dev/null and b/legacy/fonts/inter/Inter-ExtraBoldItalic.woff2 differ diff --git a/legacy/fonts/inter/Inter-ExtraLight.woff b/legacy/fonts/inter/Inter-ExtraLight.woff new file mode 100644 index 0000000000..d0de5f3973 Binary files /dev/null and b/legacy/fonts/inter/Inter-ExtraLight.woff differ diff --git a/legacy/fonts/inter/Inter-ExtraLight.woff2 b/legacy/fonts/inter/Inter-ExtraLight.woff2 new file mode 100644 index 0000000000..f2ea706faf Binary files /dev/null and b/legacy/fonts/inter/Inter-ExtraLight.woff2 differ diff --git a/legacy/fonts/inter/Inter-ExtraLightItalic.woff b/legacy/fonts/inter/Inter-ExtraLightItalic.woff new file mode 100644 index 0000000000..81f1a28ef5 Binary files /dev/null and b/legacy/fonts/inter/Inter-ExtraLightItalic.woff differ diff --git a/legacy/fonts/inter/Inter-ExtraLightItalic.woff2 b/legacy/fonts/inter/Inter-ExtraLightItalic.woff2 new file mode 100644 index 0000000000..9af717ba91 Binary files /dev/null and b/legacy/fonts/inter/Inter-ExtraLightItalic.woff2 differ diff --git a/legacy/fonts/inter/Inter-Italic.woff b/legacy/fonts/inter/Inter-Italic.woff new file mode 100644 index 0000000000..a806b38201 Binary files /dev/null and b/legacy/fonts/inter/Inter-Italic.woff differ diff --git a/legacy/fonts/inter/Inter-Italic.woff2 b/legacy/fonts/inter/Inter-Italic.woff2 new file mode 100644 index 0000000000..a619fc5486 Binary files /dev/null and b/legacy/fonts/inter/Inter-Italic.woff2 differ diff --git a/legacy/fonts/inter/Inter-Light.woff b/legacy/fonts/inter/Inter-Light.woff new file mode 100644 index 0000000000..c496464d02 Binary files /dev/null and b/legacy/fonts/inter/Inter-Light.woff differ diff --git a/legacy/fonts/inter/Inter-Light.woff2 b/legacy/fonts/inter/Inter-Light.woff2 new file mode 100644 index 0000000000..bc4be6658b Binary files /dev/null and b/legacy/fonts/inter/Inter-Light.woff2 differ diff --git a/legacy/fonts/inter/Inter-LightItalic.woff b/legacy/fonts/inter/Inter-LightItalic.woff new file mode 100644 index 0000000000..f84a9de35e Binary files /dev/null and b/legacy/fonts/inter/Inter-LightItalic.woff differ diff --git a/legacy/fonts/inter/Inter-LightItalic.woff2 b/legacy/fonts/inter/Inter-LightItalic.woff2 new file mode 100644 index 0000000000..842b2dfcb7 Binary files /dev/null and b/legacy/fonts/inter/Inter-LightItalic.woff2 differ diff --git a/legacy/fonts/inter/Inter-Medium.woff b/legacy/fonts/inter/Inter-Medium.woff new file mode 100644 index 0000000000..d546843f28 Binary files /dev/null and b/legacy/fonts/inter/Inter-Medium.woff differ diff --git a/legacy/fonts/inter/Inter-Medium.woff2 b/legacy/fonts/inter/Inter-Medium.woff2 new file mode 100644 index 0000000000..f92498a2ec Binary files /dev/null and b/legacy/fonts/inter/Inter-Medium.woff2 differ diff --git a/legacy/fonts/inter/Inter-MediumItalic.woff b/legacy/fonts/inter/Inter-MediumItalic.woff new file mode 100644 index 0000000000..459a656889 Binary files /dev/null and b/legacy/fonts/inter/Inter-MediumItalic.woff differ diff --git a/legacy/fonts/inter/Inter-MediumItalic.woff2 b/legacy/fonts/inter/Inter-MediumItalic.woff2 new file mode 100644 index 0000000000..0e3019f4ae Binary files /dev/null and b/legacy/fonts/inter/Inter-MediumItalic.woff2 differ diff --git a/legacy/fonts/inter/Inter-Regular.woff b/legacy/fonts/inter/Inter-Regular.woff new file mode 100644 index 0000000000..62d3a61871 Binary files /dev/null and b/legacy/fonts/inter/Inter-Regular.woff differ diff --git a/legacy/fonts/inter/Inter-Regular.woff2 b/legacy/fonts/inter/Inter-Regular.woff2 new file mode 100644 index 0000000000..6c2b6893d5 Binary files /dev/null and b/legacy/fonts/inter/Inter-Regular.woff2 differ diff --git a/legacy/fonts/inter/Inter-SemiBold.woff b/legacy/fonts/inter/Inter-SemiBold.woff new file mode 100644 index 0000000000..a815f43a91 Binary files /dev/null and b/legacy/fonts/inter/Inter-SemiBold.woff differ diff --git a/legacy/fonts/inter/Inter-SemiBold.woff2 b/legacy/fonts/inter/Inter-SemiBold.woff2 new file mode 100644 index 0000000000..611e90c958 Binary files /dev/null and b/legacy/fonts/inter/Inter-SemiBold.woff2 differ diff --git a/legacy/fonts/inter/Inter-SemiBoldItalic.woff b/legacy/fonts/inter/Inter-SemiBoldItalic.woff new file mode 100644 index 0000000000..909e43a97d Binary files /dev/null and b/legacy/fonts/inter/Inter-SemiBoldItalic.woff differ diff --git a/legacy/fonts/inter/Inter-SemiBoldItalic.woff2 b/legacy/fonts/inter/Inter-SemiBoldItalic.woff2 new file mode 100644 index 0000000000..545685bd2c Binary files /dev/null and b/legacy/fonts/inter/Inter-SemiBoldItalic.woff2 differ diff --git a/legacy/fonts/inter/Inter-Thin.woff b/legacy/fonts/inter/Inter-Thin.woff new file mode 100644 index 0000000000..62bc58cd14 Binary files /dev/null and b/legacy/fonts/inter/Inter-Thin.woff differ diff --git a/legacy/fonts/inter/Inter-Thin.woff2 b/legacy/fonts/inter/Inter-Thin.woff2 new file mode 100644 index 0000000000..abbc3a5c96 Binary files /dev/null and b/legacy/fonts/inter/Inter-Thin.woff2 differ diff --git a/legacy/fonts/inter/Inter-ThinItalic.woff b/legacy/fonts/inter/Inter-ThinItalic.woff new file mode 100644 index 0000000000..700a7f069b Binary files /dev/null and b/legacy/fonts/inter/Inter-ThinItalic.woff differ diff --git a/legacy/fonts/inter/Inter-ThinItalic.woff2 b/legacy/fonts/inter/Inter-ThinItalic.woff2 new file mode 100644 index 0000000000..ab0b2002a3 Binary files /dev/null and b/legacy/fonts/inter/Inter-ThinItalic.woff2 differ diff --git a/legacy/fonts/inter/Inter-italic.var.woff2 b/legacy/fonts/inter/Inter-italic.var.woff2 new file mode 100644 index 0000000000..b826d5af84 Binary files /dev/null and b/legacy/fonts/inter/Inter-italic.var.woff2 differ diff --git a/legacy/fonts/inter/Inter-roman.var.woff2 b/legacy/fonts/inter/Inter-roman.var.woff2 new file mode 100644 index 0000000000..6a256a068f Binary files /dev/null and b/legacy/fonts/inter/Inter-roman.var.woff2 differ diff --git a/legacy/fonts/intervar/Inter.var.woff2 b/legacy/fonts/intervar/Inter.var.woff2 new file mode 100644 index 0000000000..365eedc50c Binary files /dev/null and b/legacy/fonts/intervar/Inter.var.woff2 differ diff --git a/legacy/fonts/jetbrainsmono/JetBrainsMono-Bold.woff2 b/legacy/fonts/jetbrainsmono/JetBrainsMono-Bold.woff2 new file mode 100644 index 0000000000..023512c051 Binary files /dev/null and b/legacy/fonts/jetbrainsmono/JetBrainsMono-Bold.woff2 differ diff --git a/legacy/fonts/jetbrainsmono/JetBrainsMono-BoldItalic.woff2 b/legacy/fonts/jetbrainsmono/JetBrainsMono-BoldItalic.woff2 new file mode 100644 index 0000000000..f3e87a35ab Binary files /dev/null and b/legacy/fonts/jetbrainsmono/JetBrainsMono-BoldItalic.woff2 differ diff --git a/legacy/fonts/jetbrainsmono/JetBrainsMono-ExtraBold.woff2 b/legacy/fonts/jetbrainsmono/JetBrainsMono-ExtraBold.woff2 new file mode 100644 index 0000000000..a8b78a9c17 Binary files /dev/null and b/legacy/fonts/jetbrainsmono/JetBrainsMono-ExtraBold.woff2 differ diff --git a/legacy/fonts/jetbrainsmono/JetBrainsMono-ExtraBoldItalic.woff2 b/legacy/fonts/jetbrainsmono/JetBrainsMono-ExtraBoldItalic.woff2 new file mode 100644 index 0000000000..b54a2d5beb Binary files /dev/null and b/legacy/fonts/jetbrainsmono/JetBrainsMono-ExtraBoldItalic.woff2 differ diff --git a/legacy/fonts/jetbrainsmono/JetBrainsMono-ExtraLight.woff2 b/legacy/fonts/jetbrainsmono/JetBrainsMono-ExtraLight.woff2 new file mode 100644 index 0000000000..edd6a68c06 Binary files /dev/null and b/legacy/fonts/jetbrainsmono/JetBrainsMono-ExtraLight.woff2 differ diff --git a/legacy/fonts/jetbrainsmono/JetBrainsMono-ExtraLightItalic.woff2 b/legacy/fonts/jetbrainsmono/JetBrainsMono-ExtraLightItalic.woff2 new file mode 100644 index 0000000000..2a02a18e64 Binary files /dev/null and b/legacy/fonts/jetbrainsmono/JetBrainsMono-ExtraLightItalic.woff2 differ diff --git a/legacy/fonts/jetbrainsmono/JetBrainsMono-Italic.woff2 b/legacy/fonts/jetbrainsmono/JetBrainsMono-Italic.woff2 new file mode 100644 index 0000000000..e8eeb4b8e8 Binary files /dev/null and b/legacy/fonts/jetbrainsmono/JetBrainsMono-Italic.woff2 differ diff --git a/legacy/fonts/jetbrainsmono/JetBrainsMono-Light.woff2 b/legacy/fonts/jetbrainsmono/JetBrainsMono-Light.woff2 new file mode 100644 index 0000000000..459bacf498 Binary files /dev/null and b/legacy/fonts/jetbrainsmono/JetBrainsMono-Light.woff2 differ diff --git a/legacy/fonts/jetbrainsmono/JetBrainsMono-LightItalic.woff2 b/legacy/fonts/jetbrainsmono/JetBrainsMono-LightItalic.woff2 new file mode 100644 index 0000000000..352f5d95a6 Binary files /dev/null and b/legacy/fonts/jetbrainsmono/JetBrainsMono-LightItalic.woff2 differ diff --git a/legacy/fonts/jetbrainsmono/JetBrainsMono-Medium.woff2 b/legacy/fonts/jetbrainsmono/JetBrainsMono-Medium.woff2 new file mode 100644 index 0000000000..484c9e6415 Binary files /dev/null and b/legacy/fonts/jetbrainsmono/JetBrainsMono-Medium.woff2 differ diff --git a/legacy/fonts/jetbrainsmono/JetBrainsMono-MediumItalic.woff2 b/legacy/fonts/jetbrainsmono/JetBrainsMono-MediumItalic.woff2 new file mode 100644 index 0000000000..e1279949e0 Binary files /dev/null and b/legacy/fonts/jetbrainsmono/JetBrainsMono-MediumItalic.woff2 differ diff --git a/legacy/fonts/jetbrainsmono/JetBrainsMono-Regular.woff2 b/legacy/fonts/jetbrainsmono/JetBrainsMono-Regular.woff2 new file mode 100644 index 0000000000..8c862e334d Binary files /dev/null and b/legacy/fonts/jetbrainsmono/JetBrainsMono-Regular.woff2 differ diff --git a/legacy/fonts/jetbrainsmono/JetBrainsMono-SemiBold.woff2 b/legacy/fonts/jetbrainsmono/JetBrainsMono-SemiBold.woff2 new file mode 100644 index 0000000000..fce8cd8053 Binary files /dev/null and b/legacy/fonts/jetbrainsmono/JetBrainsMono-SemiBold.woff2 differ diff --git a/legacy/fonts/jetbrainsmono/JetBrainsMono-SemiBoldItalic.woff2 b/legacy/fonts/jetbrainsmono/JetBrainsMono-SemiBoldItalic.woff2 new file mode 100644 index 0000000000..a14851f6bb Binary files /dev/null and b/legacy/fonts/jetbrainsmono/JetBrainsMono-SemiBoldItalic.woff2 differ diff --git a/legacy/fonts/jetbrainsmono/JetBrainsMono-Thin.woff2 b/legacy/fonts/jetbrainsmono/JetBrainsMono-Thin.woff2 new file mode 100644 index 0000000000..7c6127875f Binary files /dev/null and b/legacy/fonts/jetbrainsmono/JetBrainsMono-Thin.woff2 differ diff --git a/legacy/fonts/jetbrainsmono/JetBrainsMono-ThinItalic.woff2 b/legacy/fonts/jetbrainsmono/JetBrainsMono-ThinItalic.woff2 new file mode 100644 index 0000000000..0676ba8a56 Binary files /dev/null and b/legacy/fonts/jetbrainsmono/JetBrainsMono-ThinItalic.woff2 differ diff --git a/legacy/img/acceptance-tests.png b/legacy/img/acceptance-tests.png new file mode 100644 index 0000000000..b85d7da7d0 Binary files /dev/null and b/legacy/img/acceptance-tests.png differ diff --git a/legacy/img/android-chrome-192x192.png b/legacy/img/android-chrome-192x192.png new file mode 100644 index 0000000000..6d04cf4c08 Binary files /dev/null and b/legacy/img/android-chrome-192x192.png differ diff --git a/legacy/img/android-chrome-256x256.png b/legacy/img/android-chrome-256x256.png new file mode 100644 index 0000000000..1c30cc0267 Binary files /dev/null and b/legacy/img/android-chrome-256x256.png differ diff --git a/legacy/img/apple-touch-icon.png b/legacy/img/apple-touch-icon.png new file mode 100644 index 0000000000..397e21af2a Binary files /dev/null and b/legacy/img/apple-touch-icon.png differ diff --git a/legacy/img/banner.jpg b/legacy/img/banner.jpg new file mode 100644 index 0000000000..9d8219317f Binary files /dev/null and b/legacy/img/banner.jpg differ diff --git a/legacy/img/docusaurus-social-card.jpg b/legacy/img/docusaurus-social-card.jpg new file mode 100644 index 0000000000..ffcb448210 Binary files /dev/null and b/legacy/img/docusaurus-social-card.jpg differ diff --git a/legacy/img/docusaurus.png b/legacy/img/docusaurus.png new file mode 100644 index 0000000000..f458149e3c Binary files /dev/null and b/legacy/img/docusaurus.png differ diff --git a/legacy/img/favicon-16x16.png b/legacy/img/favicon-16x16.png new file mode 100644 index 0000000000..5f15c3b0af Binary files /dev/null and b/legacy/img/favicon-16x16.png differ diff --git a/legacy/img/favicon-32x32.png b/legacy/img/favicon-32x32.png new file mode 100644 index 0000000000..9433c807fd Binary files /dev/null and b/legacy/img/favicon-32x32.png differ diff --git a/legacy/img/favicon-dark.svg b/legacy/img/favicon-dark.svg new file mode 100644 index 0000000000..a4f0fac959 --- /dev/null +++ b/legacy/img/favicon-dark.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/legacy/img/favicon.ico b/legacy/img/favicon.ico new file mode 100644 index 0000000000..c01d54bcd3 Binary files /dev/null and b/legacy/img/favicon.ico differ diff --git a/legacy/img/favicon.svg b/legacy/img/favicon.svg new file mode 100644 index 0000000000..dbefbad9f4 --- /dev/null +++ b/legacy/img/favicon.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/legacy/img/ico-chevron.svg b/legacy/img/ico-chevron.svg new file mode 100644 index 0000000000..3f8e8fac11 --- /dev/null +++ b/legacy/img/ico-chevron.svg @@ -0,0 +1,3 @@ + + + diff --git a/legacy/img/ico-github.svg b/legacy/img/ico-github.svg new file mode 100644 index 0000000000..a74bee5aed --- /dev/null +++ b/legacy/img/ico-github.svg @@ -0,0 +1,3 @@ + + + diff --git a/legacy/img/logo copy.svg b/legacy/img/logo copy.svg new file mode 100644 index 0000000000..95ca6d30da --- /dev/null +++ b/legacy/img/logo copy.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/legacy/img/logo-bw.svg b/legacy/img/logo-bw.svg new file mode 100644 index 0000000000..f2575260a7 --- /dev/null +++ b/legacy/img/logo-bw.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/legacy/img/logo-sdk.svg b/legacy/img/logo-sdk.svg new file mode 100644 index 0000000000..444eff2ab3 --- /dev/null +++ b/legacy/img/logo-sdk.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/legacy/img/logo.svg b/legacy/img/logo.svg new file mode 100644 index 0000000000..9db6d0d066 --- /dev/null +++ b/legacy/img/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/legacy/img/undraw_docusaurus_mountain.svg b/legacy/img/undraw_docusaurus_mountain.svg new file mode 100644 index 0000000000..af961c49a8 --- /dev/null +++ b/legacy/img/undraw_docusaurus_mountain.svg @@ -0,0 +1,171 @@ + + Easy to Use + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/legacy/img/undraw_docusaurus_react.svg b/legacy/img/undraw_docusaurus_react.svg new file mode 100644 index 0000000000..94b5cf08f8 --- /dev/null +++ b/legacy/img/undraw_docusaurus_react.svg @@ -0,0 +1,170 @@ + + Powered by React + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/legacy/img/undraw_docusaurus_tree.svg b/legacy/img/undraw_docusaurus_tree.svg new file mode 100644 index 0000000000..d9161d3392 --- /dev/null +++ b/legacy/img/undraw_docusaurus_tree.svg @@ -0,0 +1,40 @@ + + Focus on What Matters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/legacy/index.html b/legacy/index.html new file mode 100644 index 0000000000..ef68ea48a8 --- /dev/null +++ b/legacy/index.html @@ -0,0 +1,19 @@ + + + + + +Interchain Security Docs | Interchain Security + + + + + + + + + \ No newline at end of file diff --git a/legacy/introduction/overview.html b/legacy/introduction/overview.html new file mode 100644 index 0000000000..a4d0c10c47 --- /dev/null +++ b/legacy/introduction/overview.html @@ -0,0 +1,19 @@ + + + + + +Overview | Interchain Security + + + + +
+
Version: Next

Overview

info

Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.


Replicated security allows anyone to launch a "consumer" blockchain using the same validator set as the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit the full security and decentralization of the provider.

Why Replicated Security?

  • Full provider security. At launch, consumer chains are secured by the full validator set and market cap of the provider chain.
  • Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum.
  • Projects keep majority of gas fees. Depending on configuration, these fees either go to the project’s community DAO, or can be used in the protocol in other ways.
  • No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. A governance vote will take place for a chain to get adopted by the provider validators which will encourage participation and signal strong buy-in into the project's long-term success.
  • Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set.

Core protocol

info

Protocol specification is available as ICS-028 in the IBC repository.

Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer.

To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider.

Downtime Slashing

If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period.

Equivocation (Double Sign) Slashing

Evidence of equivocation must be submitted to provider governance and be voted on. This behavior is an extra safeguard before a validator is slashed, and may be replaced by a more automated system in the future.

Tokenomics and Rewards

Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance.

+ + + + \ No newline at end of file diff --git a/legacy/introduction/overview.html.html b/legacy/introduction/overview.html.html new file mode 100644 index 0000000000..58eb1f564e --- /dev/null +++ b/legacy/introduction/overview.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/introduction/params.html b/legacy/introduction/params.html new file mode 100644 index 0000000000..ae0ce37824 --- /dev/null +++ b/legacy/introduction/params.html @@ -0,0 +1,21 @@ + + + + + +Interchain Security Parameters | Interchain Security + + + + +
+
Version: Next

Interchain Security Parameters

The parameters necessary for Interchain Security (ICS) are defined in

  • the Params structure in proto/interchain_security/ccv/provider/v1/provider.proto for the provider;
  • the Params structure in proto/interchain_security/ccv/consumer/v1/consumer.proto for the consumer.

Time-based parameters

ICS relies on the following time-based parameters.

ProviderUnbondingPeriod

is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance.

ConsumerUnbondingPeriod

is the unbonding period on the consumer chain.

info

ConsumerUnbondingPeriod is set via the ConsumerAdditionProposal governance proposal to add a new consumer chain. +It is recommended that every consumer chain set and unbonding period shorter than ProviderUnbondingPeriod


Example:

ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day

Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer.

TrustingPeriodFraction

is used to calculate the TrustingPeriod of created IBC clients on both provider and consumer chains.

Setting TrustingPeriodFraction to 0.5 would result in the following:

TrustingPeriodFraction = 0.5
ProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5
ConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5

Note that a light clients must be updated within the TrustingPeriod in order to avoid being frozen.

For more details, see the IBC specification of Tendermint clients.

CCVTimeoutPeriod

is the period used to compute the timeout timestamp when sending IBC packets.

For more details, see the IBC specification of Channel & Packet Semantics.

danger

If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed.

CCVTimeoutPeriod may have different values on the provider and consumer chains.

  • CCVTimeoutPeriod on the provider must be larger than ConsumerUnbondingPeriod
  • CCVTimeoutPeriod on the consumer is initial set via the ConsumerAdditionProposal

InitTimeoutPeriod

is the maximum allowed duration for CCV channel initialization to execute.

For any consumer chain, if the CCV channel is not established within InitTimeoutPeriod then the consumer chain will be removed and therefore will not be secured by the provider chain.

The countdown starts when the spawn_time specified in the ConsumerAdditionProposal is reached.

VscTimeoutPeriod

is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live. +If the VscTimeoutPeriod is ever reached for a consumer chain that chain will be considered not live and removed from interchain security.

tip

VscTimeoutPeriod MUST be larger than the ConsumerUnbondingPeriod.

BlocksPerDistributionTransmission

is the number of blocks between rewards transfers from the consumer to the provider.

TransferPeriodTimeout

is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider.

If this timeout expires, then the transfer is attempted again after BlocksPerDistributionTransmission blocks.

  • TransferPeriodTimeout on the consumer is initial set via the ConsumerAdditionProposal gov proposal to add the consumer
  • TransferPeriodTimeout should be smaller than BlocksPerDistributionTransmission x avg_block_time

Slash Throttle Parameters

SlashMeterReplenishPeriod

exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed.

The meter is replenished to an amount equal to the slash meter allowance for that block, or SlashMeterReplenishFraction * CurrentTotalVotingPower.

SlashMeterReplenishFraction

exists on the provider as the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs.

This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a sdk.Dec when used.

MaxThrottledPackets

exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value.

This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness.

+ + + + \ No newline at end of file diff --git a/legacy/introduction/params.html.html b/legacy/introduction/params.html.html new file mode 100644 index 0000000000..b26ba588e2 --- /dev/null +++ b/legacy/introduction/params.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/introduction/technical-specification.html b/legacy/introduction/technical-specification.html new file mode 100644 index 0000000000..aa09cd2d3a --- /dev/null +++ b/legacy/introduction/technical-specification.html @@ -0,0 +1,19 @@ + + + + + +Technical Specification | Interchain Security + + + + +
+
Version: Next

Technical Specification

For a technical deep dive into the replicated security protocol, see the specification.

+ + + + \ No newline at end of file diff --git a/legacy/introduction/technical-specification.html.html b/legacy/introduction/technical-specification.html.html new file mode 100644 index 0000000000..03085db0c5 --- /dev/null +++ b/legacy/introduction/technical-specification.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/introduction/terminology.html b/legacy/introduction/terminology.html new file mode 100644 index 0000000000..dd62a59578 --- /dev/null +++ b/legacy/introduction/terminology.html @@ -0,0 +1,20 @@ + + + + + +Terminology | Interchain Security + + + + +
+
Version: Next

Terminology

You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.

Shared Security

Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share its proof-of-stake security with another blockchain or off-chain process.

Interchain Security

Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC.

Replicated Security

A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC. Note this documentation is focused on explaining the concepts from replicated security.

Mesh security

A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see Replicated vs. Mesh Security on the Informal Blog.

Consumer Chain

Chain that is secured by the validator set of the provider, instead of its own. +Replicated security allows the provider chain validator set to validate blocks on the consumer chain.

Standalone Chain

Chain that is secured by its own validator set. This chain does not participate in replicated security.

Standalone chains may sometimes be called "sovereign" - the terms are synonymous.

Changeover Procedure

Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.

+ + + + \ No newline at end of file diff --git a/legacy/introduction/terminology.html.html b/legacy/introduction/terminology.html.html new file mode 100644 index 0000000000..9940d965ab --- /dev/null +++ b/legacy/introduction/terminology.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/main/index.html b/legacy/main/index.html new file mode 100644 index 0000000000..2564e836e2 --- /dev/null +++ b/legacy/main/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/sitemap.xml b/legacy/sitemap.xml new file mode 100644 index 0000000000..f1fbd3e149 --- /dev/null +++ b/legacy/sitemap.xml @@ -0,0 +1 @@ +https://cosmos.github.io/interchain-security/legacy/v2.0.0weekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/adrs/adr-001-key-assignmentweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/adrs/adr-002-throttleweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/adrs/adr-003-equivocation-gov-proposalweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/adrs/adr-templateweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/adrs/introweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/consumer-development/app-integrationweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/consumer-development/consumer-chain-governanceweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/consumer-development/consumer-chain-upgrade-procedureweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/consumer-development/offboardingweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/consumer-development/onboardingweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/faqweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/features/key-assignmentweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/features/proposalsweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/features/reward-distributionweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/features/slashingweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/introduction/overviewweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/introduction/paramsweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/introduction/technical-specificationweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/introduction/terminologyweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/validators/joining-testnetweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/validators/overviewweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.0.0/validators/withdraw_rewardsweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsmweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/adrs/adr-001-key-assignmentweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/adrs/adr-002-throttleweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposalweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verificationweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/adrs/adr-013-equivocation-slashingweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/adrs/adr-templateweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/adrs/introweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/consumer-development/app-integrationweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/consumer-development/consumer-chain-governanceweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/consumer-development/consumer-chain-upgrade-procedureweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/consumer-development/offboardingweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/consumer-development/onboardingweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/faqweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/features/key-assignmentweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/features/proposalsweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/features/reward-distributionweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/features/slashingweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/introduction/overviewweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/introduction/paramsweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/introduction/technical-specificationweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/introduction/terminologyweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/validators/joining-testnetweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/validators/overviewweekly0.5https://cosmos.github.io/interchain-security/legacy/v2.4.0-lsm/validators/withdraw_rewardsweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0weekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/adrs/adr-001-key-assignmentweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/adrs/adr-002-throttleweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/adrs/adr-003-equivocation-gov-proposalweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-propweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/adrs/adr-008-throttle-retriesweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/adrs/adr-009-soft-opt-outweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/adrs/adr-templateweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/adrs/introweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/consumer-development/app-integrationweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/consumer-development/consumer-chain-governanceweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/consumer-development/consumer-chain-upgrade-procedureweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/consumer-development/offboardingweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/consumer-development/onboardingweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/faqweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/features/key-assignmentweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/features/proposalsweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/features/reward-distributionweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/features/slashingweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/introduction/overviewweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/introduction/paramsweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/introduction/technical-specificationweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/introduction/terminologyweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/validators/joining-testnetweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/validators/overviewweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.1.0/validators/withdraw_rewardsweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0weekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/adrs/adr-001-key-assignmentweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/adrs/adr-002-throttleweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/adrs/adr-003-equivocation-gov-proposalweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/adrs/adr-005-cryptographic-equivocation-verificationweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-propweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/adrs/adr-008-throttle-retriesweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/adrs/adr-009-soft-opt-outweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/adrs/adr-010-standalone-changeoverweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/adrs/adr-011-improving-test-confidenceweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/adrs/adr-012-separate-releasingweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/adrs/adr-013-equivocation-slashingweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/adrs/adr-templateweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/adrs/introweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/consumer-development/app-integrationweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/consumer-development/changeover-procedureweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/consumer-development/consumer-chain-governanceweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/consumer-development/offboardingweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/consumer-development/onboardingweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/faqweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/features/key-assignmentweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/features/proposalsweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/features/reward-distributionweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/features/slashingweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/introduction/overviewweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/introduction/paramsweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/introduction/technical-specificationweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/introduction/terminologyweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/validators/changeover-procedureweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/validators/joining-neutronweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/validators/joining-strideweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/validators/joining-testnetweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/validators/overviewweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.2.0/validators/withdraw_rewardsweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0weekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/adrs/adr-001-key-assignmentweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/adrs/adr-002-throttleweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/adrs/adr-003-equivocation-gov-proposalweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/adrs/adr-005-cryptographic-equivocation-verificationweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-propweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/adrs/adr-008-throttle-retriesweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/adrs/adr-009-soft-opt-outweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/adrs/adr-010-standalone-changeoverweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/adrs/adr-011-improving-test-confidenceweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/adrs/adr-012-separate-releasingweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/adrs/adr-013-equivocation-slashingweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/adrs/adr-templateweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/adrs/introweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/consumer-development/app-integrationweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/consumer-development/changeover-procedureweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/consumer-development/consumer-chain-governanceweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/consumer-development/consumer-genesis-transformationweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/consumer-development/offboardingweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/consumer-development/onboardingweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/faqweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/features/key-assignmentweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/features/proposalsweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/features/reward-distributionweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/features/slashingweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/introduction/overviewweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/introduction/paramsweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/introduction/technical-specificationweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/introduction/terminologyweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/validators/changeover-procedureweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/validators/joining-neutronweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/validators/joining-strideweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/validators/joining-testnetweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/validators/overviewweekly0.5https://cosmos.github.io/interchain-security/legacy/v3.3.0/validators/withdraw_rewardsweekly0.5https://cosmos.github.io/interchain-security/legacy/weekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-001-key-assignmentweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-002-throttleweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposalweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verificationweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-propweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-008-throttle-retriesweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-009-soft-opt-outweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-010-standalone-changeoverweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-011-improving-test-confidenceweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-012-separate-releasingweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-013-equivocation-slashingweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-templateweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/introweekly0.5https://cosmos.github.io/interchain-security/legacy/consumer-development/app-integrationweekly0.5https://cosmos.github.io/interchain-security/legacy/consumer-development/changeover-procedureweekly0.5https://cosmos.github.io/interchain-security/legacy/consumer-development/consumer-chain-governanceweekly0.5https://cosmos.github.io/interchain-security/legacy/consumer-development/consumer-genesis-transformationweekly0.5https://cosmos.github.io/interchain-security/legacy/consumer-development/offboardingweekly0.5https://cosmos.github.io/interchain-security/legacy/consumer-development/onboardingweekly0.5https://cosmos.github.io/interchain-security/legacy/faqweekly0.5https://cosmos.github.io/interchain-security/legacy/features/key-assignmentweekly0.5https://cosmos.github.io/interchain-security/legacy/features/proposalsweekly0.5https://cosmos.github.io/interchain-security/legacy/features/reward-distributionweekly0.5https://cosmos.github.io/interchain-security/legacy/features/slashingweekly0.5https://cosmos.github.io/interchain-security/legacy/introduction/overviewweekly0.5https://cosmos.github.io/interchain-security/legacy/introduction/paramsweekly0.5https://cosmos.github.io/interchain-security/legacy/introduction/technical-specificationweekly0.5https://cosmos.github.io/interchain-security/legacy/introduction/terminologyweekly0.5https://cosmos.github.io/interchain-security/legacy/validators/changeover-procedureweekly0.5https://cosmos.github.io/interchain-security/legacy/validators/joining-neutronweekly0.5https://cosmos.github.io/interchain-security/legacy/validators/joining-strideweekly0.5https://cosmos.github.io/interchain-security/legacy/validators/joining-testnetweekly0.5https://cosmos.github.io/interchain-security/legacy/validators/overviewweekly0.5https://cosmos.github.io/interchain-security/legacy/validators/withdraw_rewardsweekly0.5https://cosmos.github.io/interchain-security/legacy/weekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-001-key-assignmentweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-002-throttleweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-003-equivocation-gov-proposalweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-005-cryptographic-equivocation-verificationweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-007-pause-unbonding-on-eqv-propweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-008-throttle-retriesweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-009-soft-opt-outweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-010-standalone-changeoverweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-011-improving-test-confidenceweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-012-separate-releasingweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-013-equivocation-slashingweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/adr-templateweekly0.5https://cosmos.github.io/interchain-security/legacy/adrs/introweekly0.5https://cosmos.github.io/interchain-security/legacy/consumer-development/app-integrationweekly0.5https://cosmos.github.io/interchain-security/legacy/consumer-development/changeover-procedureweekly0.5https://cosmos.github.io/interchain-security/legacy/consumer-development/consumer-chain-governanceweekly0.5https://cosmos.github.io/interchain-security/legacy/consumer-development/consumer-genesis-transformationweekly0.5https://cosmos.github.io/interchain-security/legacy/consumer-development/offboardingweekly0.5https://cosmos.github.io/interchain-security/legacy/consumer-development/onboardingweekly0.5https://cosmos.github.io/interchain-security/legacy/faqweekly0.5https://cosmos.github.io/interchain-security/legacy/features/key-assignmentweekly0.5https://cosmos.github.io/interchain-security/legacy/features/proposalsweekly0.5https://cosmos.github.io/interchain-security/legacy/features/reward-distributionweekly0.5https://cosmos.github.io/interchain-security/legacy/features/slashingweekly0.5https://cosmos.github.io/interchain-security/legacy/introduction/overviewweekly0.5https://cosmos.github.io/interchain-security/legacy/introduction/paramsweekly0.5https://cosmos.github.io/interchain-security/legacy/introduction/technical-specificationweekly0.5https://cosmos.github.io/interchain-security/legacy/introduction/terminologyweekly0.5https://cosmos.github.io/interchain-security/legacy/validators/changeover-procedureweekly0.5https://cosmos.github.io/interchain-security/legacy/validators/joining-neutronweekly0.5https://cosmos.github.io/interchain-security/legacy/validators/joining-strideweekly0.5https://cosmos.github.io/interchain-security/legacy/validators/joining-testnetweekly0.5https://cosmos.github.io/interchain-security/legacy/validators/overviewweekly0.5https://cosmos.github.io/interchain-security/legacy/validators/withdraw_rewardsweekly0.5 \ No newline at end of file diff --git a/legacy/v2.0.0.html b/legacy/v2.0.0.html new file mode 100644 index 0000000000..6a1bdb0039 --- /dev/null +++ b/legacy/v2.0.0.html @@ -0,0 +1,19 @@ + + + + + +Interchain Security Docs | Interchain Security + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0.html.html b/legacy/v2.0.0.html.html new file mode 100644 index 0000000000..8325ca0bab --- /dev/null +++ b/legacy/v2.0.0.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/adrs/adr-001-key-assignment.html b/legacy/v2.0.0/adrs/adr-001-key-assignment.html new file mode 100644 index 0000000000..d80ce1b54f --- /dev/null +++ b/legacy/v2.0.0/adrs/adr-001-key-assignment.html @@ -0,0 +1,19 @@ + + + + + +Key Assignment | Interchain Security + + + + +
+
Version: v2.0.0

ADR 001: Key Assignment

Changelog

  • 2022-12-01: Initial Draft

Status

Accepted

Context

KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate.

Decision

It is possible to change the keys at any time by submitting a transaction (i.e., MsgAssignConsumerKey).

State required

  • ValidatorConsumerPubKey - Stores the validator assigned keys for every consumer chain.
ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey
  • ValidatorByConsumerAddr - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol.
ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress
  • KeyAssignmentReplacements - Stores the key assignments that need to be replaced in the current block. Needed to apply the key assignments received in a block to the validator updates sent to the consumer chains.
KeyAssignmentReplacementsBytePrefix | len(chainID) | chainID | providerConsAddress -> abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower},
  • ConsumerAddrsToPrune - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ValidatorByConsumerAddr.
ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses

Protocol overview

On receiving a MsgAssignConsumerKey(chainID, providerAddr, consumerKey) message:

// get validator from staking module  
validator, found := stakingKeeper.GetValidator(providerAddr)
if !found {
return ErrNoValidatorFound
}
providerConsAddr := validator.GetConsAddr()

// make sure consumer key is not in use
consumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)
if _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {
return ErrInvalidConsumerConsensusPubKey
}

// check whether the consumer chain is already registered
// i.e., a client to the consumer was already created
if _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {
// get the previous key assigned for this validator on this consumer chain
oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)
if found {
// mark this old consumer key as prunable once the VSCMaturedPacket
// for the current VSC ID is received
oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)
vscID := GetValidatorSetUpdateId()
AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)
} else {
// the validator had no key assigned on this consumer chain
oldConsumerKey := validator.TmConsPublicKey()
}

// check whether the validator is valid, i.e., its power is positive
if currentPower := stakingKeeper.GetLastValidatorPower(providerAddr); currentPower > 0 {
// to enable multiple calls of AssignConsumerKey in the same block by the same validator
// the key assignment replacement should not be overwritten
if _, found := GetKeyAssignmentReplacement(chainID, providerConsAddr); !found {
// store old key and power for modifying the valset update in EndBlock
oldKeyAssignment := abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower}
SetKeyAssignmentReplacement(chainID, providerConsAddr, oldKeyAssignment)
}
}
} else {
// if the consumer chain is not registered, then remove the previous reverse mapping
if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {
oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)
DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)
}
}


// set the mapping from this validator's provider address to the new consumer key
SetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)

// set the reverse mapping: from this validator's new consensus address
// on the consumer to its consensus address on the provider
SetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)

When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see MakeConsumerGenesis).

func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {
// ...
// get initial valset from the staking module
var updates []abci.ValidatorUpdate{}
stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {
validator := stakingKeeper.GetValidator(providerAddr)
providerKey := validator.TmConsPublicKey()
updates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})
return false
})

// applies the key assignment to the initial validator
for i, update := range updates {
providerAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)
if consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {
updates[i].PubKey = consumerKey
}
}
gen.InitialValSet = updates

// get a hash of the consumer validator set from the update
updatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)
hash := tendermint.NewValidatorSet(updatesAsValSet).Hash()

return gen, hash, nil
}

On EndBlock while queueing VSCPackets to send to registered consumer chains:

func QueueVSCPackets() {
valUpdateID := GetValidatorSetUpdateId()
// get the validator updates from the staking module
valUpdates := stakingKeeper.GetValidatorUpdates()

IterateConsumerChains(func(chainID, clientID string) (stop bool) {
// apply the key assignment to the validator updates
valUpdates := ApplyKeyAssignmentToValUpdates(chainID, valUpdates)
// ..
})
// ...
}

func ApplyKeyAssignmentToValUpdates(
chainID string,
valUpdates []abci.ValidatorUpdate,
) (newUpdates []abci.ValidatorUpdate) {
for _, valUpdate := range valUpdates {
providerAddr := utils.TMCryptoPublicKeyToConsAddr(valUpdate.PubKey)

// if a key assignment replacement is found, then
// remove the valupdate with the old consumer key
// and create two new valupdates
prevConsumerKey, _, found := GetKeyAssignmentReplacement(chainID, providerAddr)
if found {
// set the old consumer key's power to 0
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: prevConsumerKey,
Power: 0,
})
// set the new consumer key's power to the power in the update
newConsumerKey := GetValidatorConsumerPubKey(chainID, providerAddr)
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: newConsumerKey,
Power: valUpdate.Power,
})
// delete key assignment replacement
DeleteKeyAssignmentReplacement(chainID, providerAddr)
} else {
// there is no key assignment replacement;
// check if the validator's key is assigned
consumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr)
if found {
// replace the update containing the provider key
// with an update containing the consumer key
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: consumerKey,
Power: valUpdate.Power,
})
} else {
// keep the same update
newUpdates = append(newUpdates, valUpdate)
}
}
}

// iterate over the remaining key assignment replacements
IterateKeyAssignmentReplacements(chainID, func(
pAddr sdk.ConsAddress,
prevCKey tmprotocrypto.PublicKey,
power int64,
) (stop bool) {
// set the old consumer key's power to 0
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: prevCKey,
Power: 0,
})
// set the new consumer key's power to the power in key assignment replacement
newConsumerKey := GetValidatorConsumerPubKey(chainID, pAddr)
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: newConsumerKey,
Power: power,
})
return false
})

// remove all the key assignment replacements

return newUpdates
}

On receiving a SlashPacket from a consumer chain with id chainID for a infraction of a validator data.Validator:

func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {
// ...
// the slash packet validator address may be known only on the consumer chain;
// in this case, it must be mapped back to the consensus address on the provider chain
consumerAddr := sdk.ConsAddress(data.Validator.Address)
providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)
if !found {
// the validator has the same key on the consumer as on the provider
providerAddr = consumer
}
// ...
}

On receiving a VSCMatured:

func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {
// ...
// prune previous consumer validator address that are no longer needed
consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)
for _, addr := range consumerAddrs {
DeleteValidatorByConsumerAddr(chainID, addr)
}
DeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)
// ...
}

On stopping a consumer chain:

func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {
// ...
// deletes all the state needed for key assignments on this consumer chain
// ...
}

Consequences

Positive

  • Validators can use different consensus keys on the consumer chains.

Negative

  • None

Neutral

  • The consensus state necessary to create a client to the consumer chain must use the hash returned by the MakeConsumerGenesis method as the nextValsHash.
  • The consumer chain can no longer check the initial validator set against the consensus state on InitGenesis.

References

+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/adrs/adr-001-key-assignment.html.html b/legacy/v2.0.0/adrs/adr-001-key-assignment.html.html new file mode 100644 index 0000000000..b36d775c63 --- /dev/null +++ b/legacy/v2.0.0/adrs/adr-001-key-assignment.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/adrs/adr-002-throttle.html b/legacy/v2.0.0/adrs/adr-002-throttle.html new file mode 100644 index 0000000000..5ab21dcf57 --- /dev/null +++ b/legacy/v2.0.0/adrs/adr-002-throttle.html @@ -0,0 +1,19 @@ + + + + + +Jail Throttling | Interchain Security + + + + +
+
Version: v2.0.0

ADR 002: Jail Throttling

Changelog

  • 2023-01-26: Initial Draft
  • 2023-02-07: Property refined, ADR ready to review/merge

Status

Accepted

Context

The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols. In practice, this assumption may not hold. A malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider.

Before the throttling feature was implemented, the following attack was possible. Attacker(s) would create provider validators just below the provider's active set. Using a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once. Control of the provider would then pass over to the attackers' validators. This enables the attacker(s) to halt the provider. Or even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC.

Decision

The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack. Ie. this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time.

State Required - Slash Meter

There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time. This meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params.

State Required - Global entry queue

There exists a single queue which stores "global slash entries". These entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering. This queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.

State Required - Per-chain data queue

For each established consumer, there exists a queue which stores "throttled packet data". Ie. pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering. Order is enforced by IBC sequence number. These "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.

Reasoning - Multiple queues

For reasoning on why this feature was implemented with multiple queues, see spec. Specifically the section on VSC Maturity and Slashing Order. There are other ways to ensure such a property (like a queue of linked lists, etc.), but the implemented protocol seemed to be the most understandable and easiest to implement with a KV store.

Protocol Overview - OnRecvSlashPacket

Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:

  1. A global slash entry is queued.
  2. The data of such a packet is added to the per-chain queue.

Protocol Overview - OnRecvVSCMaturedPacket

Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue.

Endblocker Step 1 - Slash Meter Replenishment

Once the slash meter becomes not full, it'll be replenished after SlashMeterReplenishPeriod (param) by incrementing the meter with its allowance for the replenishment block, where allowance = SlashMeterReplenishFraction (param) * currentTotalVotingPower. The slash meter will never exceed its current allowance (fn of the total voting power for the block) in value. Note a few things:

  1. The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power. In such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods.
  2. Total voting power of a chain changes over time, especially as validators are jailed. As validators are jailed, total voting power decreases, and so does the jailing allowance. See below for more detailed throttling property discussion.
  3. The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1. If the SlashMeterReplenishFraction (param) is set too low, integer rounding will put this minimum value into effect. That is, if SlashMeterReplenishFraction * currentTotalVotingPower < 1, then the effective allowance would be 1. This min value of allowance ensures that there's some packets handled over time, even if that is a very long time. It's a crude solution to an edge case caused by too small of a replenishment fraction.

The behavior described above is achieved by executing CheckForSlashMeterReplenishment() every endblock, BEFORE HandleThrottleQueues() is executed.

Endblocker Step 2 - HandleLeadingVSCMaturedPackets

Every block it is possible that VSCMatured packet data was queued before any slash packet data. Since this "leading" VSCMatured packet data does not have to be throttled (see VSC Maturity and Slashing Order), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes.

Endblocker Step 3 - HandleThrottleQueues

Every endblocker the following pseudo-code is executed to handle data from the throttle queues.

meter := getSlashMeter()

// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist
while meter.IsPositiveOrZero() && entriesExist() {
// Get next entry in queue
entry := getNextGlobalSlashEntry()
// Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet
valPower := entry.getValPower()
meter = meter - valPower
// Using the per-chain queue, handle the single slash packet using its queued data,
// then handle all trailing VSCMatured packets for this consumer
handleSlashPacketAndTrailingVSCMaturedPackets(entry)
// Delete entry in global queue, delete handled data
entry.Delete()
deleteThrottledSlashPacketData()
deleteTrailingVSCMaturedPacketData()
}

System Properties

All CCV system properties should be maintained by implementing this feature, see: CCV spec - Consumer Initiated Slashing.

One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than MaxThrottledPackets (param), then the provider binary will panic, and the provider chain will halt. Therefore this param should be set carefully. See SetThrottledPacketDataSize. This behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators.

Main Throttling Property

Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions.

First, we define the following:

  • A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.
  • The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.
  • There is a list of honest validators s.t if they are jailed, X% of the initial validator set will be jailed.

For the following property to hold, these assumptions must be true:

  1. We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack.
  2. No validator has more than SlashMeterReplenishFraction of total voting power on the provider.
  3. SlashMeterReplenishFraction is large enough that SlashMeterReplenishFraction * currentTotalVotingPower > 1. Ie. the replenish fraction is set high enough that we can ignore the effects of rounding.
  4. SlashMeterReplenishPeriod is sufficiently longer than the time it takes to produce a block.

Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined.

Property:

The time it takes to jail/tombstone X% of the initial validator set will be greater than or equal to (X * SlashMeterReplenishPeriod / SlashMeterReplenishFraction) - 2 * SlashMeterReplenishPeriod

Intuition:

Let's use the following notation:

  • $C$: Number of replenishment cycles
  • $P$: $\text{SlashMeterReplenishPeriod}$
  • $F$: $\text{SlashMeterReplenishFraction}$
  • $V_{\mathit{max}}$: Max power of a validator as a fraction of total voting power

In $C$ number of replenishment cycles, the fraction of total voting power that can be removed, $a$, is $a \leq F \cdot C + V{\mathit{max}}$ (where $V{\mathit{max}}$ is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value).

So, we need at least $C \geq \frac{a - V_{\mathit{max}}}{F}$ cycles to remove $a$ fraction of the total voting power.

Since we defined the start of the attack to be the moment when the first slash request arrives, then $F$ fraction of the initial validator set can be jailed immediately. For the remaining $X - F$ fraction of the initial validator set to be jailed, it takes at least $C \geq \frac{(X - F) - V{\mathit{max}}}{F}$ cycles. Using the assumption that $V{\mathit{max}} \leq F$ (assumption 2), we get $C \geq \frac{X - 2F}{F}$ cycles.

In order to execute $C$ cycles, we need $C \cdot P$ time.

Thus, jailing the remaining $X - F$ fraction of the initial validator set corresponds to $\frac{P \cdot (X - 2F)}{F}$ time.

In other words, the attack must take at least $\frac{P \cdot X}{F} - 2P$ time (in the units of replenish period $P$).

This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests. For example, if SlashMeterReplenishFraction is set to 0.06, then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub. Note that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power.

Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings.

How Unjailing Affects the Main Throttling Property

Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained.

If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider.

In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack.

Consequences

Positive

  • The described attack is slowed down in seemingly all cases.
  • If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded.

Negative

  • Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below. However, this is sacrificing liveness in a edge case scenario for the sake of security. As an improvement, using retries would fully prevent this attack vector.

Neutral

  • Additional state is introduced to the provider chain.
  • VSCMatured and slash packet data is not always handled in the same block that it is received.

References

+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/adrs/adr-002-throttle.html.html b/legacy/v2.0.0/adrs/adr-002-throttle.html.html new file mode 100644 index 0000000000..d51b55d76d --- /dev/null +++ b/legacy/v2.0.0/adrs/adr-002-throttle.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/adrs/adr-003-equivocation-gov-proposal.html b/legacy/v2.0.0/adrs/adr-003-equivocation-gov-proposal.html new file mode 100644 index 0000000000..1fb26fde88 --- /dev/null +++ b/legacy/v2.0.0/adrs/adr-003-equivocation-gov-proposal.html @@ -0,0 +1,19 @@ + + + + + +Equivocation governance proposal | Interchain Security + + + + +
+
Version: v2.0.0

ADR 003: Equivocation governance proposal

Changelog

  • 2023-02-06: Initial draft

Status

Accepted

Context

We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain.

For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence.

Decision

To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain.

A new kind of governance proposal is added to the provider module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain.

If such proposal passes, the proposal handler delegates to the evidence module to process the equivocation. This module ensures the evidence isn’t too old, or else ignores it (see code). Too old is determined by 2 consensus params :

  • evidence.max_age_duration number of nanoseconds before an evidence is considered too old
  • evidence.max_age_numblocks number of blocks before an evidence is considered too old.

On the hub, those parameters are equals to

// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682
(...)
"evidence": {
"max_age_num_blocks": "1000000",
"max_age_duration": "172800000000000",
(...)
},
(...)

A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the evidence module when the proposal passes and is handled by the hub.

For max_age_num_blocks=1M, the parameter is big enough if we consider the hub produces 12k blocks per day (blocks_per_year/365 = 436,0000/365). The evidence can be up to 83 days old (1,000,000/12,000) and not be ignored.

For max_age_duration=172,800,000,000,000, the parameter is too low, because the value is in nanoseconds so it’s 2 days. Fortunately the condition that checks those 2 parameters uses a AND, so if max_age_num_blocks condition passes, the evidence won’t be ignored.

Consequences

Positive

  • Remove the possibility from a malicious consumer chain to “attack” the provider chain by slashing/jailing validators.
  • Provide a more acceptable implementation for the validator community.

Negative

  • Punishment action of double-signing isn’t “automated”, a governance proposal is required which takes more time.
  • You need to pay 250ATOM to submit an equivocation evidence.

Neutral

References

+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/adrs/adr-003-equivocation-gov-proposal.html.html b/legacy/v2.0.0/adrs/adr-003-equivocation-gov-proposal.html.html new file mode 100644 index 0000000000..9712991304 --- /dev/null +++ b/legacy/v2.0.0/adrs/adr-003-equivocation-gov-proposal.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/adrs/adr-template.html b/legacy/v2.0.0/adrs/adr-template.html new file mode 100644 index 0000000000..6d9cbbf860 --- /dev/null +++ b/legacy/v2.0.0/adrs/adr-template.html @@ -0,0 +1,22 @@ + + + + + +ADR Template | Interchain Security + + + + +
+
Version: v2.0.0

ADR {ADR-NUMBER}: {TITLE}

Changelog

  • {date}: {changelog}

Status

A decision may be "proposed" if it hasn't been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement.

{Deprecated|Proposed|Accepted}

Context

This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution.

Decision

This section explains all of the details of the proposed solution, including implementation details. +It should also describe affects / corollary items that may need to be changed as a part of this. +If the proposed change will be large, please also indicate a way to do the change to maximize ease of review. +(e.g. the optimal split of things to do between separate PR's)

Consequences

This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones.

Positive

Negative

Neutral

References

Are there any relevant PR comments, issues that led up to this, or articles referrenced for why we made the given design choice? If so link them here!

  • {reference link}
+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/adrs/adr-template.html.html b/legacy/v2.0.0/adrs/adr-template.html.html new file mode 100644 index 0000000000..0dad99907d --- /dev/null +++ b/legacy/v2.0.0/adrs/adr-template.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/adrs/intro.html b/legacy/v2.0.0/adrs/intro.html new file mode 100644 index 0000000000..cb95bc2216 --- /dev/null +++ b/legacy/v2.0.0/adrs/intro.html @@ -0,0 +1,22 @@ + + + + + +ADRs | Interchain Security + + + + +
+
Version: v2.0.0

Architecture Decision Records (ADR)

This is a location to record all high-level architecture decisions in the Interchain Security project.

You can read more about the ADR concept in this blog post.

An ADR should provide:

  • Context on the relevant goals and the current state
  • Proposed changes to achieve the goals
  • Summary of pros and cons
  • References
  • Changelog

Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and +justification for a change in architecture, or for the architecture of something +new. The spec is much more compressed and streamlined summary of everything as +it is or should be.

If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match.

Note the context/background should be written in the present tense.

To suggest an ADR, please make use of the ADR template provided.

Table of Contents

ADR #DescriptionStatus
001Consumer chain key assignmentAccepted, Implemented
002Jail ThrottlingAccepted, Implemented
003Equivocation governance proposalAccepted, Implemented
+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/adrs/intro.html.html b/legacy/v2.0.0/adrs/intro.html.html new file mode 100644 index 0000000000..946d3f9766 --- /dev/null +++ b/legacy/v2.0.0/adrs/intro.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/consumer-development/app-integration.html b/legacy/v2.0.0/consumer-development/app-integration.html new file mode 100644 index 0000000000..ca82c744da --- /dev/null +++ b/legacy/v2.0.0/consumer-development/app-integration.html @@ -0,0 +1,23 @@ + + + + + +Developing an ICS consumer chain | Interchain Security + + + + +
+
Version: v2.0.0

Developing an ICS consumer chain

When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol. +To help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications.

Basic consumer chain

The source code for the example app can be found here.

Please note that consumer chains do not implement the staking module - the validator set is replicated from the provider, meaning that the provider and the consumer use the same validator set and their stake on the provider directly determines their stake on the consumer. +At present there is no opt-in mechanism available, so all validators of the provider must also validate on the provider chain.

Your chain should import the consumer module from x/consumer and register it in the correct places in your app.go. +The x/consumer module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in. +You should not need to manage or override any code from the x/consumer module.

Democracy consumer chain

The source code for the example app can be found here.

This type of consumer chain wraps the basic CosmosSDK x/distribution, x/staking and x/governance modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system.

This allows the consumer chain to leverage those modules while also using the x/consumer module.

With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.

Standalone chain to consumer chain changeover

This feature is being actively worked on. Information will be provided at a later time.

+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/consumer-development/app-integration.html.html b/legacy/v2.0.0/consumer-development/app-integration.html.html new file mode 100644 index 0000000000..7cd0f77b25 --- /dev/null +++ b/legacy/v2.0.0/consumer-development/app-integration.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/consumer-development/consumer-chain-governance.html b/legacy/v2.0.0/consumer-development/consumer-chain-governance.html new file mode 100644 index 0000000000..e4b2478a57 --- /dev/null +++ b/legacy/v2.0.0/consumer-development/consumer-chain-governance.html @@ -0,0 +1,19 @@ + + + + + +Consumer Chain Governance | Interchain Security + + + + +
+
Version: v2.0.0

Consumer Chain Governance

Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We'll cover what these are in the "Whitelist" section below.

Democracy module

The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy.

Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus.

For an example, see the Democracy Consumer

CosmWasm

There several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain.

For an example, see Neutron.

The Whitelist

Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see Neutron's whitelist.

+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/consumer-development/consumer-chain-governance.html.html b/legacy/v2.0.0/consumer-development/consumer-chain-governance.html.html new file mode 100644 index 0000000000..b02d9f059d --- /dev/null +++ b/legacy/v2.0.0/consumer-development/consumer-chain-governance.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/consumer-development/consumer-chain-upgrade-procedure.html b/legacy/v2.0.0/consumer-development/consumer-chain-upgrade-procedure.html new file mode 100644 index 0000000000..8c36dee0db --- /dev/null +++ b/legacy/v2.0.0/consumer-development/consumer-chain-upgrade-procedure.html @@ -0,0 +1,19 @@ + + + + + +Upgrading Consumer Chains | Interchain Security + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/consumer-development/consumer-chain-upgrade-procedure.html.html b/legacy/v2.0.0/consumer-development/consumer-chain-upgrade-procedure.html.html new file mode 100644 index 0000000000..97ebca4751 --- /dev/null +++ b/legacy/v2.0.0/consumer-development/consumer-chain-upgrade-procedure.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/consumer-development/offboarding.html b/legacy/v2.0.0/consumer-development/offboarding.html new file mode 100644 index 0000000000..391dae7c3c --- /dev/null +++ b/legacy/v2.0.0/consumer-development/offboarding.html @@ -0,0 +1,19 @@ + + + + + +Offboarding Checklist | Interchain Security + + + + +
+
Version: v2.0.0

Consumer Offboarding

To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).

// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.
// If it passes, all the consumer chain's state is removed from the provider chain. The outstanding unbonding
// operation funds are released.
{
// the title of the proposal
"title": "This was a great chain",
"description": "Here is a .md formatted string specifying removal details",
// the chain-id of the consumer chain to be stopped
"chain_id": "consumerchain-1",
// the time on the provider chain at which all validators are responsible to stop their consumer chain validator node
"stop_time": "2023-03-07T12:40:00.000000Z",
}

More information will be listed in a future version of this document.

+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/consumer-development/offboarding.html.html b/legacy/v2.0.0/consumer-development/offboarding.html.html new file mode 100644 index 0000000000..611fb97c67 --- /dev/null +++ b/legacy/v2.0.0/consumer-development/offboarding.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/consumer-development/onboarding.html b/legacy/v2.0.0/consumer-development/onboarding.html new file mode 100644 index 0000000000..b881ac3d81 --- /dev/null +++ b/legacy/v2.0.0/consumer-development/onboarding.html @@ -0,0 +1,20 @@ + + + + + +Onboarding Checklist | Interchain Security + + + + +
+
Version: v2.0.0

Consumer Onboarding Checklist

The following checklists will aid in onboarding a new consumer chain to replicated security.

Additionally, you can check the testnet repo for a comprehensive guide on preparing and launching consumer chains.

1. Complete testing & integration

  • test integration with gaia
  • test your protocol with supported relayer versions (minimum hermes 1.4.1)
  • reach out to the ICS team if you are facing issues

2. Create an Onboarding Repository

To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain.

This should include (at minimum):

  • genesis.json witout CCV data (before the propsal passes)
  • genesis.json with CCV data (after spawn time passes)
  • information about relevant seed/peer nodes you are running
  • relayer information (compatible versions)
  • copy of your governance proposal (as JSON)
  • a script showing how to start your chain and connect to peers (optional)
  • take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable

Example of such a repository can be found here.

3. Submit a Governance Proposal

Before you submit a ConsumerChainAddition proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch. +If possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues.

Additionally, reach out to the community via the forum to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers.

  • determine your chain's spawn time
  • determine consumer chain parameters to be put in the proposal
  • take note to include a link to your onboarding repository
  • describe the purpose and benefits of running your chain

Example of a consumer chain addition proposal.

// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.
// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.
// It is recommended that spawn time occurs after the proposal end time.
{
// Title of the proposal
"title": "Add consumer chain",
// Description of the proposal
// format the text as a .md file and include the file in your onboarding repository
"description": ".md description of your chain and all other relevant information",
// Proposed chain-id of the new consumer chain.
// Must be unique from all other consumer chain ids of the executing provider chain.
"chain_id": "newchain-1",
// Initial height of new consumer chain.
// For a completely new chain, this will be {0,1}.
"initial_height" : {
"revision_height": 0,
"revision_number": 1,
},
// Hash of the consumer chain genesis state without the consumer CCV module genesis params.
// It is used for off-chain confirmation of genesis.json validity by validators and other parties.
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
// Hash of the consumer chain binary that should be run by validators on chain initialization.
// It is used for off-chain confirmation of binary validity by validators and other parties.
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
// Unbonding period for the consumer chain.
// It should should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
// IBC transfer packets will timeout after this interval elapses.
"transfer_timeout_period": 1800000000000,
// The fraction of tokens allocated to the consumer redistribution address during distribution events.
// The fraction is a string representing a decimal number. For example "0.75" would represent 75%.
// The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.
"consumer_redistribution_fraction": "0.75",
// BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.
// eg. send rewards to the provider every 1000 blocks
"blocks_per_distribution_transmission": 1000,
// The number of historical info entries to persist in store.
// This param is a part of the cosmos sdk staking module. In the case of
// a ccv enabled consumer chain, the ccv module acts as the staking module.
"historical_entries": 10000,
// The ID of a token transfer channel used for the Reward Distribution
// sub-protocol. If DistributionTransmissionChannel == "", a new transfer
// channel is created on top of the same connection as the CCV channel.
// Note that transfer_channel_id is the ID of the channel end on the consumer chain.
// it is most relevant for chains performing a sovereign to consumer changeover
// in order to maintan the existing ibc transfer channel
"distribution_transmission_channel": "channel-123"
}

4. Launch

The consumer chain starts after at least 66.67% of all provider's voting power comes online. The consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer

  • provide a repo with onboarding instructions for validators (it should already be listed in the proposal)
  • genesis.json with ccv data populated (MUST contain the initial validator set)
  • maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)
  • have a block explorer in place to track chain activity & health
+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/consumer-development/onboarding.html.html b/legacy/v2.0.0/consumer-development/onboarding.html.html new file mode 100644 index 0000000000..4817605917 --- /dev/null +++ b/legacy/v2.0.0/consumer-development/onboarding.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/faq.html b/legacy/v2.0.0/faq.html new file mode 100644 index 0000000000..60015069ff --- /dev/null +++ b/legacy/v2.0.0/faq.html @@ -0,0 +1,24 @@ + + + + + +Frequently Asked Questions | Interchain Security + + + + +
+
Version: v2.0.0

Frequently Asked Questions

What is the meaning of Validator Set Replication?

VSR simply means that the same validator set is used to secure both the provider and consumer chains. VSR is ensured through ICS protocol which keeps consumers up to date with the validator set of the provider.

What even is a consumer chain?

Consumer chain is blockchain operated by the same validator operators as the provider chain. The ICS protocol ensures the validator set replication properties (informs consumer chain about the current state of the validator set on the provider)

Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements.

What happens to consumer if provider is down?

In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set.

The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness.

However, if the trusting_period (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain. +This means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about.

Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point. +At the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.

What happens to provider if consumer is down?

Consumer chains do not impact the provider chain. +The ICS protocol is concerned only with validator set replication and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events).

Can I run the provider and consumer chains on the same machine?

Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation.

Can the consumer chain have its own token?

As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees.

How are Tx fees paid on consumer?

The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations.

Are there any restrictions the consumer chains need to abide by?

No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way. +The only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain.

What's in it for the validators and stakers?

The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by consumer_redistribution_fraction. The rewards are distributed (sent to the provider) every blocks_per_distribution_transmission.

note

consumer_redistribution_fraction and blocks_per_distribution_transmission are parameters defined in the ConsumerAdditionProposal used to create the consumer chain. These parameters can be changed via consumer chain governance.

Can the consumer chain have its own governance?

Yes.

In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.

Validators can also be representatives but representatives are not required to run validator nodes.

This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance.

Can validators opt-out of replicated security?

At present, the validators cannot opt-out of validating consumer chains.

There are multiple opt-out mechanisms under active research.

How does Equivocation Governance Slashing work?

To avoid potential attacks directed at provider chain validators, a new mechanism was introduced:

When a validator double-signs on the consumer chain, a special type of slash packet is relayed to the provider chain. The provider will store information about the double signing validator and allow a governance proposal to be submitted. +If the double-signing proposal passes, the offending validator will be slashed on the provider chain and tombstoned. Tombstoning will permanently exclude the validator from the active set of the provider.

caution

An equivocation proposal cannot be submitted for a validator that did not double sign on any of the consumer chains.

Can Consumer Chains perform Software Upgrades?

Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM).

Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module.

How can I connect to the testnets?

Check out the Joining Replicated Security testnet section.

How do I start using ICS?

To become a consumer chain use this checklist and check the App integration section

Which relayers are supported?

Currently supported versions:

  • Hermes 1.4.1

How does key delegation work in ICS?

You can check the Key Assignment Guide for specific instructions.

+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/faq.html.html b/legacy/v2.0.0/faq.html.html new file mode 100644 index 0000000000..eee823752e --- /dev/null +++ b/legacy/v2.0.0/faq.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/features/key-assignment.html b/legacy/v2.0.0/features/key-assignment.html new file mode 100644 index 0000000000..27f7fbdd77 --- /dev/null +++ b/legacy/v2.0.0/features/key-assignment.html @@ -0,0 +1,20 @@ + + + + + +Key Assignment | Interchain Security + + + + +
+
Version: v2.0.0

Key Assignment

Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate. +There are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains.

The feature is outlined in this ADR-001

By sending an AssignConsumerKey transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator.

tip

Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity.

Rules

  • a key can be assigned before the consumer addition proposal passes on the provider
  • validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider
  • validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X
  • a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain
tip

Validators can use a different key for each consumer chain.

Adding a key

First, create a new node on the consumer chain using the equivalent:

consumerd init <moniker>

Then query your node for the consensus key.

consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}

Then, make an assign-consensus-key transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain.

gaiad tx provider assign-consensus-key <consumer-chain-id> '<pubkey>' --from <tx-signer> --home <home_dir> --gas 900000 -b block -y -o json
  • consumer-chain-id is the string identifier of the consumer chain, as assigned on the provider chain
  • consumer-pub-key has the following format {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}

Check that the key was assigned correcly by querying the provider:

gaiad query provider validator-consumer-key <consumer-chain-id> cosmosvalcons1e....3xsj3ayzf4uv6

You must use a valcons address. You can obtain it by querying your node on the provider gaiad tendermint show-address

OR

gaiad query provider validator-provider-key <consumer-chain-id> consumervalcons1e....123asdnoaisdao

You must use a valcons address. You can obtain it by querying your node on the consumer consumerd tendermint show-address

Changing a key

To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied

Removing a key

To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the Adding a key section and using your provider consensus key.

+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/features/key-assignment.html.html b/legacy/v2.0.0/features/key-assignment.html.html new file mode 100644 index 0000000000..2166f82cf3 --- /dev/null +++ b/legacy/v2.0.0/features/key-assignment.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/features/proposals.html b/legacy/v2.0.0/features/proposals.html new file mode 100644 index 0000000000..eddc56fdfa --- /dev/null +++ b/legacy/v2.0.0/features/proposals.html @@ -0,0 +1,26 @@ + + + + + +ICS Provider Proposals | Interchain Security + + + + +
+
Version: v2.0.0

ICS Provider Proposals

Interchain security module introduces 3 new proposal types to the provider.

The proposals are used to propose upcoming interchain security events through governance.

ConsumerAdditionProposal

info

If you are preparing a ConsumerAdditionProposal you can find more information in the consumer onboarding checklist.

Proposal type used to suggest adding a new consumer chain.

When proposals of this type are passed and the spawn_time specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain.

Minimal example:

{
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
"title": "Add consumer chain",
"description": ".md description of your chain and all other relevant information",
"chain_id": "newchain-1",
"initial_height" : {
"revision_height": 0,
"revision_number": 1,
},
// Unbonding period for the consumer chain.
// It should should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
"transfer_timeout_period": 1800000000000,
"consumer_redistribution_fraction": "0.75",
"blocks_per_distribution_transmission": 1000,
"historical_entries": 10000,
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1"
// relevant for chains performing a sovereign to consumer changeover
// in order to maintan the existing ibc transfer channel
"distribution_transmission_channel": "channel-123"
}

More examples can be found in the replicated security testnet repository here and here.

ConsumerRemovalProposal

Proposal type used to suggest removing an existing consumer chain.

When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain. +After the consumer chain removal, the chain in question will no longer be secured by the provider's validator set.

info

The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain. +Additional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set. +More information will be made available in the Consumer Offboarding Checklist.

Minimal example:

{
// the time on the provider chain at which all validators are responsible to stop their consumer chain validator node
"stop_time": "2023-03-07T12:40:00.000000Z",
// the chain-id of the consumer chain to be stopped
"chain_id": "consumerchain-1",
"title": "This was a great chain",
"description": "Here is a .md formatted string specifying removal details"
}

EquivocationProposal

tip

EquivocationProposal will only be accepted on the provider chain if at least one of the consumer chains submits equivocation evidence to the provider. +Sending equivocation evidence to the provider is handled automatically by the interchain security protocol when an equivocation infraction is detected on the consumer chain.

Proposal type used to suggest slashing a validator for double signing on consumer chain. +When proposals of this type are passed, the validator in question will be slashed for equivocation on the provider chain.

danger

Take note that an equivocation slash causes a validator to be tombstoned (can never re-enter the active set). +Tombstoning a validator on the provider chain will remove the validator from the validator set of all consumer chains.

Minimal example:

{
"title": "Validator-1 double signed on consumerchain-1",
"description": "Here is more information about the infraction so you can verify it yourself",
// the list of equivocations that will be processed
"equivocations": [
{
"height": 14444680,
"time": "2023-02-28T20:40:00.000000Z",
"power": 5500000,
"consensus_address": "<consensus address ON THE PROVIDER>"
}
]
}

Notes

When submitting equivocation evidence through an EquivocationProposal please take note that you need to use the consensus address (valcons) of the offending validator on the provider chain. +Besides that, the height and the time fields should be mapped to the provider chain to avoid your evidence being rejected.

Before submitting the proposal please check that the evidence is not outdated by comparing the infraction height with the max_age_duration and max_age_num_blocks consensus parameters of the provider chain.

Gaia example:

➜  ~ cat genesis.json | jq ".consensus_params"
{
"block": {
...
},
"evidence": {
"max_age_duration": "172800000000000",
"max_age_num_blocks": "1000000",
"max_bytes": "50000"
},
"validator": {
...
},
"version": {}
}

Any EquivocationProposal transactions that submit evidence with height older than max_age_num_blocks and time older than max_age_duration will be considered invalid.

+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/features/proposals.html.html b/legacy/v2.0.0/features/proposals.html.html new file mode 100644 index 0000000000..c451850c9a --- /dev/null +++ b/legacy/v2.0.0/features/proposals.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/features/reward-distribution.html b/legacy/v2.0.0/features/reward-distribution.html new file mode 100644 index 0000000000..e0be1747b0 --- /dev/null +++ b/legacy/v2.0.0/features/reward-distribution.html @@ -0,0 +1,23 @@ + + + + + +Reward distribution | Interchain Security + + + + +
+
Version: v2.0.0

Reward distribution

Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators. +In replicated security block rewards and fees are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel that gets created during consumer chain initialization.

Reward distribution on the provider is handled by the distribution module - validators and delegators receive a fraction of the consumer chain tokens as staking rewards. +The distributed reward tokens are IBC tokens and therefore cannot be staked on the provider chain.

Sending and distributing rewards from consumer chains to provider chain is handled by the Reward Distribution sub-protocol.

Parameters

tip

The following chain parameters dictate consumer chain distribution amount and frequency. +They are set at consumer genesis and blocks_per_distribution_transmission, consumer_redistribution_fraction +transfer_timeout_period must be provided in every ConsumerChainAddition proposal.

consumer_redistribution_fraction

The fraction of tokens sent from consumer to provider during distribution events. The fraction is a string representing a decimal number. For example "0.75" would represent 75%.

tip

Example:

With consumer_redistribution_fraction set to 0.75 the consumer chain would send 75% of its block rewards and accumulated fees to the consumer chain and the remaining 25% to the provider chain every n blocks where n == blocks_per_distribution_transmission.

blocks_per_distribution_transmission

The number of blocks between IBC token transfers from the consumer chain to the provider chain.

transfer_timeout_period

Timeout period for consumer chain reward distribution IBC packets.

distribution_transmission_channel

Provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.

provider_fee_pool_addr_str

Provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.

+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/features/reward-distribution.html.html b/legacy/v2.0.0/features/reward-distribution.html.html new file mode 100644 index 0000000000..f6e4ce0cec --- /dev/null +++ b/legacy/v2.0.0/features/reward-distribution.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/features/slashing.html b/legacy/v2.0.0/features/slashing.html new file mode 100644 index 0000000000..624f81cd94 --- /dev/null +++ b/legacy/v2.0.0/features/slashing.html @@ -0,0 +1,22 @@ + + + + + +Consumer Initiated Slashing | Interchain Security + + + + +
+
Version: v2.0.0

Consumer Initiated Slashing

A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of it's own chain. +In essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake).

To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized. +Any infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains.

In the current implementation there are 2 important changes brought by the interchain security module:

Downtime infractions

reported by consumer chains are acted upon on the provider as soon as the provider receives the infraction evidence.

Instead of slashing, the provider will only jail offending validator for the duration of time established in the chain parameters.

info

Slash throttling (sometimes called jail throttling) mechanism insures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider.

Double-signing (equivocation)

infractions are not acted upon immediately.

Upon receiving double signing evidence, the provider chain will take note of the evidence and allow for EquivocationProposal to be submitted to slash the offending validator. +Any EquivocationProposals to slash a validator that has not double signed on any of the consumer chains will be automatically rejected by the provider chain.

info

The offending validator will only be slashed (and tombstoned) if an EquivocationProposal is accepted and passed through governance.

The offending validator will effectively get slashed and tombstoned on all consumer chains.

You can find instructions on creating EquivocationProposals here.

+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/features/slashing.html.html b/legacy/v2.0.0/features/slashing.html.html new file mode 100644 index 0000000000..caee30fa28 --- /dev/null +++ b/legacy/v2.0.0/features/slashing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/introduction/overview.html b/legacy/v2.0.0/introduction/overview.html new file mode 100644 index 0000000000..120b45c152 --- /dev/null +++ b/legacy/v2.0.0/introduction/overview.html @@ -0,0 +1,19 @@ + + + + + +Overview | Interchain Security + + + + +
+
Version: v2.0.0

Overview

info

Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.


Replicated security allows anyone to launch a "consumer" blockchain using the same validator set as the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit the full security and decentralization of the provider.

Why Replicated Security?

  • Full provider security. At launch, consumer chains are secured by the full validator set and market cap of the provider chain.
  • Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum.
  • Projects keep majority of gas fees. Depending on configuration, these fees either go to the project’s community DAO, or can be used in the protocol in other ways.
  • No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. A governance vote will take place for a chain to get adopted by the provider validators which will encourage participation and signal strong buy-in into the project's long-term success.
  • Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set.

Core protocol

info

Protocol specification is available as ICS-028 in the IBC repository.

Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer.

To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider.

Downtime Slashing

If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period.

Equivocation (Double Sign) Slashing

Evidence of equivocation must be submitted to provider governance and be voted on. This behavior is an extra safeguard before a validator is slashed, and may be replaced by a more automated system in the future.

Tokenomics and Rewards

Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance.

+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/introduction/overview.html.html b/legacy/v2.0.0/introduction/overview.html.html new file mode 100644 index 0000000000..0954176389 --- /dev/null +++ b/legacy/v2.0.0/introduction/overview.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/introduction/params.html b/legacy/v2.0.0/introduction/params.html new file mode 100644 index 0000000000..fcedc8c680 --- /dev/null +++ b/legacy/v2.0.0/introduction/params.html @@ -0,0 +1,21 @@ + + + + + +Interchain Security Parameters | Interchain Security + + + + +
+
Version: v2.0.0

Interchain Security Parameters

The parameters necessary for Interchain Security (ICS) are defined in

  • the Params structure in proto/interchain_security/ccv/provider/v1/provider.proto for the provider;
  • the Params structure in proto/interchain_security/ccv/consumer/v1/consumer.proto for the consumer.

Time-based parameters

ICS relies on the following time-based parameters.

ProviderUnbondingPeriod

is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance.

ConsumerUnbondingPeriod

is the unbonding period on the consumer chain.

info

ConsumerUnbondingPeriod is set via the ConsumerAdditionProposal governance proposal to add a new consumer chain. +It is recommended that every consumer chain set and unbonding period shorter than ProviderUnbondingPeriod


Example:

ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day

Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer.

TrustingPeriodFraction

is used to calculate the TrustingPeriod of created IBC clients on both provider and consumer chains.

Setting TrustingPeriodFraction to 0.5 would result in the following:

TrustingPeriodFraction = 0.5
ProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5
ConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5

Note that a light clients must be updated within the TrustingPeriod in order to avoid being frozen.

For more details, see the IBC specification of Tendermint clients.

CCVTimeoutPeriod

is the period used to compute the timeout timestamp when sending IBC packets.

For more details, see the IBC specification of Channel & Packet Semantics.

danger

If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed.

CCVTimeoutPeriod may have different values on the provider and consumer chains.

  • CCVTimeoutPeriod on the provider must be larger than ConsumerUnbondingPeriod
  • CCVTimeoutPeriod on the consumer is initial set via the ConsumerAdditionProposal

InitTimeoutPeriod

is the maximum allowed duration for CCV channel initialization to execute.

For any consumer chain, if the CCV channel is not established within InitTimeoutPeriod then the consumer chain will be removed and therefore will not be secured by the provider chain.

The countdown starts when the spawn_time specified in the ConsumerAdditionProposal is reached.

VscTimeoutPeriod

is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live. +If the VscTimeoutPeriod is ever reached for a consumer chain that chain will be considered not live and removed from interchain security.

tip

VscTimeoutPeriod MUST be larger than the ConsumerUnbondingPeriod.

BlocksPerDistributionTransmission

is the number of blocks between rewards transfers from the consumer to the provider.

TransferPeriodTimeout

is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider.

If this timeout expires, then the transfer is attempted again after BlocksPerDistributionTransmission blocks.

  • TransferPeriodTimeout on the consumer is initial set via the ConsumerAdditionProposal gov proposal to add the consumer
  • TransferPeriodTimeout should be smaller than BlocksPerDistributionTransmission x avg_block_time

Slash Throttle Parameters

SlashMeterReplenishPeriod

exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed.

The meter is replenished to an amount equal to the slash meter allowance for that block, or SlashMeterReplenishFraction * CurrentTotalVotingPower.

SlashMeterReplenishFraction

exists on the provider as the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs.

This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a sdk.Dec when used.

MaxThrottledPackets

exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value.

This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness.

+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/introduction/params.html.html b/legacy/v2.0.0/introduction/params.html.html new file mode 100644 index 0000000000..4dd3db4f99 --- /dev/null +++ b/legacy/v2.0.0/introduction/params.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/introduction/technical-specification.html b/legacy/v2.0.0/introduction/technical-specification.html new file mode 100644 index 0000000000..dda0f3fd43 --- /dev/null +++ b/legacy/v2.0.0/introduction/technical-specification.html @@ -0,0 +1,19 @@ + + + + + +Technical Specification | Interchain Security + + + + +
+
Version: v2.0.0

Technical Specification

For a technical deep dive into the replicated security protocol, see the specification.

+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/introduction/technical-specification.html.html b/legacy/v2.0.0/introduction/technical-specification.html.html new file mode 100644 index 0000000000..7bd125b936 --- /dev/null +++ b/legacy/v2.0.0/introduction/technical-specification.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/introduction/terminology.html b/legacy/v2.0.0/introduction/terminology.html new file mode 100644 index 0000000000..e0bea6c298 --- /dev/null +++ b/legacy/v2.0.0/introduction/terminology.html @@ -0,0 +1,19 @@ + + + + + +Terminology | Interchain Security + + + + +
+
Version: v2.0.0

Terminology

You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.

Shared Security

Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share it's proof-of-stake security with another blockchain or off-chain process.

Interchain Security

Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC.

Replicated Security

A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC. Note this documentation is focused on explaining the concepts from replicated security.

Mesh security

A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see Replicated vs. Mesh Security on the Informal Blog.

+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/introduction/terminology.html.html b/legacy/v2.0.0/introduction/terminology.html.html new file mode 100644 index 0000000000..0a468a4619 --- /dev/null +++ b/legacy/v2.0.0/introduction/terminology.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/validators/joining-testnet.html b/legacy/v2.0.0/validators/joining-testnet.html new file mode 100644 index 0000000000..0617ecce76 --- /dev/null +++ b/legacy/v2.0.0/validators/joining-testnet.html @@ -0,0 +1,20 @@ + + + + + +Joining Replicated Security testnet | Interchain Security + + + + +
+
Version: v2.0.0

Introduction

This short guide will teach you how to join the Replicated Security testnet.

The experience gained in the testnet will prepare you for validating interchain secured chains.

tip

Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set.

For general information about running cosmos-sdk based chains check out the validator basics and Running a Node section of Cosmos SDK docs

Joining the provider chain

info

At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain.

A comprehensive guide is available here.

Initialization

First, initialize your $NODE_HOME using the provider chain binary.

NODE_MONIKER=<your_node>
CHAIN_ID=provider
NODE_HOME=<path_to_your_home>

gaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME

Add your key to the keyring - more details available here.

In this example we will use the test keyring-backend. This option is not safe to use in production.

gaiad keys add <key_moniker> --keyring-backend test

# save the address as variable for later use
MY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)

Before issuing any transactions, use the provider testnet faucet to add funds to your address.

curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider

# example output:
{
"address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",
"amount": "10000000uatom",
"chain": "provider",
"hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",
"status": "success"
}

Then, use the account associated with the keyring to issue a create-validator transaction which will register your validator on chain.

gaiad tx staking create-validator \
--amount=1000000uatom \
--pubkey=$(gaiad tendermint show-validator) \
--moniker="choose a moniker" \
--chain-id=$CHAIN_ID" \
--commission-rate="0.10" \
--commission-max-rate="0.20" \
--commission-max-change-rate="0.01" \
--min-self-delegation="1000000" \
--gas="auto" \
--gas-prices="0.0025uatom" \
--from=<key_moniker>
tip

Check this guide to edit your validator.

After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use statesync to catch up to the rest of the network.

You can use this script to modify your config.toml with the required statesync parameters.

# create the statesync script
$: cd $NODE_HOME
$: touch statesync.sh
$ chmod 700 statesync.sh # make executable

Paste the following instructions into the statesync.sh:

#!/bin/bash

SNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"

LATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \
BLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \
TRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)

sed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\1true| ; \
s|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\1\"$SNAP_RPC,$SNAP_RPC\"| ; \
s|^(trust_height[[:space:]]+=[[:space:]]+).*$|\1$BLOCK_HEIGHT| ; \
s|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\1\"$TRUST_HASH\"|" $NODE_HOME/config/config.toml

Then, you can execute the script:

$: ./statesync.sh # setup config.toml for statesync

Finally, copy the provider genesis and start your node:

$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/replicated-security/provider/provider-genesis.json
$: wget $GENESIS_URL -O genesis.json
$: genesis.json $NODE_HOME/config/genesis.json
# start the service
$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"

Additional scripts to setup your nodes are available here and here. The scripts will configure your node and create the required services - the scripts only work in linux environments.

Joining consumer chains

tip

Once you reach the active set on the provider chain, you will be required to validate all available consumer chains.

You can use the same consensus key on all consumer chains, or opt to use a different key on each consumer chain. +Check out this guide to learn more about key assignment in replicated security.

To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries.

info

When running the provider chain and consumers on the same machine please update the PORT numbers for each of them and make sure they do not overlap (otherwise the binaries will not start).

Important ports to re-configure:

  • --rpc.laddr
  • --p2p.laddr
  • --api.address
  • --grpc.address
  • --grpc-web.address

Re-using consensus key

To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the priv_validator_key.json into the home directory of your consumer chain (<consumer_home>/config/priv_validator_key.json).

When you start the chain, the consensus key will be the same on the provider and the consumer chain.

Assigning consensus keys

Whenever you initialize a new node, it will be configured with a consensus key you can use.

# machine running consumer chain
consumerd init <node_moniker> --home <home_path> --chain-id consumer-1

# use the output of this command to get the consumer chain consensus key
consumerd tendermint show-validator
# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}

Then, let the provider know which key you will be using for the consumer chain:

# machine running the provider chain
gaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b block -y -o json

After this step, you are ready to copy the consumer genesis into your nodes's /config folder, start your consumer chain node and catch up to the network.

Baryon

You can find the onboarding repo instructions for the Baryon chain here

Noble

You can find the onboarding repo instructions for the Noble chain here

+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/validators/joining-testnet.html.html b/legacy/v2.0.0/validators/joining-testnet.html.html new file mode 100644 index 0000000000..68c2e26c0d --- /dev/null +++ b/legacy/v2.0.0/validators/joining-testnet.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/validators/overview.html b/legacy/v2.0.0/validators/overview.html new file mode 100644 index 0000000000..806f91444e --- /dev/null +++ b/legacy/v2.0.0/validators/overview.html @@ -0,0 +1,24 @@ + + + + + +Overview | Interchain Security + + + + +
+
Version: v2.0.0

Overview

tip

We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.

At present, replicated security requires all validators of the provider chain (ie. Cosmos Hub) to run validator nodes for all governance-approved consumer chains.

Once a ConsumerAdditionProposal passes, validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains.

Provider chain and consumer chains represent standalone chains that only share the validator set ie. the same validator operators are tasked with running all chains.

info

To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 175 validators for Cosmos Hub).

Startup sequence overview

Consumer chains cannot start and be secured by the validator set of the provider unless a ConsumerAdditionProposal is passed. +Each proposal contains defines a spawn_time - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider.

tip

Validators are required to run consumer chain binaries only after spawn_time has passed.

Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains.

The image below illustrates the startup sequence +startup

1. Consumer Chain init + 2. Genesis generation

Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ConsumerAdditionProposal

3. Submit Proposal

Consumer chain team (or their advocates) submits a ConsumerAdditionProposal. +The most important parameters for validators are:

  • spawn_time - the time after which the consumer chain must be started
  • genesis_hash - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and spawn_time is reached
  • binary_hash - hash of the consumer chain binary used to validate the software builds

4. CCV Genesis state generation

After reaching spawn_time the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain genesis.json. The CCV validator set consists of the validator set on the provider at spawn_time.

The state can be queried on the provider chain (in this case the Cosmos Hub):

 gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json

This is used by the launch coordinator to create the final genesis.json that will be distributed to validators in step 5.

5. Updating the genesis file

Upon reaching the spawn_time the initial validator set state will become available on the provider chain. The initial validator set is included in the final genesis.json of the consumer chain.

6. Chain start

info

The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences.

The new genesis.json containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided genesis.json to start their consumer chain node.

tip

Please pay attention to any onboarding repositories provided by the consumer chain teams. +Recommendations are available in Consumer Onboarding Checklist. +Another comprehensive guide is available in the Replicated Security testnet repo.

7. Creating IBC connections

Finally, to fully establish replicated security an IBC relayer is used to establish connections and create the required channels.

danger

The relayer can establish the connection only after the consumer chain starts producing blocks.

hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> 
hermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1
hermes start

Downtime Infractions

At present, the consumer chain can report evidence about downtime infractions to the provider chain. The min_signed_per_window and signed_blocks_window can be different on each consumer chain and are subject to changes via consumer chain governance.

info

Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains.

To unjail, the validator must wait for the jailing period to elapse on the provider chain and submit an unjail transaction on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains.

More information is available in Downtime Slashing documentation

Double-signing Infractions

To learn more about equivocation handling in replicated security check out the Slashing and EquivocationProposal documentation sections

Key assignment

Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use.

For more information check our the Key assignment overview and guide

References:

+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/validators/overview.html.html b/legacy/v2.0.0/validators/overview.html.html new file mode 100644 index 0000000000..eb73af0ef8 --- /dev/null +++ b/legacy/v2.0.0/validators/overview.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.0.0/validators/withdraw_rewards.html b/legacy/v2.0.0/validators/withdraw_rewards.html new file mode 100644 index 0000000000..edf29089ba --- /dev/null +++ b/legacy/v2.0.0/validators/withdraw_rewards.html @@ -0,0 +1,20 @@ + + + + + +Withdrawing consumer chain validator rewards | Interchain Security + + + + +
+
Version: v2.0.0

Withdrawing consumer chain validator rewards

Here are example steps for withdrawing rewards from consumer chains in the provider chain

info

The examples used are from rs-testnet, the replicated security persistent testnet.

Validator operator address: cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 +Self-delegation address: cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

Prior to withdrawing rewards, query balances for self-delegation address:

gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

balances:
- amount: "1000000000000"
denom: uatom
pagination:
next_key: null
total: "0"

Querying validator rewards

Query rewards for the validator address:

gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6

rewards:
- amount: "158.069895000000000000"
denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD
- amount: "841842390516.072526500000000000"
denom: uatom

The ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD denom represents rewards from a consumer chain.

Withdrawing rewards and commission

1. Withdraw rewards

gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y

txhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A

2. Confirm withdrawal

After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:

gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

balances:
- amount: "216"
denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD
- amount: "2233766225342"
denom: uatom
pagination:
next_key: null
total: "0"
+ + + + \ No newline at end of file diff --git a/legacy/v2.0.0/validators/withdraw_rewards.html.html b/legacy/v2.0.0/validators/withdraw_rewards.html.html new file mode 100644 index 0000000000..5d44aac566 --- /dev/null +++ b/legacy/v2.0.0/validators/withdraw_rewards.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm.html b/legacy/v2.4.0-lsm.html new file mode 100644 index 0000000000..01e85d021e --- /dev/null +++ b/legacy/v2.4.0-lsm.html @@ -0,0 +1,19 @@ + + + + + +Interchain Security Docs | Interchain Security + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm.html.html b/legacy/v2.4.0-lsm.html.html new file mode 100644 index 0000000000..1ee3b8f0db --- /dev/null +++ b/legacy/v2.4.0-lsm.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/adrs/adr-001-key-assignment.html b/legacy/v2.4.0-lsm/adrs/adr-001-key-assignment.html new file mode 100644 index 0000000000..a6149945aa --- /dev/null +++ b/legacy/v2.4.0-lsm/adrs/adr-001-key-assignment.html @@ -0,0 +1,19 @@ + + + + + +Key Assignment | Interchain Security + + + + +
+
Version: v2.4.0-lsm

ADR 001: Key Assignment

Changelog

  • 2022-12-01: Initial Draft

Status

Accepted

Context

KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate.

Decision

It is possible to change the keys at any time by submitting a transaction (i.e., MsgAssignConsumerKey).

State required

  • ValidatorConsumerPubKey - Stores the validator assigned keys for every consumer chain.
ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey
  • ValidatorByConsumerAddr - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol.
ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress
  • KeyAssignmentReplacements - Stores the key assignments that need to be replaced in the current block. Needed to apply the key assignments received in a block to the validator updates sent to the consumer chains.
KeyAssignmentReplacementsBytePrefix | len(chainID) | chainID | providerConsAddress -> abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower},
  • ConsumerAddrsToPrune - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ValidatorByConsumerAddr.
ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses

Protocol overview

On receiving a MsgAssignConsumerKey(chainID, providerAddr, consumerKey) message:

// get validator from staking module  
validator, found := stakingKeeper.GetValidator(providerAddr)
if !found {
return ErrNoValidatorFound
}
providerConsAddr := validator.GetConsAddr()

// make sure consumer key is not in use
consumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)
if _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {
return ErrInvalidConsumerConsensusPubKey
}

// check whether the consumer chain is already registered
// i.e., a client to the consumer was already created
if _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {
// get the previous key assigned for this validator on this consumer chain
oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)
if found {
// mark this old consumer key as prunable once the VSCMaturedPacket
// for the current VSC ID is received
oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)
vscID := GetValidatorSetUpdateId()
AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)
} else {
// the validator had no key assigned on this consumer chain
oldConsumerKey := validator.TmConsPublicKey()
}

// check whether the validator is valid, i.e., its power is positive
if currentPower := stakingKeeper.GetLastValidatorPower(providerAddr); currentPower > 0 {
// to enable multiple calls of AssignConsumerKey in the same block by the same validator
// the key assignment replacement should not be overwritten
if _, found := GetKeyAssignmentReplacement(chainID, providerConsAddr); !found {
// store old key and power for modifying the valset update in EndBlock
oldKeyAssignment := abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower}
SetKeyAssignmentReplacement(chainID, providerConsAddr, oldKeyAssignment)
}
}
} else {
// if the consumer chain is not registered, then remove the previous reverse mapping
if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {
oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)
DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)
}
}


// set the mapping from this validator's provider address to the new consumer key
SetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)

// set the reverse mapping: from this validator's new consensus address
// on the consumer to its consensus address on the provider
SetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)

When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see MakeConsumerGenesis).

func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {
// ...
// get initial valset from the staking module
var updates []abci.ValidatorUpdate{}
stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {
validator := stakingKeeper.GetValidator(providerAddr)
providerKey := validator.TmConsPublicKey()
updates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})
return false
})

// applies the key assignment to the initial validator
for i, update := range updates {
providerAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)
if consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {
updates[i].PubKey = consumerKey
}
}
gen.InitialValSet = updates

// get a hash of the consumer validator set from the update
updatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)
hash := tendermint.NewValidatorSet(updatesAsValSet).Hash()

return gen, hash, nil
}

On EndBlock while queueing VSCPackets to send to registered consumer chains:

func QueueVSCPackets() {
valUpdateID := GetValidatorSetUpdateId()
// get the validator updates from the staking module
valUpdates := stakingKeeper.GetValidatorUpdates()

IterateConsumerChains(func(chainID, clientID string) (stop bool) {
// apply the key assignment to the validator updates
valUpdates := ApplyKeyAssignmentToValUpdates(chainID, valUpdates)
// ..
})
// ...
}

func ApplyKeyAssignmentToValUpdates(
chainID string,
valUpdates []abci.ValidatorUpdate,
) (newUpdates []abci.ValidatorUpdate) {
for _, valUpdate := range valUpdates {
providerAddr := utils.TMCryptoPublicKeyToConsAddr(valUpdate.PubKey)

// if a key assignment replacement is found, then
// remove the valupdate with the old consumer key
// and create two new valupdates
prevConsumerKey, _, found := GetKeyAssignmentReplacement(chainID, providerAddr)
if found {
// set the old consumer key's power to 0
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: prevConsumerKey,
Power: 0,
})
// set the new consumer key's power to the power in the update
newConsumerKey := GetValidatorConsumerPubKey(chainID, providerAddr)
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: newConsumerKey,
Power: valUpdate.Power,
})
// delete key assignment replacement
DeleteKeyAssignmentReplacement(chainID, providerAddr)
} else {
// there is no key assignment replacement;
// check if the validator's key is assigned
consumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr)
if found {
// replace the update containing the provider key
// with an update containing the consumer key
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: consumerKey,
Power: valUpdate.Power,
})
} else {
// keep the same update
newUpdates = append(newUpdates, valUpdate)
}
}
}

// iterate over the remaining key assignment replacements
IterateKeyAssignmentReplacements(chainID, func(
pAddr sdk.ConsAddress,
prevCKey tmprotocrypto.PublicKey,
power int64,
) (stop bool) {
// set the old consumer key's power to 0
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: prevCKey,
Power: 0,
})
// set the new consumer key's power to the power in key assignment replacement
newConsumerKey := GetValidatorConsumerPubKey(chainID, pAddr)
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: newConsumerKey,
Power: power,
})
return false
})

// remove all the key assignment replacements

return newUpdates
}

On receiving a SlashPacket from a consumer chain with id chainID for a infraction of a validator data.Validator:

func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {
// ...
// the slash packet validator address may be known only on the consumer chain;
// in this case, it must be mapped back to the consensus address on the provider chain
consumerAddr := sdk.ConsAddress(data.Validator.Address)
providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)
if !found {
// the validator has the same key on the consumer as on the provider
providerAddr = consumer
}
// ...
}

On receiving a VSCMatured:

func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {
// ...
// prune previous consumer validator address that are no longer needed
consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)
for _, addr := range consumerAddrs {
DeleteValidatorByConsumerAddr(chainID, addr)
}
DeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)
// ...
}

On stopping a consumer chain:

func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {
// ...
// deletes all the state needed for key assignments on this consumer chain
// ...
}

Consequences

Positive

  • Validators can use different consensus keys on the consumer chains.

Negative

  • None

Neutral

  • The consensus state necessary to create a client to the consumer chain must use the hash returned by the MakeConsumerGenesis method as the nextValsHash.
  • The consumer chain can no longer check the initial validator set against the consensus state on InitGenesis.

References

+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/adrs/adr-001-key-assignment.html.html b/legacy/v2.4.0-lsm/adrs/adr-001-key-assignment.html.html new file mode 100644 index 0000000000..8fca73ee27 --- /dev/null +++ b/legacy/v2.4.0-lsm/adrs/adr-001-key-assignment.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/adrs/adr-002-throttle.html b/legacy/v2.4.0-lsm/adrs/adr-002-throttle.html new file mode 100644 index 0000000000..000bb45f67 --- /dev/null +++ b/legacy/v2.4.0-lsm/adrs/adr-002-throttle.html @@ -0,0 +1,19 @@ + + + + + +Jail Throttling | Interchain Security + + + + +
+
Version: v2.4.0-lsm

ADR 002: Jail Throttling

Changelog

  • 2023-01-26: Initial Draft
  • 2023-02-07: Property refined, ADR ready to review/merge

Status

Accepted

Context

The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols. In practice, this assumption may not hold. A malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider.

Before the throttling feature was implemented, the following attack was possible. Attacker(s) would create provider validators just below the provider's active set. Using a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once. Control of the provider would then pass over to the attackers' validators. This enables the attacker(s) to halt the provider. Or even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC.

Decision

The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack. Ie. this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time.

State Required - Slash Meter

There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time. This meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params.

State Required - Global entry queue

There exists a single queue which stores "global slash entries". These entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering. This queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.

State Required - Per-chain data queue

For each established consumer, there exists a queue which stores "throttled packet data". Ie. pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering. Order is enforced by IBC sequence number. These "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.

Reasoning - Multiple queues

For reasoning on why this feature was implemented with multiple queues, see spec. Specifically the section on VSC Maturity and Slashing Order. There are other ways to ensure such a property (like a queue of linked lists, etc.), but the implemented protocol seemed to be the most understandable and easiest to implement with a KV store.

Protocol Overview - OnRecvSlashPacket

Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:

  1. A global slash entry is queued.
  2. The data of such a packet is added to the per-chain queue.

Protocol Overview - OnRecvVSCMaturedPacket

Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue.

Endblocker Step 1 - Slash Meter Replenishment

Once the slash meter becomes not full, it'll be replenished after SlashMeterReplenishPeriod (param) by incrementing the meter with its allowance for the replenishment block, where allowance = SlashMeterReplenishFraction (param) * currentTotalVotingPower. The slash meter will never exceed its current allowance (fn of the total voting power for the block) in value. Note a few things:

  1. The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power. In such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods.
  2. Total voting power of a chain changes over time, especially as validators are jailed. As validators are jailed, total voting power decreases, and so does the jailing allowance. See below for more detailed throttling property discussion.
  3. The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1. If the SlashMeterReplenishFraction (param) is set too low, integer rounding will put this minimum value into effect. That is, if SlashMeterReplenishFraction * currentTotalVotingPower < 1, then the effective allowance would be 1. This min value of allowance ensures that there's some packets handled over time, even if that is a very long time. It's a crude solution to an edge case caused by too small of a replenishment fraction.

The behavior described above is achieved by executing CheckForSlashMeterReplenishment() every endblock, BEFORE HandleThrottleQueues() is executed.

Endblocker Step 2 - HandleLeadingVSCMaturedPackets

Every block it is possible that VSCMatured packet data was queued before any slash packet data. Since this "leading" VSCMatured packet data does not have to be throttled (see VSC Maturity and Slashing Order), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes.

Endblocker Step 3 - HandleThrottleQueues

Every endblocker the following pseudo-code is executed to handle data from the throttle queues.

meter := getSlashMeter()

// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist
while meter.IsPositiveOrZero() && entriesExist() {
// Get next entry in queue
entry := getNextGlobalSlashEntry()
// Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet
valPower := entry.getValPower()
meter = meter - valPower
// Using the per-chain queue, handle the single slash packet using its queued data,
// then handle all trailing VSCMatured packets for this consumer
handleSlashPacketAndTrailingVSCMaturedPackets(entry)
// Delete entry in global queue, delete handled data
entry.Delete()
deleteThrottledSlashPacketData()
deleteTrailingVSCMaturedPacketData()
}

System Properties

All CCV system properties should be maintained by implementing this feature, see: CCV spec - Consumer Initiated Slashing.

One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than MaxThrottledPackets (param), then the provider binary will panic, and the provider chain will halt. Therefore this param should be set carefully. See SetThrottledPacketDataSize. This behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators.

Main Throttling Property

Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions.

First, we define the following:

  • A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.
  • The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.
  • There is a list of honest validators s.t if they are jailed, X% of the initial validator set will be jailed.

For the following property to hold, these assumptions must be true:

  1. We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack.
  2. No validator has more than SlashMeterReplenishFraction of total voting power on the provider.
  3. SlashMeterReplenishFraction is large enough that SlashMeterReplenishFraction * currentTotalVotingPower > 1. Ie. the replenish fraction is set high enough that we can ignore the effects of rounding.
  4. SlashMeterReplenishPeriod is sufficiently longer than the time it takes to produce a block.

Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined.

Property:

The time it takes to jail/tombstone X% of the initial validator set will be greater than or equal to (X * SlashMeterReplenishPeriod / SlashMeterReplenishFraction) - 2 * SlashMeterReplenishPeriod

Intuition:

Let's use the following notation:

  • $C$: Number of replenishment cycles
  • $P$: $\text{SlashMeterReplenishPeriod}$
  • $F$: $\text{SlashMeterReplenishFraction}$
  • $V_{\mathit{max}}$: Max power of a validator as a fraction of total voting power

In $C$ number of replenishment cycles, the fraction of total voting power that can be removed, $a$, is $a \leq F \cdot C + V{\mathit{max}}$ (where $V{\mathit{max}}$ is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value).

So, we need at least $C \geq \frac{a - V_{\mathit{max}}}{F}$ cycles to remove $a$ fraction of the total voting power.

Since we defined the start of the attack to be the moment when the first slash request arrives, then $F$ fraction of the initial validator set can be jailed immediately. For the remaining $X - F$ fraction of the initial validator set to be jailed, it takes at least $C \geq \frac{(X - F) - V{\mathit{max}}}{F}$ cycles. Using the assumption that $V{\mathit{max}} \leq F$ (assumption 2), we get $C \geq \frac{X - 2F}{F}$ cycles.

In order to execute $C$ cycles, we need $C \cdot P$ time.

Thus, jailing the remaining $X - F$ fraction of the initial validator set corresponds to $\frac{P \cdot (X - 2F)}{F}$ time.

In other words, the attack must take at least $\frac{P \cdot X}{F} - 2P$ time (in the units of replenish period $P$).

This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests. For example, if SlashMeterReplenishFraction is set to 0.06, then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub. Note that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power.

Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings.

How Unjailing Affects the Main Throttling Property

Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained.

If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider.

In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack.

Consequences

Positive

  • The described attack is slowed down in seemingly all cases.
  • If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded.

Negative

  • Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below. However, this is sacrificing liveness in a edge case scenario for the sake of security. As an improvement, using retries would fully prevent this attack vector.

Neutral

  • Additional state is introduced to the provider chain.
  • VSCMatured and slash packet data is not always handled in the same block that it is received.

References

+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/adrs/adr-002-throttle.html.html b/legacy/v2.4.0-lsm/adrs/adr-002-throttle.html.html new file mode 100644 index 0000000000..a7eec812e8 --- /dev/null +++ b/legacy/v2.4.0-lsm/adrs/adr-002-throttle.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposal.html b/legacy/v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposal.html new file mode 100644 index 0000000000..60816ccc1a --- /dev/null +++ b/legacy/v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposal.html @@ -0,0 +1,19 @@ + + + + + +Equivocation governance proposal | Interchain Security + + + + +
+
Version: v2.4.0-lsm

ADR 003: Equivocation governance proposal

Changelog

  • 2023-02-06: Initial draft

Status

Accepted

Context

We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain.

For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence.

Decision

To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain.

A new kind of governance proposal is added to the provider module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain.

If such proposal passes, the proposal handler delegates to the evidence module to process the equivocation. This module ensures the evidence isn’t too old, or else ignores it (see code). Too old is determined by 2 consensus params :

  • evidence.max_age_duration number of nanoseconds before an evidence is considered too old
  • evidence.max_age_numblocks number of blocks before an evidence is considered too old.

On the hub, those parameters are equals to

// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682
(...)
"evidence": {
"max_age_num_blocks": "1000000",
"max_age_duration": "172800000000000",
(...)
},
(...)

A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the evidence module when the proposal passes and is handled by the hub.

For max_age_num_blocks=1M, the parameter is big enough if we consider the hub produces 12k blocks per day (blocks_per_year/365 = 436,0000/365). The evidence can be up to 83 days old (1,000,000/12,000) and not be ignored.

For max_age_duration=172,800,000,000,000, the parameter is too low, because the value is in nanoseconds so it’s 2 days. Fortunately the condition that checks those 2 parameters uses a AND, so if max_age_num_blocks condition passes, the evidence won’t be ignored.

Consequences

Positive

  • Remove the possibility from a malicious consumer chain to “attack” the provider chain by slashing/jailing validators.
  • Provide a more acceptable implementation for the validator community.

Negative

  • Punishment action of double-signing isn’t “automated”, a governance proposal is required which takes more time.
  • You need to pay 250ATOM to submit an equivocation evidence.

Neutral

References

+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposal.html.html b/legacy/v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposal.html.html new file mode 100644 index 0000000000..ab7faf0dc4 --- /dev/null +++ b/legacy/v2.4.0-lsm/adrs/adr-003-equivocation-gov-proposal.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verification.html b/legacy/v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verification.html new file mode 100644 index 0000000000..7cbb2d3968 --- /dev/null +++ b/legacy/v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verification.html @@ -0,0 +1,85 @@ + + + + + +Cryptographic verification of equivocation evidence | Interchain Security + + + + +
+
Version: v2.4.0-lsm

ADR 005: Cryptographic verification of equivocation evidence

Changelog

  • 5/1/2023: First draft
  • 7/23/2023: Add light client attacks handling
  • 9/6/2023: Add double signing attacks handling
  • 11/3/2023: Update limitations to clarify amnesia attacks are ignored

Status

Accepted

Context

Currently, we use a governance proposal to slash validators for equivocation (double signing and light client attacks). +Every proposal needs to go through a (two weeks) voting period before it can be approved. +Given a three-week unbonding period, this means that an equivocation proposal needs to be submitted within one week since the infraction occurred.

This ADR proposes a system to slash validators automatically for equivocation, immediately upon the provider chain's receipt of the evidence. Another thing to note is that we intend to introduce this system in stages, since even the partial ability to slash and/or tombstone is a strict improvement in security. +The feature is implemented in two parts, each with its dedicated endpoint. One endpoint handles light client attacks, while the other handles double signing attacks.

Light Client Attack

In a nutshell, the light client is a process that solely verifies a specific state machine's +consensus without executing the transactions. The light clients get new headers by querying +multiple nodes, called primary and witness nodes.

Light clients download new headers committed on chain from a primary. Headers can be verified in two ways: sequentially, +where the block height of headers is serial, or using skipping. This second verification method allows light clients to download headers +with nonconsecutive block height, where some intermediate headers are skipped (see Tendermint Light Client, Figure 1 and Figure 3). +Additionally, light clients are cross-checking new headers obtained from a primary with witnesses to ensure all nodes share the same state.

A light client attack occurs when a Byzantine validator sends invalid headers to a light client. +As the light client doesn't execute transactions, it can be deceived into trusting corrupted application state transitions. +For instance, if a light client receives header A from the primary and header B from a witness for the same block height H, +and both headers are successfully verified, it indicates a light client attack. +Note that in this case, either the primary or the witness or both are malicious.

The types of light client attacks are defined by analyzing the differences between the conflicting headers. +There are three types of light client attacks: lunatic attack, equivocation attack, and amnesia attack. +For details, see the CometBFT specification.

When a light client agent detects two conflicting headers, it will initially verify their traces (see cometBFT detector) using its primary and witness nodes. +If these headers pass successful verification, the Byzantine validators will be identified based on the header's commit signatures +and the type of light client attack. The agent will then transmit this information to its nodes using a LightClientAttackEvidence evidence to be eventually voted on and added to a block. +Note that from a light client agent perspective, it is not possible to establish whether a primary or a witness node, or both, are malicious. +Therefore, it will create and send two evidences: one against the primary (sent to the witness), and one against the witness (sent to the primary). +Both nodes will then verify it before broadcasting it and adding it to the evidence pool. +If an evidence is finally committed to a block, the chain's evidence module will execute it, resulting in the jailing and the slashing of the validators responsible for the light client attack.

Light clients are a core component of IBC. In the event of a light client attack, IBC relayers notify the affected chains by submitting an IBC misbehavior message. +A misbehavior message includes the conflicting headers that constitute a light client attack evidence. Upon receiving such a message, +a chain will first verify whether these headers would have convinced its light client. This verification is achieved by checking +the header states against the light client consensus states (see IBC misbehaviour handler). If the misbehaviour is successfully verified, the chain will then "freeze" the +light client, halting any further trust in or updating of its states.

Double Signing Attack

A double signing attack, also known as equivocation, +occurs when a validator votes for two different blocks in the same round of the CometBFT consensus. +This consensus mechanism operates with multiple voting rounds at each block height, +and it strictly prohibits sending two votes of the same type during a round +(see CometBFT State Machine Overview).

When a node observes two votes from the same peer, it will use these two votes to create +a DuplicateVoteEvidence +evidence and gossip it to the other nodes in the network +(see CometBFT equivocation detection). +Each node will then verify the evidence according to the CometBFT rules that define a valid double signing infraction, and based on this verification, they will decide whether to add the evidence to a block. +During the evidence verification process, the signatures of the conflicting votes must be verified successfully. +Note that this is achieved using the public key of the misbehaving validator, along with the chain ID of the chain where the infraction occurred (see CometBFT equivocation verification).

Once a double signing evidence is committed to a block, the consensus layer will report the equivocation to the evidence module of the Cosmos SDK application layer. +The application will, in turn, punish the malicious validator through jailing, tombstoning and slashing +(see handleEquivocationEvidence).

Decision

Light Client Attack

In the first part of the feature, we introduce a new endpoint: HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour). +The main idea is to leverage the current IBC misbehaviour handling and update it to solely jail and slash the validators that +performed a light client attack. Note that in this context, we assume that chains connected via a light client +share the same validator set, as is the case with Replicated Security.

This endpoint reuses the IBC client libraries to verify that the misbehaviour headers would have fooled the light client. +Additionally, it’s crucial that the endpoint logic results in the slashing and jailing of validators under the same conditions +as a light client agent detector. Therefore, the endpoint ensures that the two conditions are met: +the headers in the misbehaviour message have the same block height, and +the light client isn’t expired.

After having successfully verified a misbehaviour, the endpoint executes the jailing and slashing of the malicious validators similarly as in the evidence module.

Double Signing Attack

In the second part of the feature, we introduce a new endpoint HandleConsumerDoubleVoting( +ctx sdk.Context, evidence *tmtypes.DuplicateVoteEvidence, chainID string, pubkey cryptotypes.PubKey). +Simply put, the handling logic verifies a double signing evidence against a provided +public key and chain ID and, if successful, executes the jailing of the malicious validator who double voted.

We define a new +MsgSubmitConsumerDoubleVoting message to report a double voting evidence observed +on a consumer chain to the endpoint of the provider chain. This message contains two fields: +a double signing evidence +duplicate_vote_evidence and a light client header for the infraction block height, +referred to as infraction_block_header. +The latter provides the malicious validator's public key and the chain ID required to verify the signature of the votes contained in the evidence.

Note that double signing evidence is not verified using the same conditions as in the implementation CometBFT (see +verify(evidence types.Evidence) method). Specifically, we do not check that the evidence hasn't expired. +More details can be found in the "Current limitations" section below.

Upon a successful equivocation verification, the misbehaving validator is jailed for the maximum time +(see DoubleSignJailEndTime +in the SDK evidence module).

Current limitations:

  • We cannot derive an infraction height from the evidence, so it is only possible to jail validators, not actually slash them. +To explain the technical reasons behind this limitation, let's recap the initial consumer initiated slashing logic. +In a nutshell, consumer heights are mapped to provider heights through VSCPackets, namely through the so called vscIDs. +When an infraction occurs on the consumer, a SlashPacket containing the vscID obtained from mapping the consumer infraction height +is sent to the provider. Upon receiving the packet, the provider maps the consumer infraction height to a local infraction height, +which is used to slash the misbehaving validator. In the context of untrusted consumer chains, all their states, including vscIDs, +could be corrupted and therefore cannot be used for slashing purposes.

  • For the same reasons explained above, the age of a consumer double signing evidence can't be verified, +either using its infraction height or its unsigned timestamp. Note that changes the jailing behaviour, potentially leading to a validator's jailing based on some "old" evidence from a consumer, which wouldn't occur if the consumer were a standalone chain.

  • In the first stage of this feature, validators are jailed indefinitely without being tombstoned. +The underlying reason is that a malicious validator could take advantage of getting tombstoned +to avoid being slashed on the provider (see comment).

  • Currently, the endpoint can only handle equivocation light client attacks. This is because the lunatic attacks require the endpoint to possess the ability to dissociate which header is conflicted or trusted upon receiving a misbehavior message. Without this information, it's not possible to extract the Byzantine validators from the conflicting headers (see comment). In addition, "amnesia" attacks are ignored, similar to CometBFT (see ADR-056).

Consequences

Positive

  • It is now possible for the provider chain to jail validators who committed +light client or double signing attacks on a consumer chain.

Negative

  • N/A

References

+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verification.html.html b/legacy/v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verification.html.html new file mode 100644 index 0000000000..7c249e3236 --- /dev/null +++ b/legacy/v2.4.0-lsm/adrs/adr-005-cryptographic-equivocation-verification.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/adrs/adr-013-equivocation-slashing.html b/legacy/v2.4.0-lsm/adrs/adr-013-equivocation-slashing.html new file mode 100644 index 0000000000..15b0506910 --- /dev/null +++ b/legacy/v2.4.0-lsm/adrs/adr-013-equivocation-slashing.html @@ -0,0 +1,39 @@ + + + + + +Slashing on the provider for consumer equivocation | Interchain Security + + + + +
+
Version: v2.4.0-lsm

ADR 013: Slashing on the provider for consumer equivocation

Changelog

  • 1st Sept. 2023: Initial draft

Status

Proposed

Context

This ADR presents some approaches on how to slash on the provider chain validators that performed equivocations on consumer chains. +Currently, the provider chain can receive and verify evidence of equivocation, but it cannot slash the misbehaving validator.

In the remainder of this section, we explain how slashing is performed on a single chain and show why slashing on the provider for equivocation on the consumer is challenging.

Note that future versions of the Cosmos SDK, CometBFT, and ibc-go could modify the way we slash, etc. Therefore, a future reader of this ADR, should note that when we refer to Cosmos SDK, CometBFT, and ibc-go we specifically refer to their v0.47, v0.37 and v7.3.0 versions respectively.

Single-chain slashing

Slashing is implemented across the slashing +and staking modules. +The slashing module's keeper calls the staking module's Slash() method, passing among others, the infractionHeight (i.e., the height when the equivocation occurred), the validator's power at the infraction height, and the slashFactor (currently set to 5% in case of equivocation on the Cosmos Hub).

Slashing undelegations and redelegations

To slash undelegations, Slash goes through all undelegations and checks whether they started before or after the infraction occurred. If an undelegation started before the infractionHeight, then it is not slashed, otherwise it is slashed by slashFactor.

The slashing of redelegations happens in a similar way, meaning that Slash goes through all redelegations and checks whether the redelegations started before or after the infractionHeight.

Slashing delegations

Besides undelegations and redelegations, the validator's delegations need to also be slashed. +This is performed by deducting the appropriate amount of tokens from the validator. Note that this deduction is computed based on the voting power the misbehaving validator had at the height of the equivocation. As a result of the tokens deduction, +the tokens per share +reduce and hence later on, when delegators undelegate or redelegate, the delegators retrieve back less +tokens, effectively having their tokens slashed. The rationale behind this slashing mechanism, as mentioned in the Cosmos SDK documentation

[...] is to simplify the accounting around slashing. Rather than iteratively slashing the tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, effectively reducing the value of each issued delegator share.

This approach of slashing delegations does not utilize the +infractionHeight in any way and hence the following scenario could occur:

  1. a validator V performs an equivocation at a height Hi
  2. a new delegator D delegates to V after height Hi
  3. evidence of the equivocation by validator V is received
  4. the tokens of delegator D are slashed

In the above scenario, delegator D is slashed, even though D's voting power did not contribute to the infraction.

Old evidence

In the single-chain case, old evidence (e.g., from 3 years ago) is ignored. This is achieved through +CometBFT that ignores old evidence based on the parameters MaxAgeNumBlocks and MaxAgeDuration (see here). +Additionally, note that when the evidence is sent by CometBFT to the application, the evidence is rechecked in the evidence module of Cosmos SDK and if it is old, the evidence is ignored. +In Cosmos Hub, the MaxAgeNumBlocks is set to 1000000 (i.e., ~70 days if we assume we need ~6 sec per block) and MaxAgeDuration is set to 172800000000000 ns (i.e., 2 days). Because of this check, we can easily exclude old evidence.

Slashing for equivocation on the consumer

In the single-chain case, slashing requires both the infractionHeight and the voting power. +In order to slash on the provider for an equivocation on a consumer, we need to have both the provider's infractionHeight and voting power. +Note that the infractionHeight on the consumer chain must be mapped to a height on the provider chain. +Unless we have a way to find the corresponding infractionHeight and power on the provider chain, we cannot slash for equivocation on the consumer in the same way as we would slash in the single-chain case.

The challenge of figuring out the corresponding infractionHeight and power values on the provider chain is due to the following trust assumption:

  • We trust the consensus layer and validator set of the consumer chains, but we do not trust the application layer.

As a result, we cannot trust anything that stems from the application state of a consumer chain.

Note that when a relayer or a user sends evidence through a MsgSubmitConsumerDoubleVoting message, the provider gets access to DuplicateVoteEvidence:

type DuplicateVoteEvidence struct {
VoteA *Vote `json:"vote_a"`
VoteB *Vote `json:"vote_b"`

// abci specific information
TotalVotingPower int64
ValidatorPower int64
Timestamp time.Time
}

The "abci specific information" fields cannot be trusted because they are not signed. Therefore, +we can use neither ValidatorPower for slashing on the provider chain, nor the Timestamp to check the evidence age. We can get the infractionHeight from the votes, but this infractionHeight corresponds to the infraction height on the consumer and not on the provider chain. +Similarly, when a relayer or a user sends evidence through a MsgSubmitConsumerMisbehaviour message, the provider gets access to Misbehaviour that we cannot use to extract the infraction height, power, or the time on the provider chain.

Proposed solution

As a first iteration, we propose the following approach. At the moment the provider receives evidence of equivocation on a consumer:

  1. slash all the undelegations and redelegations using slashFactor;
  2. slash all delegations using as voting power the sum of the voting power of the misbehaving validator and the power of all the ongoing undelegations and redelegations.

Evidence expiration: Additionally, because we cannot infer the actual time of the evidence (i.e., the timestamp of the evidence cannot be trusted), we do not consider evidence expiration and hence old evidence is never ignored (e.g., the provider would act on 3 year-old evidence of equivocation on a consumer). +Additionally, we do not need to store equivocation evidence to avoid slashing a validator more than once, because we do not slash tombstoned validators and we tombstone a validator when slashed.

We do not act on evidence that was signed by a validator consensus key that is pruned when we receive the evidence. We prune a validator's consensus key if the validator has assigned a new consumer key (using MsgAssignConsumerKey) and an unbonding period on the consumer chain has elapsed (see key assignment ADR). Note that the provider chain is informed that the unbonding period has elapsed on the consumer when the provider receives a VSCMaturedPacket and because of this, if the consumer delays the sending of a VSCMaturedPacket, we would delay the pruning of the key as well.

Implementation

The following logic needs to be added to the HandleConsumerDoubleVoting and HandleConsumerMisbehaviour methods:

undelegationsInTokens := sdk.NewInt(0)
for _, v := range k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validatorAddress) {
for _, entry := range v.Entries {
if entry.IsMature(now) && !entry.OnHold() {
// undelegation no longer eligible for slashing, skip it
continue
}
undelegationsInTokens = undelegationsInTokens.Add(entry.InitialBalance)
}
}

redelegationsInTokens := sdk.NewInt(0)
for _, v := range k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validatorAddress) {
for _, entry := range v.Entries {
if entry.IsMature(now) && !entry.OnHold() {
// redelegation no longer eligible for slashing, skip it
continue
}
redelegationsInTokens = redelegationsInTokens.Add(entry.InitialBalance)
}
}

infractionHeight := 0
undelegationsAndRedelegationsInPower = sdk.TokensToConsensusPower(undelegationsInTokens.Add(redelegationsInTokens))
totalPower := validator's voting power + undelegationsAndRedelegationsInPower
slashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)

k.stakingKeeper.Slash(ctx, validatorConsAddress, infractionHeight, totalPower, slashFraction, DoubleSign)

Infraction height: We provide a zero infractionHeight to the Slash method in order to slash all ongoing undelegations and redelegations (see checks in Slash, SlashUnbondingDelegation, and SlashRedelegation).

Power: We pass the sum of the voting power of the misbehaving validator when the evidence was received (i.e., at evidence height) and the power of all the ongoing undelegations and redelegations. +If we assume that the slashFactor is 5%, then the voting power we pass is power + totalPower(undelegations) + totalPower(redelegations). +Hence, when the Slash method slashes all the undelegations and redelegations it would end up with 0.05 * power + 0.05 * totalPower(undelegations) + 0.05 * totalPower(redelegations) - 0.05 * totalPower(undelegations) - 0.05 * totalPower(redelegations) = 0.05 * power and hence it would slash 5% of the validator's power when the evidence is received.

Positive

With the proposed approach we can quickly implement slashing functionality on the provider chain for consumer chain equivocations. +This approach does not need to change the staking module and therefore does not change in any way how slashing is performed today for a single chain.

Negative

  • We definitely slash more when it comes to undelegations and redelegations because we slash for all of them without considering an infractionHeight.
  • We potentially slash more than what we would have slashed if we knew the voting power at the corresponding infractionHeight in the provider chain.
  • We slash on old evidence of equivocation on a consumer.

References

+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/adrs/adr-013-equivocation-slashing.html.html b/legacy/v2.4.0-lsm/adrs/adr-013-equivocation-slashing.html.html new file mode 100644 index 0000000000..07aa9876fb --- /dev/null +++ b/legacy/v2.4.0-lsm/adrs/adr-013-equivocation-slashing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/adrs/adr-template.html b/legacy/v2.4.0-lsm/adrs/adr-template.html new file mode 100644 index 0000000000..8262055c57 --- /dev/null +++ b/legacy/v2.4.0-lsm/adrs/adr-template.html @@ -0,0 +1,22 @@ + + + + + +ADR Template | Interchain Security + + + + +
+
Version: v2.4.0-lsm

ADR {ADR-NUMBER}: {TITLE}

Changelog

  • {date}: {changelog}

Status

A decision may be "proposed" if it hasn't been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement.

{Deprecated|Proposed|Accepted}

Context

This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution.

Decision

This section explains all of the details of the proposed solution, including implementation details. +It should also describe affects / corollary items that may need to be changed as a part of this. +If the proposed change will be large, please also indicate a way to do the change to maximize ease of review. +(e.g. the optimal split of things to do between separate PR's)

Consequences

This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones.

Positive

Negative

Neutral

References

Are there any relevant PR comments, issues that led up to this, or articles referrenced for why we made the given design choice? If so link them here!

  • {reference link}
+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/adrs/adr-template.html.html b/legacy/v2.4.0-lsm/adrs/adr-template.html.html new file mode 100644 index 0000000000..9c02892401 --- /dev/null +++ b/legacy/v2.4.0-lsm/adrs/adr-template.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/adrs/intro.html b/legacy/v2.4.0-lsm/adrs/intro.html new file mode 100644 index 0000000000..3c8e65ca02 --- /dev/null +++ b/legacy/v2.4.0-lsm/adrs/intro.html @@ -0,0 +1,22 @@ + + + + + +ADRs | Interchain Security + + + + +
+
Version: v2.4.0-lsm

Architecture Decision Records (ADR)

This is a location to record all high-level architecture decisions in the Interchain Security project.

You can read more about the ADR concept in this blog post.

An ADR should provide:

  • Context on the relevant goals and the current state
  • Proposed changes to achieve the goals
  • Summary of pros and cons
  • References
  • Changelog

Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and +justification for a change in architecture, or for the architecture of something +new. The spec is much more compressed and streamlined summary of everything as +it is or should be.

If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match.

Note the context/background should be written in the present tense.

To suggest an ADR, please make use of the ADR template provided.

Table of Contents

ADR #DescriptionStatus
001Consumer chain key assignmentAccepted, Implemented
002Jail ThrottlingAccepted, Implemented
003Equivocation governance proposalAccepted, Implemented
+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/adrs/intro.html.html b/legacy/v2.4.0-lsm/adrs/intro.html.html new file mode 100644 index 0000000000..88f37a5414 --- /dev/null +++ b/legacy/v2.4.0-lsm/adrs/intro.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/consumer-development/app-integration.html b/legacy/v2.4.0-lsm/consumer-development/app-integration.html new file mode 100644 index 0000000000..8d29c68a70 --- /dev/null +++ b/legacy/v2.4.0-lsm/consumer-development/app-integration.html @@ -0,0 +1,23 @@ + + + + + +Developing an ICS consumer chain | Interchain Security + + + + +
+
Version: v2.4.0-lsm

Developing an ICS consumer chain

When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol. +To help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications.

Basic consumer chain

The source code for the example app can be found here.

Please note that consumer chains do not implement the staking module - the validator set is replicated from the provider, meaning that the provider and the consumer use the same validator set and their stake on the provider directly determines their stake on the consumer. +At present there is no opt-in mechanism available, so all validators of the provider must also validate on the provider chain.

Your chain should import the consumer module from x/consumer and register it in the correct places in your app.go. +The x/consumer module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in. +You should not need to manage or override any code from the x/consumer module.

Democracy consumer chain

The source code for the example app can be found here.

This type of consumer chain wraps the basic CosmosSDK x/distribution, x/staking and x/governance modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system.

This allows the consumer chain to leverage those modules while also using the x/consumer module.

With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.

Standalone chain to consumer chain changeover

This feature is being actively worked on. Information will be provided at a later time.

+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/consumer-development/app-integration.html.html b/legacy/v2.4.0-lsm/consumer-development/app-integration.html.html new file mode 100644 index 0000000000..adeec13ec0 --- /dev/null +++ b/legacy/v2.4.0-lsm/consumer-development/app-integration.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/consumer-development/consumer-chain-governance.html b/legacy/v2.4.0-lsm/consumer-development/consumer-chain-governance.html new file mode 100644 index 0000000000..78b79828a1 --- /dev/null +++ b/legacy/v2.4.0-lsm/consumer-development/consumer-chain-governance.html @@ -0,0 +1,19 @@ + + + + + +Consumer Chain Governance | Interchain Security + + + + +
+
Version: v2.4.0-lsm

Consumer Chain Governance

Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We'll cover what these are in the "Whitelist" section below.

Democracy module

The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy.

Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus.

For an example, see the Democracy Consumer

CosmWasm

There several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain.

For an example, see Neutron.

The Whitelist

Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see Neutron's whitelist.

+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/consumer-development/consumer-chain-governance.html.html b/legacy/v2.4.0-lsm/consumer-development/consumer-chain-governance.html.html new file mode 100644 index 0000000000..b5d24c5e96 --- /dev/null +++ b/legacy/v2.4.0-lsm/consumer-development/consumer-chain-governance.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/consumer-development/consumer-chain-upgrade-procedure.html b/legacy/v2.4.0-lsm/consumer-development/consumer-chain-upgrade-procedure.html new file mode 100644 index 0000000000..c00a00d824 --- /dev/null +++ b/legacy/v2.4.0-lsm/consumer-development/consumer-chain-upgrade-procedure.html @@ -0,0 +1,19 @@ + + + + + +Upgrading Consumer Chains | Interchain Security + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/consumer-development/consumer-chain-upgrade-procedure.html.html b/legacy/v2.4.0-lsm/consumer-development/consumer-chain-upgrade-procedure.html.html new file mode 100644 index 0000000000..40a04187dc --- /dev/null +++ b/legacy/v2.4.0-lsm/consumer-development/consumer-chain-upgrade-procedure.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/consumer-development/offboarding.html b/legacy/v2.4.0-lsm/consumer-development/offboarding.html new file mode 100644 index 0000000000..c946fea126 --- /dev/null +++ b/legacy/v2.4.0-lsm/consumer-development/offboarding.html @@ -0,0 +1,19 @@ + + + + + +Offboarding Checklist | Interchain Security + + + + +
+
Version: v2.4.0-lsm

Consumer Offboarding

To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).

// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.
// If it passes, all the consumer chain's state is removed from the provider chain. The outstanding unbonding
// operation funds are released.
{
// the title of the proposal
"title": "This was a great chain",
"description": "Here is a .md formatted string specifying removal details",
// the chain-id of the consumer chain to be stopped
"chain_id": "consumerchain-1",
// the time on the provider chain at which all validators are responsible to stop their consumer chain validator node
"stop_time": "2023-03-07T12:40:00.000000Z",
}

More information will be listed in a future version of this document.

+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/consumer-development/offboarding.html.html b/legacy/v2.4.0-lsm/consumer-development/offboarding.html.html new file mode 100644 index 0000000000..ea3f596d36 --- /dev/null +++ b/legacy/v2.4.0-lsm/consumer-development/offboarding.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/consumer-development/onboarding.html b/legacy/v2.4.0-lsm/consumer-development/onboarding.html new file mode 100644 index 0000000000..0e0f7a69ad --- /dev/null +++ b/legacy/v2.4.0-lsm/consumer-development/onboarding.html @@ -0,0 +1,20 @@ + + + + + +Onboarding Checklist | Interchain Security + + + + +
+
Version: v2.4.0-lsm

Consumer Onboarding Checklist

The following checklists will aid in onboarding a new consumer chain to replicated security.

Additionally, you can check the testnet repo for a comprehensive guide on preparing and launching consumer chains.

1. Complete testing & integration

  • test integration with gaia
  • test your protocol with supported relayer versions (minimum hermes 1.4.1)
  • reach out to the ICS team if you are facing issues

2. Create an Onboarding Repository

To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain.

This should include (at minimum):

  • genesis.json witout CCV data (before the propsal passes)
  • genesis.json with CCV data (after spawn time passes)
  • information about relevant seed/peer nodes you are running
  • relayer information (compatible versions)
  • copy of your governance proposal (as JSON)
  • a script showing how to start your chain and connect to peers (optional)
  • take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable

Example of such a repository can be found here.

3. Submit a Governance Proposal

Before you submit a ConsumerChainAddition proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch. +If possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues.

Additionally, reach out to the community via the forum to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers.

  • determine your chain's spawn time
  • determine consumer chain parameters to be put in the proposal
  • take note to include a link to your onboarding repository
  • describe the purpose and benefits of running your chain

Example of a consumer chain addition proposal.

// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.
// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.
// It is recommended that spawn time occurs after the proposal end time.
{
// Title of the proposal
"title": "Add consumer chain",
// Description of the proposal
// format the text as a .md file and include the file in your onboarding repository
"description": ".md description of your chain and all other relevant information",
// Proposed chain-id of the new consumer chain.
// Must be unique from all other consumer chain ids of the executing provider chain.
"chain_id": "newchain-1",
// Initial height of new consumer chain.
// For a completely new chain, this will be {0,1}.
"initial_height" : {
"revision_height": 0,
"revision_number": 1,
},
// Hash of the consumer chain genesis state without the consumer CCV module genesis params.
// It is used for off-chain confirmation of genesis.json validity by validators and other parties.
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
// Hash of the consumer chain binary that should be run by validators on chain initialization.
// It is used for off-chain confirmation of binary validity by validators and other parties.
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
// Unbonding period for the consumer chain.
// It should should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
// IBC transfer packets will timeout after this interval elapses.
"transfer_timeout_period": 1800000000000,
// The fraction of tokens allocated to the consumer redistribution address during distribution events.
// The fraction is a string representing a decimal number. For example "0.75" would represent 75%.
// The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.
"consumer_redistribution_fraction": "0.75",
// BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.
// eg. send rewards to the provider every 1000 blocks
"blocks_per_distribution_transmission": 1000,
// The number of historical info entries to persist in store.
// This param is a part of the cosmos sdk staking module. In the case of
// a ccv enabled consumer chain, the ccv module acts as the staking module.
"historical_entries": 10000,
// The ID of a token transfer channel used for the Reward Distribution
// sub-protocol. If DistributionTransmissionChannel == "", a new transfer
// channel is created on top of the same connection as the CCV channel.
// Note that transfer_channel_id is the ID of the channel end on the consumer chain.
// it is most relevant for chains performing a sovereign to consumer changeover
// in order to maintan the existing ibc transfer channel
"distribution_transmission_channel": "channel-123"
}

4. Launch

The consumer chain starts after at least 66.67% of all provider's voting power comes online. The consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer

  • provide a repo with onboarding instructions for validators (it should already be listed in the proposal)
  • genesis.json with ccv data populated (MUST contain the initial validator set)
  • maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)
  • have a block explorer in place to track chain activity & health
+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/consumer-development/onboarding.html.html b/legacy/v2.4.0-lsm/consumer-development/onboarding.html.html new file mode 100644 index 0000000000..490a343a69 --- /dev/null +++ b/legacy/v2.4.0-lsm/consumer-development/onboarding.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/faq.html b/legacy/v2.4.0-lsm/faq.html new file mode 100644 index 0000000000..1ea2c032b3 --- /dev/null +++ b/legacy/v2.4.0-lsm/faq.html @@ -0,0 +1,24 @@ + + + + + +Frequently Asked Questions | Interchain Security + + + + +
+
Version: v2.4.0-lsm

Frequently Asked Questions

What is the meaning of Validator Set Replication?

VSR simply means that the same validator set is used to secure both the provider and consumer chains. VSR is ensured through ICS protocol which keeps consumers up to date with the validator set of the provider.

What even is a consumer chain?

Consumer chain is blockchain operated by the same validator operators as the provider chain. The ICS protocol ensures the validator set replication properties (informs consumer chain about the current state of the validator set on the provider)

Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements.

What happens to consumer if provider is down?

In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set.

The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness.

However, if the trusting_period (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain. +This means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about.

Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point. +At the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.

What happens to provider if consumer is down?

Consumer chains do not impact the provider chain. +The ICS protocol is concerned only with validator set replication and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events).

Can I run the provider and consumer chains on the same machine?

Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation.

Can the consumer chain have its own token?

As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees.

How are Tx fees paid on consumer?

The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations.

Are there any restrictions the consumer chains need to abide by?

No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way. +The only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain.

What's in it for the validators and stakers?

The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by consumer_redistribution_fraction. The rewards are distributed (sent to the provider) every blocks_per_distribution_transmission.

note

consumer_redistribution_fraction and blocks_per_distribution_transmission are parameters defined in the ConsumerAdditionProposal used to create the consumer chain. These parameters can be changed via consumer chain governance.

Can the consumer chain have its own governance?

Yes.

In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.

Validators can also be representatives but representatives are not required to run validator nodes.

This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance.

Can validators opt-out of replicated security?

At present, the validators cannot opt-out of validating consumer chains.

There are multiple opt-out mechanisms under active research.

How does Equivocation Governance Slashing work?

To avoid potential attacks directed at provider chain validators, a new mechanism was introduced:

When a validator double-signs on the consumer chain, a special type of slash packet is relayed to the provider chain. The provider will store information about the double signing validator and allow a governance proposal to be submitted. +If the double-signing proposal passes, the offending validator will be slashed on the provider chain and tombstoned. Tombstoning will permanently exclude the validator from the active set of the provider.

caution

An equivocation proposal cannot be submitted for a validator that did not double sign on any of the consumer chains.

Can Consumer Chains perform Software Upgrades?

Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM).

Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module.

How can I connect to the testnets?

Check out the Joining Replicated Security testnet section.

How do I start using ICS?

To become a consumer chain use this checklist and check the App integration section

Which relayers are supported?

Currently supported versions:

  • Hermes 1.4.1

How does key delegation work in ICS?

You can check the Key Assignment Guide for specific instructions.

+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/faq.html.html b/legacy/v2.4.0-lsm/faq.html.html new file mode 100644 index 0000000000..b3d1d43d5f --- /dev/null +++ b/legacy/v2.4.0-lsm/faq.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/features/key-assignment.html b/legacy/v2.4.0-lsm/features/key-assignment.html new file mode 100644 index 0000000000..363440268d --- /dev/null +++ b/legacy/v2.4.0-lsm/features/key-assignment.html @@ -0,0 +1,20 @@ + + + + + +Key Assignment | Interchain Security + + + + +
+
Version: v2.4.0-lsm

Key Assignment

Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate. +There are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains.

The feature is outlined in this ADR-001

By sending an AssignConsumerKey transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator.

tip

Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity.

Rules

  • a key can be assigned before the consumer addition proposal passes on the provider
  • validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider
  • validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X
  • a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain
tip

Validators can use a different key for each consumer chain.

Adding a key

First, create a new node on the consumer chain using the equivalent:

consumerd init <moniker>

Then query your node for the consensus key.

consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}

Then, make an assign-consensus-key transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain.

gaiad tx provider assign-consensus-key <consumer-chain-id> '<pubkey>' --from <tx-signer> --home <home_dir> --gas 900000 -b block -y -o json
  • consumer-chain-id is the string identifier of the consumer chain, as assigned on the provider chain
  • consumer-pub-key has the following format {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}

Check that the key was assigned correcly by querying the provider:

gaiad query provider validator-consumer-key <consumer-chain-id> cosmosvalcons1e....3xsj3ayzf4uv6

You must use a valcons address. You can obtain it by querying your node on the provider gaiad tendermint show-address

OR

gaiad query provider validator-provider-key <consumer-chain-id> consumervalcons1e....123asdnoaisdao

You must use a valcons address. You can obtain it by querying your node on the consumer consumerd tendermint show-address

Changing a key

To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied

Removing a key

To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the Adding a key section and using your provider consensus key.

+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/features/key-assignment.html.html b/legacy/v2.4.0-lsm/features/key-assignment.html.html new file mode 100644 index 0000000000..1bdb8a01fe --- /dev/null +++ b/legacy/v2.4.0-lsm/features/key-assignment.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/features/proposals.html b/legacy/v2.4.0-lsm/features/proposals.html new file mode 100644 index 0000000000..56a0ec2427 --- /dev/null +++ b/legacy/v2.4.0-lsm/features/proposals.html @@ -0,0 +1,22 @@ + + + + + +ICS Provider Proposals | Interchain Security + + + + +
+
Version: v2.4.0-lsm

ICS Provider Proposals

Interchain security module introduces 3 new proposal types to the provider.

The proposals are used to propose upcoming interchain security events through governance.

ConsumerAdditionProposal

info

If you are preparing a ConsumerAdditionProposal you can find more information in the consumer onboarding checklist.

Proposal type used to suggest adding a new consumer chain.

When proposals of this type are passed and the spawn_time specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain.

Minimal example:

{
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
"title": "Add consumer chain",
"description": ".md description of your chain and all other relevant information",
"chain_id": "newchain-1",
"initial_height" : {
"revision_height": 0,
"revision_number": 1,
},
// Unbonding period for the consumer chain.
// It should should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
"transfer_timeout_period": 1800000000000,
"consumer_redistribution_fraction": "0.75",
"blocks_per_distribution_transmission": 1000,
"historical_entries": 10000,
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1"
// relevant for chains performing a sovereign to consumer changeover
// in order to maintan the existing ibc transfer channel
"distribution_transmission_channel": "channel-123"
}

More examples can be found in the replicated security testnet repository here and here.

ConsumerRemovalProposal

Proposal type used to suggest removing an existing consumer chain.

When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain. +After the consumer chain removal, the chain in question will no longer be secured by the provider's validator set.

info

The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain. +Additional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set. +More information will be made available in the Consumer Offboarding Checklist.

Minimal example:

{
// the time on the provider chain at which all validators are responsible to stop their consumer chain validator node
"stop_time": "2023-03-07T12:40:00.000000Z",
// the chain-id of the consumer chain to be stopped
"chain_id": "consumerchain-1",
"title": "This was a great chain",
"description": "Here is a .md formatted string specifying removal details"
}

ChangeRewardDenomProposal

tip

ChangeRewardDenomProposal will only be accepted on the provider chain if at least one of the denomsToAdd or denomsToRemove fields is populated with at least one denom. Also, a denom cannot be repeated in both sets.

Proposal type used to mutate the set of denoms accepted by the provider as rewards.

Minimal example:

{
"title": "Add untrn as a reward denom",
"description": "Here is more information about the proposal",
"denomsToAdd": ["untrn"],
"denomsToRemove": []
}
+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/features/proposals.html.html b/legacy/v2.4.0-lsm/features/proposals.html.html new file mode 100644 index 0000000000..bb7870c2af --- /dev/null +++ b/legacy/v2.4.0-lsm/features/proposals.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/features/reward-distribution.html b/legacy/v2.4.0-lsm/features/reward-distribution.html new file mode 100644 index 0000000000..ef58f655f0 --- /dev/null +++ b/legacy/v2.4.0-lsm/features/reward-distribution.html @@ -0,0 +1,23 @@ + + + + + +Reward distribution | Interchain Security + + + + +
+
Version: v2.4.0-lsm

Reward distribution

Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators. +In replicated security block rewards and fees are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel that gets created during consumer chain initialization.

Reward distribution on the provider is handled by the distribution module - validators and delegators receive a fraction of the consumer chain tokens as staking rewards. +The distributed reward tokens are IBC tokens and therefore cannot be staked on the provider chain.

Sending and distributing rewards from consumer chains to provider chain is handled by the Reward Distribution sub-protocol.

Parameters

tip

The following chain parameters dictate consumer chain distribution amount and frequency. +They are set at consumer genesis and blocks_per_distribution_transmission, consumer_redistribution_fraction +transfer_timeout_period must be provided in every ConsumerChainAddition proposal.

consumer_redistribution_fraction

The fraction of tokens sent from consumer to provider during distribution events. The fraction is a string representing a decimal number. For example "0.75" would represent 75%.

tip

Example:

With consumer_redistribution_fraction set to 0.75 the consumer chain would send 75% of its block rewards and accumulated fees to the consumer chain and the remaining 25% to the provider chain every n blocks where n == blocks_per_distribution_transmission.

blocks_per_distribution_transmission

The number of blocks between IBC token transfers from the consumer chain to the provider chain.

transfer_timeout_period

Timeout period for consumer chain reward distribution IBC packets.

distribution_transmission_channel

Provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.

provider_fee_pool_addr_str

Provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.

+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/features/reward-distribution.html.html b/legacy/v2.4.0-lsm/features/reward-distribution.html.html new file mode 100644 index 0000000000..1bd8e4d65b --- /dev/null +++ b/legacy/v2.4.0-lsm/features/reward-distribution.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/features/slashing.html b/legacy/v2.4.0-lsm/features/slashing.html new file mode 100644 index 0000000000..3c20ac4997 --- /dev/null +++ b/legacy/v2.4.0-lsm/features/slashing.html @@ -0,0 +1,22 @@ + + + + + +Consumer Initiated Slashing | Interchain Security + + + + +
+
Version: v2.4.0-lsm

Consumer Initiated Slashing

A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain. +In essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake).

To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized. +Any infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains.

In the current implementation there are 2 important changes brought by the interchain security module:

Downtime infractions

reported by consumer chains are acted upon on the provider as soon as the provider receives the infraction evidence.

Instead of slashing, the provider will only jail offending validator for the duration of time established in the chain parameters.

info

Slash throttling (sometimes called jail throttling) mechanism ensures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider.

Cryptographic verification of equivocation and slashing

The Cryptographic verification of equivocation allows external agents to submit evidences of light client and double signing attack observed on a consumer chain. When a valid evidence is received, the malicious validators will be slashed, jailed, and tombstoned on the provider.

The feature is outlined in ADR-005 and ADR-013.

By sending a MsgSubmitConsumerMisbehaviour or a MsgSubmitConsumerDoubleVoting transaction, the provider will +verify the reported equivocation and, if successful, slash, jail, and tombstone the malicious validator.

+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/features/slashing.html.html b/legacy/v2.4.0-lsm/features/slashing.html.html new file mode 100644 index 0000000000..78ecf46567 --- /dev/null +++ b/legacy/v2.4.0-lsm/features/slashing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/introduction/overview.html b/legacy/v2.4.0-lsm/introduction/overview.html new file mode 100644 index 0000000000..3e36288ba0 --- /dev/null +++ b/legacy/v2.4.0-lsm/introduction/overview.html @@ -0,0 +1,19 @@ + + + + + +Overview | Interchain Security + + + + +
+
Version: v2.4.0-lsm

Overview

info

Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.


Replicated security allows anyone to launch a "consumer" blockchain using the same validator set as the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit the full security and decentralization of the provider.

Why Replicated Security?

  • Full provider security. At launch, consumer chains are secured by the full validator set and market cap of the provider chain.
  • Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum.
  • Projects keep majority of gas fees. Depending on configuration, these fees either go to the project’s community DAO, or can be used in the protocol in other ways.
  • No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. A governance vote will take place for a chain to get adopted by the provider validators which will encourage participation and signal strong buy-in into the project's long-term success.
  • Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set.

Core protocol

info

Protocol specification is available as ICS-028 in the IBC repository.

Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer.

To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider.

Downtime Slashing

If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period.

Tokenomics and Rewards

Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance.

+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/introduction/overview.html.html b/legacy/v2.4.0-lsm/introduction/overview.html.html new file mode 100644 index 0000000000..2217f3553f --- /dev/null +++ b/legacy/v2.4.0-lsm/introduction/overview.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/introduction/params.html b/legacy/v2.4.0-lsm/introduction/params.html new file mode 100644 index 0000000000..50d1c33651 --- /dev/null +++ b/legacy/v2.4.0-lsm/introduction/params.html @@ -0,0 +1,21 @@ + + + + + +Interchain Security Parameters | Interchain Security + + + + +
+
Version: v2.4.0-lsm

Interchain Security Parameters

The parameters necessary for Interchain Security (ICS) are defined in

  • the Params structure in proto/interchain_security/ccv/provider/v1/provider.proto for the provider;
  • the Params structure in proto/interchain_security/ccv/consumer/v1/consumer.proto for the consumer.

Time-based parameters

ICS relies on the following time-based parameters.

ProviderUnbondingPeriod

is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance.

ConsumerUnbondingPeriod

is the unbonding period on the consumer chain.

info

ConsumerUnbondingPeriod is set via the ConsumerAdditionProposal governance proposal to add a new consumer chain. +It is recommended that every consumer chain set and unbonding period shorter than ProviderUnbondingPeriod


Example:

ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day

Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer.

TrustingPeriodFraction

is used to calculate the TrustingPeriod of created IBC clients on both provider and consumer chains.

Setting TrustingPeriodFraction to 0.5 would result in the following:

TrustingPeriodFraction = 0.5
ProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5
ConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5

Note that a light clients must be updated within the TrustingPeriod in order to avoid being frozen.

For more details, see the IBC specification of Tendermint clients.

CCVTimeoutPeriod

is the period used to compute the timeout timestamp when sending IBC packets.

For more details, see the IBC specification of Channel & Packet Semantics.

danger

If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed.

CCVTimeoutPeriod may have different values on the provider and consumer chains.

  • CCVTimeoutPeriod on the provider must be larger than ConsumerUnbondingPeriod
  • CCVTimeoutPeriod on the consumer is initial set via the ConsumerAdditionProposal

InitTimeoutPeriod

is the maximum allowed duration for CCV channel initialization to execute.

For any consumer chain, if the CCV channel is not established within InitTimeoutPeriod then the consumer chain will be removed and therefore will not be secured by the provider chain.

The countdown starts when the spawn_time specified in the ConsumerAdditionProposal is reached.

VscTimeoutPeriod

is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live. +If the VscTimeoutPeriod is ever reached for a consumer chain that chain will be considered not live and removed from interchain security.

tip

VscTimeoutPeriod MUST be larger than the ConsumerUnbondingPeriod.

BlocksPerDistributionTransmission

is the number of blocks between rewards transfers from the consumer to the provider.

TransferPeriodTimeout

is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider.

If this timeout expires, then the transfer is attempted again after BlocksPerDistributionTransmission blocks.

  • TransferPeriodTimeout on the consumer is initial set via the ConsumerAdditionProposal gov proposal to add the consumer
  • TransferPeriodTimeout should be smaller than BlocksPerDistributionTransmission x avg_block_time

Slash Throttle Parameters

SlashMeterReplenishPeriod

exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed.

The meter is replenished to an amount equal to the slash meter allowance for that block, or SlashMeterReplenishFraction * CurrentTotalVotingPower.

SlashMeterReplenishFraction

exists on the provider as the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs.

This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a sdk.Dec when used.

MaxThrottledPackets

exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value.

This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness.

+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/introduction/params.html.html b/legacy/v2.4.0-lsm/introduction/params.html.html new file mode 100644 index 0000000000..f434ccdf61 --- /dev/null +++ b/legacy/v2.4.0-lsm/introduction/params.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/introduction/technical-specification.html b/legacy/v2.4.0-lsm/introduction/technical-specification.html new file mode 100644 index 0000000000..caf3d900f4 --- /dev/null +++ b/legacy/v2.4.0-lsm/introduction/technical-specification.html @@ -0,0 +1,19 @@ + + + + + +Technical Specification | Interchain Security + + + + +
+
Version: v2.4.0-lsm

Technical Specification

For a technical deep dive into the replicated security protocol, see the specification.

+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/introduction/technical-specification.html.html b/legacy/v2.4.0-lsm/introduction/technical-specification.html.html new file mode 100644 index 0000000000..bed59e1760 --- /dev/null +++ b/legacy/v2.4.0-lsm/introduction/technical-specification.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/introduction/terminology.html b/legacy/v2.4.0-lsm/introduction/terminology.html new file mode 100644 index 0000000000..2fa04b8320 --- /dev/null +++ b/legacy/v2.4.0-lsm/introduction/terminology.html @@ -0,0 +1,19 @@ + + + + + +Terminology | Interchain Security + + + + +
+
Version: v2.4.0-lsm

Terminology

You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.

Shared Security

Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share it's proof-of-stake security with another blockchain or off-chain process.

Interchain Security

Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC.

Replicated Security

A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC. Note this documentation is focused on explaining the concepts from replicated security.

Mesh security

A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see Replicated vs. Mesh Security on the Informal Blog.

+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/introduction/terminology.html.html b/legacy/v2.4.0-lsm/introduction/terminology.html.html new file mode 100644 index 0000000000..2742521919 --- /dev/null +++ b/legacy/v2.4.0-lsm/introduction/terminology.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/validators/joining-testnet.html b/legacy/v2.4.0-lsm/validators/joining-testnet.html new file mode 100644 index 0000000000..938b0581c6 --- /dev/null +++ b/legacy/v2.4.0-lsm/validators/joining-testnet.html @@ -0,0 +1,20 @@ + + + + + +Joining Replicated Security testnet | Interchain Security + + + + +
+
Version: v2.4.0-lsm

Introduction

This short guide will teach you how to join the Replicated Security testnet.

The experience gained in the testnet will prepare you for validating interchain secured chains.

tip

Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set.

For general information about running cosmos-sdk based chains check out the validator basics and Running a Node section of Cosmos SDK docs

Joining the provider chain

info

At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain.

A comprehensive guide is available here.

Initialization

First, initialize your $NODE_HOME using the provider chain binary.

NODE_MONIKER=<your_node>
CHAIN_ID=provider
NODE_HOME=<path_to_your_home>

gaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME

Add your key to the keyring - more details available here.

In this example we will use the test keyring-backend. This option is not safe to use in production.

gaiad keys add <key_moniker> --keyring-backend test

# save the address as variable for later use
MY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)

Before issuing any transactions, use the provider testnet faucet to add funds to your address.

curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider

# example output:
{
"address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",
"amount": "10000000uatom",
"chain": "provider",
"hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",
"status": "success"
}

Then, use the account associated with the keyring to issue a create-validator transaction which will register your validator on chain.

gaiad tx staking create-validator \
--amount=1000000uatom \
--pubkey=$(gaiad tendermint show-validator) \
--moniker="choose a moniker" \
--chain-id=$CHAIN_ID" \
--commission-rate="0.10" \
--commission-max-rate="0.20" \
--commission-max-change-rate="0.01" \
--min-self-delegation="1000000" \
--gas="auto" \
--gas-prices="0.0025uatom" \
--from=<key_moniker>
tip

Check this guide to edit your validator.

After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use statesync to catch up to the rest of the network.

You can use this script to modify your config.toml with the required statesync parameters.

# create the statesync script
$: cd $NODE_HOME
$: touch statesync.sh
$ chmod 700 statesync.sh # make executable

Paste the following instructions into the statesync.sh:

#!/bin/bash

SNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"

LATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \
BLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \
TRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)

sed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\1true| ; \
s|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\1\"$SNAP_RPC,$SNAP_RPC\"| ; \
s|^(trust_height[[:space:]]+=[[:space:]]+).*$|\1$BLOCK_HEIGHT| ; \
s|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\1\"$TRUST_HASH\"|" $NODE_HOME/config/config.toml

Then, you can execute the script:

$: ./statesync.sh # setup config.toml for statesync

Finally, copy the provider genesis and start your node:

$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/replicated-security/provider/provider-genesis.json
$: wget $GENESIS_URL -O genesis.json
$: genesis.json $NODE_HOME/config/genesis.json
# start the service
$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"

Additional scripts to setup your nodes are available here and here. The scripts will configure your node and create the required services - the scripts only work in linux environments.

Joining consumer chains

tip

Once you reach the active set on the provider chain, you will be required to validate all available consumer chains.

You can use the same consensus key on all consumer chains, or opt to use a different key on each consumer chain. +Check out this guide to learn more about key assignment in replicated security.

To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries.

info

When running the provider chain and consumers on the same machine please update the PORT numbers for each of them and make sure they do not overlap (otherwise the binaries will not start).

Important ports to re-configure:

  • --rpc.laddr
  • --p2p.laddr
  • --api.address
  • --grpc.address
  • --grpc-web.address

Re-using consensus key

To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the priv_validator_key.json into the home directory of your consumer chain (<consumer_home>/config/priv_validator_key.json).

When you start the chain, the consensus key will be the same on the provider and the consumer chain.

Assigning consensus keys

Whenever you initialize a new node, it will be configured with a consensus key you can use.

# machine running consumer chain
consumerd init <node_moniker> --home <home_path> --chain-id consumer-1

# use the output of this command to get the consumer chain consensus key
consumerd tendermint show-validator
# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}

Then, let the provider know which key you will be using for the consumer chain:

# machine running the provider chain
gaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b block -y -o json

After this step, you are ready to copy the consumer genesis into your nodes's /config folder, start your consumer chain node and catch up to the network.

Baryon

You can find the onboarding repo instructions for the Baryon chain here

Noble

You can find the onboarding repo instructions for the Noble chain here

+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/validators/joining-testnet.html.html b/legacy/v2.4.0-lsm/validators/joining-testnet.html.html new file mode 100644 index 0000000000..de52616a37 --- /dev/null +++ b/legacy/v2.4.0-lsm/validators/joining-testnet.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/validators/overview.html b/legacy/v2.4.0-lsm/validators/overview.html new file mode 100644 index 0000000000..26b85bbde5 --- /dev/null +++ b/legacy/v2.4.0-lsm/validators/overview.html @@ -0,0 +1,24 @@ + + + + + +Overview | Interchain Security + + + + +
+
Version: v2.4.0-lsm

Overview

tip

We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.

At present, replicated security requires all validators of the provider chain (ie. Cosmos Hub) to run validator nodes for all governance-approved consumer chains.

Once a ConsumerAdditionProposal passes, validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains.

Provider chain and consumer chains represent standalone chains that only share the validator set ie. the same validator operators are tasked with running all chains.

info

To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 175 validators for Cosmos Hub).

Startup sequence overview

Consumer chains cannot start and be secured by the validator set of the provider unless a ConsumerAdditionProposal is passed. +Each proposal contains defines a spawn_time - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider.

tip

Validators are required to run consumer chain binaries only after spawn_time has passed.

Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains.

The image below illustrates the startup sequence +startup

1. Consumer Chain init + 2. Genesis generation

Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ConsumerAdditionProposal

3. Submit Proposal

Consumer chain team (or their advocates) submits a ConsumerAdditionProposal. +The most important parameters for validators are:

  • spawn_time - the time after which the consumer chain must be started
  • genesis_hash - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and spawn_time is reached
  • binary_hash - hash of the consumer chain binary used to validate the software builds

4. CCV Genesis state generation

After reaching spawn_time the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain genesis.json. The CCV validator set consists of the validator set on the provider at spawn_time.

The state can be queried on the provider chain (in this case the Cosmos Hub):

 gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json

This is used by the launch coordinator to create the final genesis.json that will be distributed to validators in step 5.

5. Updating the genesis file

Upon reaching the spawn_time the initial validator set state will become available on the provider chain. The initial validator set is included in the final genesis.json of the consumer chain.

6. Chain start

info

The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences.

The new genesis.json containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided genesis.json to start their consumer chain node.

tip

Please pay attention to any onboarding repositories provided by the consumer chain teams. +Recommendations are available in Consumer Onboarding Checklist. +Another comprehensive guide is available in the Replicated Security testnet repo.

7. Creating IBC connections

Finally, to fully establish replicated security an IBC relayer is used to establish connections and create the required channels.

danger

The relayer can establish the connection only after the consumer chain starts producing blocks.

hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> 
hermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1
hermes start

Downtime Infractions

At present, the consumer chain can report evidence about downtime infractions to the provider chain. The min_signed_per_window and signed_blocks_window can be different on each consumer chain and are subject to changes via consumer chain governance.

info

Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains.

To unjail, the validator must wait for the jailing period to elapse on the provider chain and submit an unjail transaction on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains.

More information is available in Downtime Slashing documentation

Double-signing Infractions

To learn more about equivocation handling in replicated security check out the Slashing documentation section.

Key assignment

Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use.

For more information check our the Key assignment overview and guide

References:

+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/validators/overview.html.html b/legacy/v2.4.0-lsm/validators/overview.html.html new file mode 100644 index 0000000000..6d90e1c5a0 --- /dev/null +++ b/legacy/v2.4.0-lsm/validators/overview.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/validators/withdraw_rewards.html b/legacy/v2.4.0-lsm/validators/withdraw_rewards.html new file mode 100644 index 0000000000..07ec993a6e --- /dev/null +++ b/legacy/v2.4.0-lsm/validators/withdraw_rewards.html @@ -0,0 +1,20 @@ + + + + + +Withdrawing consumer chain validator rewards | Interchain Security + + + + +
+
Version: v2.4.0-lsm

Withdrawing consumer chain validator rewards

Here are example steps for withdrawing rewards from consumer chains in the provider chain

info

The examples used are from rs-testnet, the replicated security persistent testnet.

Validator operator address: cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 +Self-delegation address: cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

Prior to withdrawing rewards, query balances for self-delegation address:

gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

balances:
- amount: "1000000000000"
denom: uatom
pagination:
next_key: null
total: "0"

Querying validator rewards

Query rewards for the validator address:

gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6

rewards:
- amount: "158.069895000000000000"
denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD
- amount: "841842390516.072526500000000000"
denom: uatom

The ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD denom represents rewards from a consumer chain.

Withdrawing rewards and commission

1. Withdraw rewards

gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y

txhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A

2. Confirm withdrawal

After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:

gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

balances:
- amount: "216"
denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD
- amount: "2233766225342"
denom: uatom
pagination:
next_key: null
total: "0"
+ + + + \ No newline at end of file diff --git a/legacy/v2.4.0-lsm/validators/withdraw_rewards.html.html b/legacy/v2.4.0-lsm/validators/withdraw_rewards.html.html new file mode 100644 index 0000000000..d8c6f4696a --- /dev/null +++ b/legacy/v2.4.0-lsm/validators/withdraw_rewards.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0.html b/legacy/v3.1.0.html new file mode 100644 index 0000000000..ab2c894111 --- /dev/null +++ b/legacy/v3.1.0.html @@ -0,0 +1,19 @@ + + + + + +Interchain Security Docs | Interchain Security + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0.html.html b/legacy/v3.1.0.html.html new file mode 100644 index 0000000000..c0124edcd7 --- /dev/null +++ b/legacy/v3.1.0.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/adrs/adr-001-key-assignment.html b/legacy/v3.1.0/adrs/adr-001-key-assignment.html new file mode 100644 index 0000000000..7ff657411e --- /dev/null +++ b/legacy/v3.1.0/adrs/adr-001-key-assignment.html @@ -0,0 +1,19 @@ + + + + + +Key Assignment | Interchain Security + + + + +
+
Version: v3.1.0

ADR 001: Key Assignment

Changelog

  • 2022-12-01: Initial Draft

Status

Accepted

Context

KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate.

Decision

It is possible to change the keys at any time by submitting a transaction (i.e., MsgAssignConsumerKey).

State required

  • ValidatorConsumerPubKey - Stores the validator assigned keys for every consumer chain.
ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey
  • ValidatorByConsumerAddr - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol.
ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress
  • KeyAssignmentReplacements - Stores the key assignments that need to be replaced in the current block. Needed to apply the key assignments received in a block to the validator updates sent to the consumer chains.
KeyAssignmentReplacementsBytePrefix | len(chainID) | chainID | providerConsAddress -> abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower},
  • ConsumerAddrsToPrune - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ValidatorByConsumerAddr.
ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses

Protocol overview

On receiving a MsgAssignConsumerKey(chainID, providerAddr, consumerKey) message:

// get validator from staking module  
validator, found := stakingKeeper.GetValidator(providerAddr)
if !found {
return ErrNoValidatorFound
}
providerConsAddr := validator.GetConsAddr()

// make sure consumer key is not in use
consumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)
if _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {
return ErrInvalidConsumerConsensusPubKey
}

// check whether the consumer chain is already registered
// i.e., a client to the consumer was already created
if _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {
// get the previous key assigned for this validator on this consumer chain
oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)
if found {
// mark this old consumer key as prunable once the VSCMaturedPacket
// for the current VSC ID is received
oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)
vscID := GetValidatorSetUpdateId()
AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)
} else {
// the validator had no key assigned on this consumer chain
oldConsumerKey := validator.TmConsPublicKey()
}

// check whether the validator is valid, i.e., its power is positive
if currentPower := stakingKeeper.GetLastValidatorPower(providerAddr); currentPower > 0 {
// to enable multiple calls of AssignConsumerKey in the same block by the same validator
// the key assignment replacement should not be overwritten
if _, found := GetKeyAssignmentReplacement(chainID, providerConsAddr); !found {
// store old key and power for modifying the valset update in EndBlock
oldKeyAssignment := abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower}
SetKeyAssignmentReplacement(chainID, providerConsAddr, oldKeyAssignment)
}
}
} else {
// if the consumer chain is not registered, then remove the previous reverse mapping
if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {
oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)
DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)
}
}


// set the mapping from this validator's provider address to the new consumer key
SetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)

// set the reverse mapping: from this validator's new consensus address
// on the consumer to its consensus address on the provider
SetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)

When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see MakeConsumerGenesis).

func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {
// ...
// get initial valset from the staking module
var updates []abci.ValidatorUpdate{}
stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {
validator := stakingKeeper.GetValidator(providerAddr)
providerKey := validator.TmConsPublicKey()
updates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})
return false
})

// applies the key assignment to the initial validator
for i, update := range updates {
providerAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)
if consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {
updates[i].PubKey = consumerKey
}
}
gen.InitialValSet = updates

// get a hash of the consumer validator set from the update
updatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)
hash := tendermint.NewValidatorSet(updatesAsValSet).Hash()

return gen, hash, nil
}

On EndBlock while queueing VSCPackets to send to registered consumer chains:

func QueueVSCPackets() {
valUpdateID := GetValidatorSetUpdateId()
// get the validator updates from the staking module
valUpdates := stakingKeeper.GetValidatorUpdates()

IterateConsumerChains(func(chainID, clientID string) (stop bool) {
// apply the key assignment to the validator updates
valUpdates := ApplyKeyAssignmentToValUpdates(chainID, valUpdates)
// ..
})
// ...
}

func ApplyKeyAssignmentToValUpdates(
chainID string,
valUpdates []abci.ValidatorUpdate,
) (newUpdates []abci.ValidatorUpdate) {
for _, valUpdate := range valUpdates {
providerAddr := utils.TMCryptoPublicKeyToConsAddr(valUpdate.PubKey)

// if a key assignment replacement is found, then
// remove the valupdate with the old consumer key
// and create two new valupdates
prevConsumerKey, _, found := GetKeyAssignmentReplacement(chainID, providerAddr)
if found {
// set the old consumer key's power to 0
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: prevConsumerKey,
Power: 0,
})
// set the new consumer key's power to the power in the update
newConsumerKey := GetValidatorConsumerPubKey(chainID, providerAddr)
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: newConsumerKey,
Power: valUpdate.Power,
})
// delete key assignment replacement
DeleteKeyAssignmentReplacement(chainID, providerAddr)
} else {
// there is no key assignment replacement;
// check if the validator's key is assigned
consumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr)
if found {
// replace the update containing the provider key
// with an update containing the consumer key
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: consumerKey,
Power: valUpdate.Power,
})
} else {
// keep the same update
newUpdates = append(newUpdates, valUpdate)
}
}
}

// iterate over the remaining key assignment replacements
IterateKeyAssignmentReplacements(chainID, func(
pAddr sdk.ConsAddress,
prevCKey tmprotocrypto.PublicKey,
power int64,
) (stop bool) {
// set the old consumer key's power to 0
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: prevCKey,
Power: 0,
})
// set the new consumer key's power to the power in key assignment replacement
newConsumerKey := GetValidatorConsumerPubKey(chainID, pAddr)
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: newConsumerKey,
Power: power,
})
return false
})

// remove all the key assignment replacements

return newUpdates
}

On receiving a SlashPacket from a consumer chain with id chainID for a infraction of a validator data.Validator:

func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {
// ...
// the slash packet validator address may be known only on the consumer chain;
// in this case, it must be mapped back to the consensus address on the provider chain
consumerAddr := sdk.ConsAddress(data.Validator.Address)
providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)
if !found {
// the validator has the same key on the consumer as on the provider
providerAddr = consumer
}
// ...
}

On receiving a VSCMatured:

func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {
// ...
// prune previous consumer validator address that are no longer needed
consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)
for _, addr := range consumerAddrs {
DeleteValidatorByConsumerAddr(chainID, addr)
}
DeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)
// ...
}

On stopping a consumer chain:

func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {
// ...
// deletes all the state needed for key assignments on this consumer chain
// ...
}

Consequences

Positive

  • Validators can use different consensus keys on the consumer chains.

Negative

  • None

Neutral

  • The consensus state necessary to create a client to the consumer chain must use the hash returned by the MakeConsumerGenesis method as the nextValsHash.
  • The consumer chain can no longer check the initial validator set against the consensus state on InitGenesis.

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/adrs/adr-001-key-assignment.html.html b/legacy/v3.1.0/adrs/adr-001-key-assignment.html.html new file mode 100644 index 0000000000..b58812801e --- /dev/null +++ b/legacy/v3.1.0/adrs/adr-001-key-assignment.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/adrs/adr-002-throttle.html b/legacy/v3.1.0/adrs/adr-002-throttle.html new file mode 100644 index 0000000000..f6b80fb8c3 --- /dev/null +++ b/legacy/v3.1.0/adrs/adr-002-throttle.html @@ -0,0 +1,19 @@ + + + + + +Jail Throttling | Interchain Security + + + + +
+
Version: v3.1.0

ADR 002: Jail Throttling

Changelog

  • 2023-01-26: Initial Draft
  • 2023-02-07: Property refined, ADR ready to review/merge

Status

Accepted

Context

The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols. In practice, this assumption may not hold. A malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider.

Before the throttling feature was implemented, the following attack was possible. Attacker(s) would create provider validators just below the provider's active set. Using a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once. Control of the provider would then pass over to the attackers' validators. This enables the attacker(s) to halt the provider. Or even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC.

Decision

The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack. Ie. this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time.

State Required - Slash Meter

There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time. This meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params.

State Required - Global entry queue

There exists a single queue which stores "global slash entries". These entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering. This queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.

State Required - Per-chain data queue

For each established consumer, there exists a queue which stores "throttled packet data". Ie. pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering. Order is enforced by IBC sequence number. These "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.

Reasoning - Multiple queues

For reasoning on why this feature was implemented with multiple queues, see spec. Specifically the section on VSC Maturity and Slashing Order. There are other ways to ensure such a property (like a queue of linked lists, etc.), but the implemented protocol seemed to be the most understandable and easiest to implement with a KV store.

Protocol Overview - OnRecvSlashPacket

Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:

  1. A global slash entry is queued.
  2. The data of such a packet is added to the per-chain queue.

Protocol Overview - OnRecvVSCMaturedPacket

Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue.

Endblocker Step 1 - Slash Meter Replenishment

Once the slash meter becomes not full, it'll be replenished after SlashMeterReplenishPeriod (param) by incrementing the meter with its allowance for the replenishment block, where allowance = SlashMeterReplenishFraction (param) * currentTotalVotingPower. The slash meter will never exceed its current allowance (fn of the total voting power for the block) in value. Note a few things:

  1. The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power. In such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods.
  2. Total voting power of a chain changes over time, especially as validators are jailed. As validators are jailed, total voting power decreases, and so does the jailing allowance. See below for more detailed throttling property discussion.
  3. The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1. If the SlashMeterReplenishFraction (param) is set too low, integer rounding will put this minimum value into effect. That is, if SlashMeterReplenishFraction * currentTotalVotingPower < 1, then the effective allowance would be 1. This min value of allowance ensures that there's some packets handled over time, even if that is a very long time. It's a crude solution to an edge case caused by too small of a replenishment fraction.

The behavior described above is achieved by executing CheckForSlashMeterReplenishment() every endblock, BEFORE HandleThrottleQueues() is executed.

Endblocker Step 2 - HandleLeadingVSCMaturedPackets

Every block it is possible that VSCMatured packet data was queued before any slash packet data. Since this "leading" VSCMatured packet data does not have to be throttled (see VSC Maturity and Slashing Order), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes.

Endblocker Step 3 - HandleThrottleQueues

Every endblocker the following pseudo-code is executed to handle data from the throttle queues.

meter := getSlashMeter()

// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist
while meter.IsPositiveOrZero() && entriesExist() {
// Get next entry in queue
entry := getNextGlobalSlashEntry()
// Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet
valPower := entry.getValPower()
meter = meter - valPower
// Using the per-chain queue, handle the single slash packet using its queued data,
// then handle all trailing VSCMatured packets for this consumer
handleSlashPacketAndTrailingVSCMaturedPackets(entry)
// Delete entry in global queue, delete handled data
entry.Delete()
deleteThrottledSlashPacketData()
deleteTrailingVSCMaturedPacketData()
}

System Properties

All CCV system properties should be maintained by implementing this feature, see: CCV spec - Consumer Initiated Slashing.

One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than MaxThrottledPackets (param), then the provider binary will panic, and the provider chain will halt. Therefore this param should be set carefully. See SetThrottledPacketDataSize. This behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators.

Main Throttling Property

Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions.

First, we define the following:

  • A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.
  • The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.
  • There is a list of honest validators s.t if they are jailed, X% of the initial validator set will be jailed.

For the following property to hold, these assumptions must be true:

  1. We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack.
  2. No validator has more than SlashMeterReplenishFraction of total voting power on the provider.
  3. SlashMeterReplenishFraction is large enough that SlashMeterReplenishFraction * currentTotalVotingPower > 1. Ie. the replenish fraction is set high enough that we can ignore the effects of rounding.
  4. SlashMeterReplenishPeriod is sufficiently longer than the time it takes to produce a block.

Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined.

Property:

The time it takes to jail/tombstone X% of the initial validator set will be greater than or equal to (X * SlashMeterReplenishPeriod / SlashMeterReplenishFraction) - 2 * SlashMeterReplenishPeriod

Intuition:

Let's use the following notation:

  • $C$: Number of replenishment cycles
  • $P$: $\text{SlashMeterReplenishPeriod}$
  • $F$: $\text{SlashMeterReplenishFraction}$
  • $V_{\mathit{max}}$: Max power of a validator as a fraction of total voting power

In $C$ number of replenishment cycles, the fraction of total voting power that can be removed, $a$, is $a \leq F \cdot C + V{\mathit{max}}$ (where $V{\mathit{max}}$ is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value).

So, we need at least $C \geq \frac{a - V_{\mathit{max}}}{F}$ cycles to remove $a$ fraction of the total voting power.

Since we defined the start of the attack to be the moment when the first slash request arrives, then $F$ fraction of the initial validator set can be jailed immediately. For the remaining $X - F$ fraction of the initial validator set to be jailed, it takes at least $C \geq \frac{(X - F) - V{\mathit{max}}}{F}$ cycles. Using the assumption that $V{\mathit{max}} \leq F$ (assumption 2), we get $C \geq \frac{X - 2F}{F}$ cycles.

In order to execute $C$ cycles, we need $C \cdot P$ time.

Thus, jailing the remaining $X - F$ fraction of the initial validator set corresponds to $\frac{P \cdot (X - 2F)}{F}$ time.

In other words, the attack must take at least $\frac{P \cdot X}{F} - 2P$ time (in the units of replenish period $P$).

This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests. For example, if SlashMeterReplenishFraction is set to 0.06, then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub. Note that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power.

Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings.

How Unjailing Affects the Main Throttling Property

Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained.

If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider.

In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack.

Consequences

Positive

  • The described attack is slowed down in seemingly all cases.
  • If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded.

Negative

  • Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below. However, this is sacrificing liveness in a edge case scenario for the sake of security. As an improvement, using retries would fully prevent this attack vector.

Neutral

  • Additional state is introduced to the provider chain.
  • VSCMatured and slash packet data is not always handled in the same block that it is received.

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/adrs/adr-002-throttle.html.html b/legacy/v3.1.0/adrs/adr-002-throttle.html.html new file mode 100644 index 0000000000..1920594d1a --- /dev/null +++ b/legacy/v3.1.0/adrs/adr-002-throttle.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/adrs/adr-003-equivocation-gov-proposal.html b/legacy/v3.1.0/adrs/adr-003-equivocation-gov-proposal.html new file mode 100644 index 0000000000..6546a76de2 --- /dev/null +++ b/legacy/v3.1.0/adrs/adr-003-equivocation-gov-proposal.html @@ -0,0 +1,19 @@ + + + + + +Equivocation governance proposal | Interchain Security + + + + +
+
Version: v3.1.0

ADR 003: Equivocation governance proposal

Changelog

  • 2023-02-06: Initial draft

Status

Accepted

Context

We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain.

For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence.

Decision

To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain.

A new kind of governance proposal is added to the provider module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain.

If such proposal passes, the proposal handler delegates to the evidence module to process the equivocation. This module ensures the evidence isn’t too old, or else ignores it (see code). Too old is determined by 2 consensus params :

  • evidence.max_age_duration number of nanoseconds before an evidence is considered too old
  • evidence.max_age_numblocks number of blocks before an evidence is considered too old.

On the hub, those parameters are equals to

// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682
(...)
"evidence": {
"max_age_num_blocks": "1000000",
"max_age_duration": "172800000000000",
(...)
},
(...)

A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the evidence module when the proposal passes and is handled by the hub.

For max_age_num_blocks=1M, the parameter is big enough if we consider the hub produces 12k blocks per day (blocks_per_year/365 = 436,0000/365). The evidence can be up to 83 days old (1,000,000/12,000) and not be ignored.

For max_age_duration=172,800,000,000,000, the parameter is too low, because the value is in nanoseconds so it’s 2 days. Fortunately the condition that checks those 2 parameters uses a AND, so if max_age_num_blocks condition passes, the evidence won’t be ignored.

Consequences

Positive

  • Remove the possibility from a malicious consumer chain to “attack” the provider chain by slashing/jailing validators.
  • Provide a more acceptable implementation for the validator community.

Negative

  • Punishment action of double-signing isn’t “automated”, a governance proposal is required which takes more time.
  • You need to pay 250ATOM to submit an equivocation evidence.

Neutral

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/adrs/adr-003-equivocation-gov-proposal.html.html b/legacy/v3.1.0/adrs/adr-003-equivocation-gov-proposal.html.html new file mode 100644 index 0000000000..e094f93523 --- /dev/null +++ b/legacy/v3.1.0/adrs/adr-003-equivocation-gov-proposal.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html b/legacy/v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html new file mode 100644 index 0000000000..0a608ae0f3 --- /dev/null +++ b/legacy/v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html @@ -0,0 +1,51 @@ + + + + + +ADR Template | Interchain Security + + + + +
+
Version: v3.1.0

ADR 007: Pause validator unbonding during equivocation proposal

Changelog

  • 2023-05-16: Initial Draft

Status

Proposed

Context

Currently, if an equivocation slashing proposal is created after more than one +week has passed since the equivocation, it is possible that the validator in +question could unbond and get away without being slashed, since the unbonding +period is 3 weeks, and the voting period is 2 weeks. For this reason, it might +be good to pause unbondings for validators named in an equivocation slashing +proposal until the proposal's voting period is over.

Decision

How

Pausing the unbonding period is already possible thanks to the changes in the +staking module of the cosmos-sdk:

  • stakingKeeper.PutUnbondingOnHold pauses an unbonding period
  • stakingKeeper.UnbondingCanComplete unpauses an unbonding period

These methods use a reference counter under the hood, that gets incremented +every time PutUnbondingOnHold is called, and decreased when +UnbondingCanComplete is called instead. A specific unbonding is considered +fully unpaused when its underlying reference counter reaches 0. Therefore, as +long as we safeguard consistency - i.e. we make sure we eventually decrement +the reference counter for each time we have incremented it - we can safely use +this existing mechanism without conflicts with the Completion of Unbonding +Operations system.

When pause

The unbonding period (if there is any unbonding) should be paused once an +equivocation proposal enters the voting period. For that, the gov module's +hook AfterProposalDeposit can be used.

If the hook is triggered with a an equivocation proposal in voting period, then +for each equivocation of the proposal, the unbonding operations of the related +validator that were initiated after the equivocation block time must be paused

  • i.e. the underlying reference counter has to be increased.

Note that even after the voting period has started, a proposal can receive +additional deposits. The hook is triggered however at arrival of a deposit, so +a check to verify that the proposal is not already in voting period is +required.

When unpause

We can use a gov module's hook also here and it is +AfterProposalVotingPeriodEnded.

If the hook is triggered with an equivocation proposal, then for each +associated equivocation, the unbonding operations of the related validator that +were initiated between the equivocation block time and the start of the +proposal voting period must be unpaused - i.e. decrease the underlying +reference counter - regardless of the proposal outcome.

Consequences

Positive

  • Validators subject to an equivocation proposal cannot finish unbonding +their tokens before the end of the voting period.

Negative

  • A malicious consumer chain could forge slash packets enabling submission of +an equivocation proposal on the provider chain, resulting in the freezing of +validator's unbondings for an undeterminated amount of time.
  • Misbehavior on a consumer chain can potentially go unpunished, if no one +submits an equivocation proposal in time, or if the proposal doesn't pass.

Neutral

  • This feature can't be used for social slashing, because an equivocation +proposal is only accepted if there's a slash log for the related +validator(s), meaning the consumer chain has reported the equivocation to +the provider chain.

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html b/legacy/v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html new file mode 100644 index 0000000000..038db2ef0e --- /dev/null +++ b/legacy/v3.1.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/adrs/adr-008-throttle-retries.html b/legacy/v3.1.0/adrs/adr-008-throttle-retries.html new file mode 100644 index 0000000000..5d2abda8be --- /dev/null +++ b/legacy/v3.1.0/adrs/adr-008-throttle-retries.html @@ -0,0 +1,19 @@ + + + + + +Throttle with retries | Interchain Security + + + + +
+
Version: v3.1.0

Throttle with retries

ADR 008: Throttle with retries

Changelog

  • 6/9/23: Initial draft

Status

Accepted

Context

For context on why the throttling mechanism exists, see ADR 002.

Note the terms slash throttling and jail throttling are synonymous, since in replicated security a SlashPacket simply jails a validator for downtime infractions.

Currently the throttling mechanism is designed so that provider logic (slash meter, etc.) dictates how many slash packets can be handled over time. Throttled slash packets are persisted on the provider, leading to multiple possible issues. Namely:

  • If slash or vsc matured packets are actually throttled/queued on the provider, state can grow and potentially lead to a DoS attack. We have short term solutions around this, but overall they come with their own weaknesses. See #594.
  • If a jailing attack described in ADR 002 were actually to be carried out with the current throttling design, we'd likely have to halt the provider, and perform an emergency upgrade and/or migration to clear the queues of slash packets that were deemed to be malicious. Alternatively, validators would just have to tough it out and wait for the queues to clear, during which all/most validators would be jailed. Right after being jailed, vals would have to unjail themselves promptly to ensure safety. The synchronous coordination required to maintain safety in such a scenario is not ideal.

So what's the solution? We can improve the throttling mechanism to instead queue/persist relevant data on each consumer, and have consumers retry slash requests as needed.

Decision

Consumer changes

Note the consumer already queues up both slash and vsc matured packets via AppendPendingPacket. Those packets are dequeued every endblock in SendPackets and sent to the provider.

Instead, we will now introduce the following logic on endblock:

  • Slash packets will always be sent to the provider once they're at the head of the queue. However, once sent, the consumer will not send any trailing vsc matured packets from the queue until the provider responds with an ack that the slash packet has been handled (ie. val was jailed). That is, slash packets block the sending of trailing vsc matured packets in the consumer queue.
  • If two slash packets are at the head of the queue, the consumer will send the first slash packet, and then wait for a success ack from the provider before sending the second slash packet. This seems like it'd simplify implementation.
  • VSC matured packets at the head of the queue (ie. NOT trailing a slash packet) can be sent immediately, and do not block any other packets in the queue, since the provider always handles them immediately.

To prevent the provider from having to keep track of what slash packets have been rejected, the consumer will have to retry the sending of slash packets over some period of time. This can be achieved with an on-chain consumer param. The suggested param value would probably be 1/2 of the provider's SlashMeterReplenishmentPeriod, although it doesn't matter too much as long as the param value is sane.

Note to prevent weird edge case behavior, a retry would not be attempted until either a success ack or failure ack has been recv from the provider.

With the behavior described, we maintain very similar behavior to the current throttling mechanism regarding the timing that slash and vsc matured packets are handled on the provider. Obviously the queueing and blocking logic is moved, and the two chains would have to send more messages between one another (only in the case the throttling mechanism is triggered).

In the normal case, when no or a few slash packets are being sent, the VSCMaturedPackets will not be delayed, and hence unbonding will not be delayed.

Provider changes

The main change needed for the provider is the removal of queuing logic for slash and vsc matured packets upon being received.

Instead, the provider will consult the slash meter to determine if a slash packet can be handled immediately. If not, the provider will return an ack message to the consumer communicating that the slash packet could not be handled, and needs to be sent again in the future (retried).

VSCMatured packets will always be handled immediately upon being received by the provider.

Note spec. Specifically the section on VSC Maturity and Slashing Order. Previously the onus was on the provider to maintain this property via queuing packets and handling them FIFO.

Now this property will be maintained by the consumer sending packets in the correct order, and blocking the sending of VSCMatured packets as needed. Then, the ordered IBC channel will ensure that Slash/VSCMatured packets are received in the correct order on the provider.

The provider's main responsibility regarding throttling will now be to determine if a recv slash packet can be handled via slash meter etc., and appropriately ack to the sending consumer.

Why the provider can handle VSCMatured packets immediately

First we answer, what does a VSCMatured packet communicate to the provider? A VSCMatured packet communicates that a VSC has been applied to a consumer long enough that infractions committed on the consumer could have been submitted.

If the consumer is following the queuing/blocking protocol described. No bad behavior occurs, VSC Maturity and Slashing Order property is maintained.

If a consumer sends VSCMatured packets too leniently: The consumer is malicious and sending duplicate vsc matured packets, or sending the packets sooner than the ccv protocol specifies. In this scenario, the provider needs to handle vsc matured packets immediately to prevent DOS, state bloat, or other issues. The only possible negative outcome is that the malicious consumer may not be able to jail a validator who should have been jailed. The malicious behavior only creates a negative outcome for the chain that is being malicious.

If a consumer blocks the sending of VSCMatured packets: The consumer is malicious and blocking vsc matured packets that should have been sent. This will block unbonding only up until the VSC timeout period has elapsed. At that time, the consumer is removed. Again the malicious behavior only creates a negative outcome for the chain that is being malicious.

Splitting of PRs

We could split this feature into two PRs, one affecting the consumer and one affecting the provider, along with a third PR which could setup a clever way to upgrade the provider in multiple steps, ensuring that queued slash packets at upgrade time are handled properly.

Consequences

  • Consumers will now have to manage their own queues, and retry logic.
  • Consumers still aren't trustless, but the provider is now less susceptible to mismanaged or malicious consumers.
  • Recovering from the "jailing attack" is more elegant.
  • Some issues like #1001 will now be handled implicitly by the improved throttling mechanism.
  • Slash and vsc matured packets can be handled immediately once recv by the provider if the slash meter allows.
  • In general, we reduce the amount of computation that happens in the provider end-blocker.

Positive

  • We no longer have to reason about a "global queue" and a "chain specific queue", and keeping those all in-sync. Now slash and vsc matured packet queuing is handled on each consumer individually.
  • Due to the above, the throttling protocol becomes less complex overall.
  • We no longer have to worry about throttle related DoS attack on the provider, since no queuing exists on the provider.

Negative

  • Increased number of IBC packets being relayed anytime throttling logic is triggered.
  • Consumer complexity increases, since consumers now have manage queuing themselves, and implement packet retry logic.

Neutral

  • Core throttling logic on the provider remains unchanged, ie. slash meter, replenishment cycles, etc.

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/adrs/adr-008-throttle-retries.html.html b/legacy/v3.1.0/adrs/adr-008-throttle-retries.html.html new file mode 100644 index 0000000000..ff8c9fac84 --- /dev/null +++ b/legacy/v3.1.0/adrs/adr-008-throttle-retries.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/adrs/adr-009-soft-opt-out.html b/legacy/v3.1.0/adrs/adr-009-soft-opt-out.html new file mode 100644 index 0000000000..2661fb2bf2 --- /dev/null +++ b/legacy/v3.1.0/adrs/adr-009-soft-opt-out.html @@ -0,0 +1,19 @@ + + + + + +Soft Opt-Out | Interchain Security + + + + +
+
Version: v3.1.0

Soft Opt-Out

ADR 009: Soft Opt-Out

Changelog

  • 6/13/23: Initial draft of ADR. Feature already implemented and in production.

Status

Accepted

Context

Some small validators may not have the resources needed to validate all consumer chains. Therefore a need exists to allow the bottom x% of validators to opt-out of validating a consumer chain. Meaning downtime infractions for these validators are dropped without ever reaching the provider.

This document specifies a modification to the ccv protocol which allows the bottom x% of the validator set by power to opt out of validating consumer chains without being jailed or otherwise punished for it. The feature is implemented with entirely consumer-side code.

Decision

A consumer param exists, known as SoftOptOutThreshold, which is a string decimal in the range of [0, 0.2], that determines the portion of validators which are allowed to opt out of validating that specific consumer.

In every consumer beginblocker, a function is ran which determines the so called smallest non opt-out voting power. Validators with voting power greater than or equal to this value must validate the consumer chain, while validators below this value may opt out of validating the consumer chain.

The smallest non opt-out voting power is recomputed every beginblocker in UpdateSmallestNonOptOutPower(). In a nutshell, the method obtains the total voting power of the consumer, iterates through the full valset (ordered power ascending) keeping track of a power sum, and when powerSum / totalPower > SoftOptOutThreshold, the SmallestNonOptOutPower is found and persisted.

Then, whenever the Slash() interface is executed on the consumer, if the voting power of the relevant validator being slashed is less than SmallestNonOptOutPower for that block, the slash request is dropped and never sent to the provider.

Consequences

Positive

  • Small validators can opt out of validating specific consumers without being punished for it.

Negative

  • The bottom x% is still part of the total voting power of the consumer chain. This means that if the soft opt-out threshold is set to 10% for example, and every validator in the bottom 10% opts out from validating the consumer, then a 24% downtime of the remaining voting power would halt the chain. This may be especially problematic during consumer upgrades.
  • In nominal scenarios, consumers with soft opt out enabled will be constructing slash packets for small vals, which may be dropped. This is wasted computation, but necessary to keep implementation simple. Note that the sdk's full downtime logic is always executed on the consumer, which can be computationally expensive and slow down certain blocks.

Neutral

  • Validators in the bottom of the valset who don't have to validate, may receive large delegation(s) which suddenly boost the validator to the subset that has to validate. This may catch the validator off guard.

References

  • Original issue with some napkin math #784
+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/adrs/adr-009-soft-opt-out.html.html b/legacy/v3.1.0/adrs/adr-009-soft-opt-out.html.html new file mode 100644 index 0000000000..f07f37706e --- /dev/null +++ b/legacy/v3.1.0/adrs/adr-009-soft-opt-out.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/adrs/adr-template.html b/legacy/v3.1.0/adrs/adr-template.html new file mode 100644 index 0000000000..54808aa916 --- /dev/null +++ b/legacy/v3.1.0/adrs/adr-template.html @@ -0,0 +1,22 @@ + + + + + +ADR Template | Interchain Security + + + + +
+
Version: v3.1.0

ADR {ADR-NUMBER}: {TITLE}

Changelog

  • {date}: {changelog}

Status

A decision may be "proposed" if it hasn't been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement.

{Deprecated|Proposed|Accepted}

Context

This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution.

Decision

This section explains all of the details of the proposed solution, including implementation details. +It should also describe affects / corollary items that may need to be changed as a part of this. +If the proposed change will be large, please also indicate a way to do the change to maximize ease of review. +(e.g. the optimal split of things to do between separate PR's)

Consequences

This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones.

Positive

Negative

Neutral

References

Are there any relevant PR comments, issues that led up to this, or articles referrenced for why we made the given design choice? If so link them here!

  • {reference link}
+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/adrs/adr-template.html.html b/legacy/v3.1.0/adrs/adr-template.html.html new file mode 100644 index 0000000000..a3997b9f94 --- /dev/null +++ b/legacy/v3.1.0/adrs/adr-template.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/adrs/intro.html b/legacy/v3.1.0/adrs/intro.html new file mode 100644 index 0000000000..d48c091a88 --- /dev/null +++ b/legacy/v3.1.0/adrs/intro.html @@ -0,0 +1,22 @@ + + + + + +ADRs | Interchain Security + + + + +
+
Version: v3.1.0

Architecture Decision Records (ADR)

This is a location to record all high-level architecture decisions in the Interchain Security project.

You can read more about the ADR concept in this blog post.

An ADR should provide:

  • Context on the relevant goals and the current state
  • Proposed changes to achieve the goals
  • Summary of pros and cons
  • References
  • Changelog

Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and +justification for a change in architecture, or for the architecture of something +new. The spec is much more compressed and streamlined summary of everything as +it is or should be.

If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match.

Note the context/background should be written in the present tense.

To suggest an ADR, please make use of the ADR template provided.

Table of Contents

ADR #DescriptionStatus
001Consumer chain key assignmentAccepted, Implemented
002Jail ThrottlingAccepted, Implemented
003Equivocation governance proposalAccepted, Implemented
004Denom DOS fixesAccepted, Implemented
007Pause validator unbonding during equivocation proposalProposed
008Throttle with retriesAccepted, In-progress
009Soft Opt-outAccepted, Implemented
+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/adrs/intro.html.html b/legacy/v3.1.0/adrs/intro.html.html new file mode 100644 index 0000000000..7490d100df --- /dev/null +++ b/legacy/v3.1.0/adrs/intro.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/consumer-development/app-integration.html b/legacy/v3.1.0/consumer-development/app-integration.html new file mode 100644 index 0000000000..703bdd162d --- /dev/null +++ b/legacy/v3.1.0/consumer-development/app-integration.html @@ -0,0 +1,23 @@ + + + + + +Developing an ICS consumer chain | Interchain Security + + + + +
+
Version: v3.1.0

Developing an ICS consumer chain

When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol. +To help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications.

Basic consumer chain

The source code for the example app can be found here.

Please note that consumer chains do not implement the staking module - the validator set is replicated from the provider, meaning that the provider and the consumer use the same validator set and their stake on the provider directly determines their stake on the consumer. +At present there is no opt-in mechanism available, so all validators of the provider must also validate on the provider chain.

Your chain should import the consumer module from x/consumer and register it in the correct places in your app.go. +The x/consumer module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in. +You should not need to manage or override any code from the x/consumer module.

Democracy consumer chain

The source code for the example app can be found here.

This type of consumer chain wraps the basic CosmosSDK x/distribution, x/staking and x/governance modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system.

This allows the consumer chain to leverage those modules while also using the x/consumer module.

With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.

Standalone chain to consumer chain changeover

This feature is being actively worked on. Information will be provided at a later time.

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/consumer-development/app-integration.html.html b/legacy/v3.1.0/consumer-development/app-integration.html.html new file mode 100644 index 0000000000..48f5358e9e --- /dev/null +++ b/legacy/v3.1.0/consumer-development/app-integration.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/consumer-development/consumer-chain-governance.html b/legacy/v3.1.0/consumer-development/consumer-chain-governance.html new file mode 100644 index 0000000000..91c544541c --- /dev/null +++ b/legacy/v3.1.0/consumer-development/consumer-chain-governance.html @@ -0,0 +1,19 @@ + + + + + +Consumer Chain Governance | Interchain Security + + + + +
+
Version: v3.1.0

Consumer Chain Governance

Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We'll cover what these are in the "Whitelist" section below.

Democracy module

The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy.

Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus.

For an example, see the Democracy Consumer

CosmWasm

There several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain.

For an example, see Neutron.

The Whitelist

Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see Neutron's whitelist.

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/consumer-development/consumer-chain-governance.html.html b/legacy/v3.1.0/consumer-development/consumer-chain-governance.html.html new file mode 100644 index 0000000000..a890806902 --- /dev/null +++ b/legacy/v3.1.0/consumer-development/consumer-chain-governance.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/consumer-development/consumer-chain-upgrade-procedure.html b/legacy/v3.1.0/consumer-development/consumer-chain-upgrade-procedure.html new file mode 100644 index 0000000000..d646a976fe --- /dev/null +++ b/legacy/v3.1.0/consumer-development/consumer-chain-upgrade-procedure.html @@ -0,0 +1,19 @@ + + + + + +Upgrading Consumer Chains | Interchain Security + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/consumer-development/consumer-chain-upgrade-procedure.html.html b/legacy/v3.1.0/consumer-development/consumer-chain-upgrade-procedure.html.html new file mode 100644 index 0000000000..1e68787775 --- /dev/null +++ b/legacy/v3.1.0/consumer-development/consumer-chain-upgrade-procedure.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/consumer-development/offboarding.html b/legacy/v3.1.0/consumer-development/offboarding.html new file mode 100644 index 0000000000..21c1e25b0d --- /dev/null +++ b/legacy/v3.1.0/consumer-development/offboarding.html @@ -0,0 +1,19 @@ + + + + + +Offboarding Checklist | Interchain Security + + + + +
+
Version: v3.1.0

Consumer Offboarding

To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).

// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.
// If it passes, all the consumer chain's state is removed from the provider chain. The outstanding unbonding
// operation funds are released.
{
// the title of the proposal
"title": "This was a great chain",
"description": "Here is a .md formatted string specifying removal details",
// the chain-id of the consumer chain to be stopped
"chain_id": "consumerchain-1",
// the time on the provider chain at which all validators are responsible to stop their consumer chain validator node
"stop_time": "2023-03-07T12:40:00.000000Z",
}

More information will be listed in a future version of this document.

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/consumer-development/offboarding.html.html b/legacy/v3.1.0/consumer-development/offboarding.html.html new file mode 100644 index 0000000000..a7d521e19d --- /dev/null +++ b/legacy/v3.1.0/consumer-development/offboarding.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/consumer-development/onboarding.html b/legacy/v3.1.0/consumer-development/onboarding.html new file mode 100644 index 0000000000..60ed755b00 --- /dev/null +++ b/legacy/v3.1.0/consumer-development/onboarding.html @@ -0,0 +1,20 @@ + + + + + +Onboarding Checklist | Interchain Security + + + + +
+
Version: v3.1.0

Consumer Onboarding Checklist

The following checklists will aid in onboarding a new consumer chain to replicated security.

Additionally, you can check the testnet repo for a comprehensive guide on preparing and launching consumer chains.

1. Complete testing & integration

  • test integration with gaia
  • test your protocol with supported relayer versions (minimum hermes 1.4.1)
  • reach out to the ICS team if you are facing issues

2. Create an Onboarding Repository

To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain.

This should include (at minimum):

  • genesis.json witout CCV data (before the propsal passes)
  • genesis.json with CCV data (after spawn time passes)
  • information about relevant seed/peer nodes you are running
  • relayer information (compatible versions)
  • copy of your governance proposal (as JSON)
  • a script showing how to start your chain and connect to peers (optional)
  • take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable

Example of such a repository can be found here.

3. Submit a Governance Proposal

Before you submit a ConsumerChainAddition proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch. +If possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues.

Additionally, reach out to the community via the forum to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers.

  • determine your chain's spawn time
  • determine consumer chain parameters to be put in the proposal
  • take note to include a link to your onboarding repository
  • describe the purpose and benefits of running your chain

Example of a consumer chain addition proposal.

// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.
// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.
// It is recommended that spawn time occurs after the proposal end time.
{
// Title of the proposal
"title": "Add consumer chain",
// Description of the proposal
// format the text as a .md file and include the file in your onboarding repository
"description": ".md description of your chain and all other relevant information",
// Proposed chain-id of the new consumer chain.
// Must be unique from all other consumer chain ids of the executing provider chain.
"chain_id": "newchain-1",
// Initial height of new consumer chain.
// For a completely new chain, this will be {0,1}.
"initial_height" : {
"revision_height": 0,
"revision_number": 1,
},
// Hash of the consumer chain genesis state without the consumer CCV module genesis params.
// It is used for off-chain confirmation of genesis.json validity by validators and other parties.
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
// Hash of the consumer chain binary that should be run by validators on chain initialization.
// It is used for off-chain confirmation of binary validity by validators and other parties.
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
// Unbonding period for the consumer chain.
// It should should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
// IBC transfer packets will timeout after this interval elapses.
"transfer_timeout_period": 1800000000000,
// The fraction of tokens allocated to the consumer redistribution address during distribution events.
// The fraction is a string representing a decimal number. For example "0.75" would represent 75%.
// The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.
"consumer_redistribution_fraction": "0.75",
// BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.
// eg. send rewards to the provider every 1000 blocks
"blocks_per_distribution_transmission": 1000,
// The number of historical info entries to persist in store.
// This param is a part of the cosmos sdk staking module. In the case of
// a ccv enabled consumer chain, the ccv module acts as the staking module.
"historical_entries": 10000,
// The ID of a token transfer channel used for the Reward Distribution
// sub-protocol. If DistributionTransmissionChannel == "", a new transfer
// channel is created on top of the same connection as the CCV channel.
// Note that transfer_channel_id is the ID of the channel end on the consumer chain.
// it is most relevant for chains performing a sovereign to consumer changeover
// in order to maintan the existing ibc transfer channel
"distribution_transmission_channel": "channel-123"
}

4. Launch

The consumer chain starts after at least 66.67% of all provider's voting power comes online. The consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer

  • provide a repo with onboarding instructions for validators (it should already be listed in the proposal)
  • genesis.json with ccv data populated (MUST contain the initial validator set)
  • maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)
  • have a block explorer in place to track chain activity & health
+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/consumer-development/onboarding.html.html b/legacy/v3.1.0/consumer-development/onboarding.html.html new file mode 100644 index 0000000000..79f6fed089 --- /dev/null +++ b/legacy/v3.1.0/consumer-development/onboarding.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/faq.html b/legacy/v3.1.0/faq.html new file mode 100644 index 0000000000..0c4134072e --- /dev/null +++ b/legacy/v3.1.0/faq.html @@ -0,0 +1,24 @@ + + + + + +Frequently Asked Questions | Interchain Security + + + + +
+
Version: v3.1.0

Frequently Asked Questions

What is the meaning of Validator Set Replication?

VSR simply means that the same validator set is used to secure both the provider and consumer chains. VSR is ensured through ICS protocol which keeps consumers up to date with the validator set of the provider.

What even is a consumer chain?

Consumer chain is blockchain operated by the same validator operators as the provider chain. The ICS protocol ensures the validator set replication properties (informs consumer chain about the current state of the validator set on the provider)

Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements.

What happens to consumer if provider is down?

In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set.

The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness.

However, if the trusting_period (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain. +This means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about.

Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point. +At the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.

What happens to provider if consumer is down?

Consumer chains do not impact the provider chain. +The ICS protocol is concerned only with validator set replication and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events).

Can I run the provider and consumer chains on the same machine?

Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation.

Can the consumer chain have its own token?

As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees.

How are Tx fees paid on consumer?

The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations.

Are there any restrictions the consumer chains need to abide by?

No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way. +The only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain.

What's in it for the validators and stakers?

The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by consumer_redistribution_fraction. The rewards are distributed (sent to the provider) every blocks_per_distribution_transmission.

note

consumer_redistribution_fraction and blocks_per_distribution_transmission are parameters defined in the ConsumerAdditionProposal used to create the consumer chain. These parameters can be changed via consumer chain governance.

Can the consumer chain have its own governance?

Yes.

In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.

Validators can also be representatives but representatives are not required to run validator nodes.

This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance.

Can validators opt-out of replicated security?

At present, the validators cannot opt-out of validating consumer chains.

There are multiple opt-out mechanisms under active research.

How does Equivocation Governance Slashing work?

To avoid potential attacks directed at provider chain validators, a new mechanism was introduced:

When a validator double-signs on the consumer chain, a special type of slash packet is relayed to the provider chain. The provider will store information about the double signing validator and allow a governance proposal to be submitted. +If the double-signing proposal passes, the offending validator will be slashed on the provider chain and tombstoned. Tombstoning will permanently exclude the validator from the active set of the provider.

caution

An equivocation proposal cannot be submitted for a validator that did not double sign on any of the consumer chains.

Can Consumer Chains perform Software Upgrades?

Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM).

Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module.

How can I connect to the testnets?

Check out the Joining Replicated Security testnet section.

How do I start using ICS?

To become a consumer chain use this checklist and check the App integration section

Which relayers are supported?

Currently supported versions:

  • Hermes 1.4.1

How does key delegation work in ICS?

You can check the Key Assignment Guide for specific instructions.

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/faq.html.html b/legacy/v3.1.0/faq.html.html new file mode 100644 index 0000000000..86da540ee6 --- /dev/null +++ b/legacy/v3.1.0/faq.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/features/key-assignment.html b/legacy/v3.1.0/features/key-assignment.html new file mode 100644 index 0000000000..9133142d7b --- /dev/null +++ b/legacy/v3.1.0/features/key-assignment.html @@ -0,0 +1,20 @@ + + + + + +Key Assignment | Interchain Security + + + + +
+
Version: v3.1.0

Key Assignment

Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate. +There are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains.

The feature is outlined in this ADR-001

By sending an AssignConsumerKey transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator.

tip

Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity.

Rules

  • a key can be assigned before the consumer addition proposal passes on the provider
  • validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider
  • validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X
  • a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain
tip

Validators can use a different key for each consumer chain.

Adding a key

First, create a new node on the consumer chain using the equivalent:

consumerd init <moniker>

Then query your node for the consensus key.

consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}

Then, make an assign-consensus-key transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain.

gaiad tx provider assign-consensus-key <consumer-chain-id> '<pubkey>' --from <tx-signer> --home <home_dir> --gas 900000 -b sync -y -o json
  • consumer-chain-id is the string identifier of the consumer chain, as assigned on the provider chain
  • consumer-pub-key has the following format {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}

Check that the key was assigned correcly by querying the provider:

gaiad query provider validator-consumer-key <consumer-chain-id> cosmosvalcons1e....3xsj3ayzf4uv6

You must use a valcons address. You can obtain it by querying your node on the provider gaiad tendermint show-address

OR

gaiad query provider validator-provider-key <consumer-chain-id> consumervalcons1e....123asdnoaisdao

You must use a valcons address. You can obtain it by querying your node on the consumer consumerd tendermint show-address

Changing a key

To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied

Removing a key

To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the Adding a key section and using your provider consensus key.

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/features/key-assignment.html.html b/legacy/v3.1.0/features/key-assignment.html.html new file mode 100644 index 0000000000..c9719af9ef --- /dev/null +++ b/legacy/v3.1.0/features/key-assignment.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/features/proposals.html b/legacy/v3.1.0/features/proposals.html new file mode 100644 index 0000000000..bd7dd515fe --- /dev/null +++ b/legacy/v3.1.0/features/proposals.html @@ -0,0 +1,26 @@ + + + + + +ICS Provider Proposals | Interchain Security + + + + +
+
Version: v3.1.0

ICS Provider Proposals

Interchain security module introduces 3 new proposal types to the provider.

The proposals are used to propose upcoming interchain security events through governance.

ConsumerAdditionProposal

info

If you are preparing a ConsumerAdditionProposal you can find more information in the consumer onboarding checklist.

Proposal type used to suggest adding a new consumer chain.

When proposals of this type are passed and the spawn_time specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain.

Minimal example:

{
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
"title": "Add consumer chain",
"description": ".md description of your chain and all other relevant information",
"chain_id": "newchain-1",
"initial_height" : {
"revision_height": 0,
"revision_number": 1,
},
// Unbonding period for the consumer chain.
// It should should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
"transfer_timeout_period": 1800000000000,
"consumer_redistribution_fraction": "0.75",
"blocks_per_distribution_transmission": 1000,
"historical_entries": 10000,
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1"
// relevant for chains performing a sovereign to consumer changeover
// in order to maintan the existing ibc transfer channel
"distribution_transmission_channel": "channel-123"
}

More examples can be found in the replicated security testnet repository here and here.

ConsumerRemovalProposal

Proposal type used to suggest removing an existing consumer chain.

When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain. +After the consumer chain removal, the chain in question will no longer be secured by the provider's validator set.

info

The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain. +Additional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set. +More information will be made available in the Consumer Offboarding Checklist.

Minimal example:

{
// the time on the provider chain at which all validators are responsible to stop their consumer chain validator node
"stop_time": "2023-03-07T12:40:00.000000Z",
// the chain-id of the consumer chain to be stopped
"chain_id": "consumerchain-1",
"title": "This was a great chain",
"description": "Here is a .md formatted string specifying removal details"
}

EquivocationProposal

tip

EquivocationProposal will only be accepted on the provider chain if at least one of the consumer chains submits equivocation evidence to the provider. +Sending equivocation evidence to the provider is handled automatically by the interchain security protocol when an equivocation infraction is detected on the consumer chain.

Proposal type used to suggest slashing a validator for double signing on consumer chain. +When proposals of this type are passed, the validator in question will be slashed for equivocation on the provider chain.

danger

Take note that an equivocation slash causes a validator to be tombstoned (can never re-enter the active set). +Tombstoning a validator on the provider chain will remove the validator from the validator set of all consumer chains.

Minimal example:

{
"title": "Validator-1 double signed on consumerchain-1",
"description": "Here is more information about the infraction so you can verify it yourself",
// the list of equivocations that will be processed
"equivocations": [
{
"height": 14444680,
"time": "2023-02-28T20:40:00.000000Z",
"power": 5500000,
"consensus_address": "<consensus address ON THE PROVIDER>"
}
]
}

Notes

When submitting equivocation evidence through an EquivocationProposal please take note that you need to use the consensus address (valcons) of the offending validator on the provider chain. +Besides that, the height and the time fields should be mapped to the provider chain to avoid your evidence being rejected.

Before submitting the proposal please check that the evidence is not outdated by comparing the infraction height with the max_age_duration and max_age_num_blocks consensus parameters of the provider chain.

Gaia example:

➜  ~ cat genesis.json | jq ".consensus_params"
{
"block": {
...
},
"evidence": {
"max_age_duration": "172800000000000",
"max_age_num_blocks": "1000000",
"max_bytes": "50000"
},
"validator": {
...
},
"version": {}
}

Any EquivocationProposal transactions that submit evidence with height older than max_age_num_blocks and time older than max_age_duration will be considered invalid.

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/features/proposals.html.html b/legacy/v3.1.0/features/proposals.html.html new file mode 100644 index 0000000000..9859bcf244 --- /dev/null +++ b/legacy/v3.1.0/features/proposals.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/features/reward-distribution.html b/legacy/v3.1.0/features/reward-distribution.html new file mode 100644 index 0000000000..b907cbefc2 --- /dev/null +++ b/legacy/v3.1.0/features/reward-distribution.html @@ -0,0 +1,25 @@ + + + + + +Reward distribution | Interchain Security + + + + +
+
Version: v3.1.0

Reward distribution

Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators. +In replicated security block rewards and fees are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel that gets created during consumer chain initialization.

Reward distribution on the provider is handled by the distribution module - validators and delegators receive a fraction of the consumer chain tokens as staking rewards. +The distributed reward tokens are IBC tokens and therefore cannot be staked on the provider chain.

Sending and distributing rewards from consumer chains to provider chain is handled by the Reward Distribution sub-protocol.

Note

The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the ConsumerRewardsPool. +There is a new transaction type called RegisterConsumerRewardDenom. This transaction allows consumer chains to register denoms to be used as consumer chain rewards on the provider. +The cost to register a denom is configurable (ConsumerRewardDenomRegistrationFee chain param) and the full amount of this fee is transferred to the community pool of the provider chain. Only denoms registered through this transaction are then transferred from the ConsumerRewardsPool to the FeePoolAddress, to be distributed out to delegators and validators.

Instructions for adding a denom

The transaction must be carried out on the provider chain. Please use the ibc/* denom trace format.

tip
# reward denoms must be registered on the provider chain (gaia in this example)
gaiad tx provider register-consumer-reward-denom ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9 --from mykey

Parameters

tip

The following chain parameters dictate consumer chain distribution amount and frequency. +They are set at consumer genesis and blocks_per_distribution_transmission, consumer_redistribution_fraction +transfer_timeout_period must be provided in every ConsumerChainAddition proposal.

consumer_redistribution_fraction

The fraction of tokens allocated to the consumer redistribution address during distribution events. The fraction is a string representing a decimal number. For example "0.75" would represent 75%.

tip

Example:

With consumer_redistribution_fraction set to 0.75 the consumer chain would send 75% of its block rewards and accumulated fees to the consumer redistribution address, and the remaining 25% to the provider chain every n blocks where n == blocks_per_distribution_transmission.

blocks_per_distribution_transmission

The number of blocks between IBC token transfers from the consumer chain to the provider chain.

transfer_timeout_period

Timeout period for consumer chain reward distribution IBC packets.

distribution_transmission_channel

Provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.

provider_fee_pool_addr_str

Provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/features/reward-distribution.html.html b/legacy/v3.1.0/features/reward-distribution.html.html new file mode 100644 index 0000000000..6cc53fcbab --- /dev/null +++ b/legacy/v3.1.0/features/reward-distribution.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/features/slashing.html b/legacy/v3.1.0/features/slashing.html new file mode 100644 index 0000000000..cb8cf130ee --- /dev/null +++ b/legacy/v3.1.0/features/slashing.html @@ -0,0 +1,22 @@ + + + + + +Consumer Initiated Slashing | Interchain Security + + + + +
+
Version: v3.1.0

Consumer Initiated Slashing

A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of it's own chain. +In essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake).

To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized. +Any infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains.

In the current implementation there are 2 important changes brought by the interchain security module:

Downtime infractions

reported by consumer chains are acted upon on the provider as soon as the provider receives the infraction evidence.

Instead of slashing, the provider will only jail offending validator for the duration of time established in the chain parameters.

info

Slash throttling (sometimes called jail throttling) mechanism insures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider.

Double-signing (equivocation)

infractions are not acted upon immediately.

Upon receiving double signing evidence, the provider chain will take note of the evidence and allow for EquivocationProposal to be submitted to slash the offending validator. +Any EquivocationProposals to slash a validator that has not double signed on any of the consumer chains will be automatically rejected by the provider chain.

info

The offending validator will only be slashed (and tombstoned) if an EquivocationProposal is accepted and passed through governance.

The offending validator will effectively get slashed and tombstoned on all consumer chains.

You can find instructions on creating EquivocationProposals here.

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/features/slashing.html.html b/legacy/v3.1.0/features/slashing.html.html new file mode 100644 index 0000000000..212f946c37 --- /dev/null +++ b/legacy/v3.1.0/features/slashing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/introduction/overview.html b/legacy/v3.1.0/introduction/overview.html new file mode 100644 index 0000000000..29451566f5 --- /dev/null +++ b/legacy/v3.1.0/introduction/overview.html @@ -0,0 +1,19 @@ + + + + + +Overview | Interchain Security + + + + +
+
Version: v3.1.0

Overview

info

Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.


Replicated security allows anyone to launch a "consumer" blockchain using the same validator set as the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit the full security and decentralization of the provider.

Why Replicated Security?

  • Full provider security. At launch, consumer chains are secured by the full validator set and market cap of the provider chain.
  • Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum.
  • Projects keep majority of gas fees. Depending on configuration, these fees either go to the project’s community DAO, or can be used in the protocol in other ways.
  • No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. A governance vote will take place for a chain to get adopted by the provider validators which will encourage participation and signal strong buy-in into the project's long-term success.
  • Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set.

Core protocol

info

Protocol specification is available as ICS-028 in the IBC repository.

Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer.

To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider.

Downtime Slashing

If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period.

Equivocation (Double Sign) Slashing

Evidence of equivocation must be submitted to provider governance and be voted on. This behavior is an extra safeguard before a validator is slashed, and may be replaced by a more automated system in the future.

Tokenomics and Rewards

Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance.

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/introduction/overview.html.html b/legacy/v3.1.0/introduction/overview.html.html new file mode 100644 index 0000000000..581441388b --- /dev/null +++ b/legacy/v3.1.0/introduction/overview.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/introduction/params.html b/legacy/v3.1.0/introduction/params.html new file mode 100644 index 0000000000..bf05f6ac8e --- /dev/null +++ b/legacy/v3.1.0/introduction/params.html @@ -0,0 +1,21 @@ + + + + + +Interchain Security Parameters | Interchain Security + + + + +
+
Version: v3.1.0

Interchain Security Parameters

The parameters necessary for Interchain Security (ICS) are defined in

  • the Params structure in proto/interchain_security/ccv/provider/v1/provider.proto for the provider;
  • the Params structure in proto/interchain_security/ccv/consumer/v1/consumer.proto for the consumer.

Time-based parameters

ICS relies on the following time-based parameters.

ProviderUnbondingPeriod

is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance.

ConsumerUnbondingPeriod

is the unbonding period on the consumer chain.

info

ConsumerUnbondingPeriod is set via the ConsumerAdditionProposal governance proposal to add a new consumer chain. +It is recommended that every consumer chain set and unbonding period shorter than ProviderUnbondingPeriod


Example:

ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day

Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer.

TrustingPeriodFraction

is used to calculate the TrustingPeriod of created IBC clients on both provider and consumer chains.

Setting TrustingPeriodFraction to 0.5 would result in the following:

TrustingPeriodFraction = 0.5
ProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5
ConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5

Note that a light clients must be updated within the TrustingPeriod in order to avoid being frozen.

For more details, see the IBC specification of Tendermint clients.

CCVTimeoutPeriod

is the period used to compute the timeout timestamp when sending IBC packets.

For more details, see the IBC specification of Channel & Packet Semantics.

danger

If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed.

CCVTimeoutPeriod may have different values on the provider and consumer chains.

  • CCVTimeoutPeriod on the provider must be larger than ConsumerUnbondingPeriod
  • CCVTimeoutPeriod on the consumer is initial set via the ConsumerAdditionProposal

InitTimeoutPeriod

is the maximum allowed duration for CCV channel initialization to execute.

For any consumer chain, if the CCV channel is not established within InitTimeoutPeriod then the consumer chain will be removed and therefore will not be secured by the provider chain.

The countdown starts when the spawn_time specified in the ConsumerAdditionProposal is reached.

VscTimeoutPeriod

is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live. +If the VscTimeoutPeriod is ever reached for a consumer chain that chain will be considered not live and removed from interchain security.

tip

VscTimeoutPeriod MUST be larger than the ConsumerUnbondingPeriod.

BlocksPerDistributionTransmission

is the number of blocks between rewards transfers from the consumer to the provider.

TransferPeriodTimeout

is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider.

If this timeout expires, then the transfer is attempted again after BlocksPerDistributionTransmission blocks.

  • TransferPeriodTimeout on the consumer is initial set via the ConsumerAdditionProposal gov proposal to add the consumer
  • TransferPeriodTimeout should be smaller than BlocksPerDistributionTransmission x avg_block_time

Slash Throttle Parameters

SlashMeterReplenishPeriod

exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed.

The meter is replenished to an amount equal to the slash meter allowance for that block, or SlashMeterReplenishFraction * CurrentTotalVotingPower.

SlashMeterReplenishFraction

exists on the provider as the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs.

This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a sdk.Dec when used.

MaxThrottledPackets

exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value.

This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness.

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/introduction/params.html.html b/legacy/v3.1.0/introduction/params.html.html new file mode 100644 index 0000000000..4e089c5b94 --- /dev/null +++ b/legacy/v3.1.0/introduction/params.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/introduction/technical-specification.html b/legacy/v3.1.0/introduction/technical-specification.html new file mode 100644 index 0000000000..eac266a8ff --- /dev/null +++ b/legacy/v3.1.0/introduction/technical-specification.html @@ -0,0 +1,19 @@ + + + + + +Technical Specification | Interchain Security + + + + +
+
Version: v3.1.0

Technical Specification

For a technical deep dive into the replicated security protocol, see the specification.

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/introduction/technical-specification.html.html b/legacy/v3.1.0/introduction/technical-specification.html.html new file mode 100644 index 0000000000..9decd0c12a --- /dev/null +++ b/legacy/v3.1.0/introduction/technical-specification.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/introduction/terminology.html b/legacy/v3.1.0/introduction/terminology.html new file mode 100644 index 0000000000..acca938205 --- /dev/null +++ b/legacy/v3.1.0/introduction/terminology.html @@ -0,0 +1,19 @@ + + + + + +Terminology | Interchain Security + + + + +
+
Version: v3.1.0

Terminology

You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.

Shared Security

Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share it's proof-of-stake security with another blockchain or off-chain process.

Interchain Security

Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC.

Replicated Security

A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC. Note this documentation is focused on explaining the concepts from replicated security.

Mesh security

A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see Replicated vs. Mesh Security on the Informal Blog.

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/introduction/terminology.html.html b/legacy/v3.1.0/introduction/terminology.html.html new file mode 100644 index 0000000000..4ee208837f --- /dev/null +++ b/legacy/v3.1.0/introduction/terminology.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/validators/joining-testnet.html b/legacy/v3.1.0/validators/joining-testnet.html new file mode 100644 index 0000000000..d3dde228a2 --- /dev/null +++ b/legacy/v3.1.0/validators/joining-testnet.html @@ -0,0 +1,20 @@ + + + + + +Joining Replicated Security testnet | Interchain Security + + + + +
+
Version: v3.1.0

Joining Replicated Security testnet

Introduction

This short guide will teach you how to join the Replicated Security testnet.

The experience gained in the testnet will prepare you for validating interchain secured chains.

tip

Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set.

For general information about running cosmos-sdk based chains check out the validator basics and Running a Node section of Cosmos SDK docs

Joining the provider chain

info

At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain.

A comprehensive guide is available here.

Initialization

First, initialize your $NODE_HOME using the provider chain binary.

NODE_MONIKER=<your_node>
CHAIN_ID=provider
NODE_HOME=<path_to_your_home>

gaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME

Add your key to the keyring - more details available here.

In this example we will use the test keyring-backend. This option is not safe to use in production.

gaiad keys add <key_moniker> --keyring-backend test

# save the address as variable for later use
MY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)

Before issuing any transactions, use the provider testnet faucet to add funds to your address.

curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider

# example output:
{
"address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",
"amount": "10000000uatom",
"chain": "provider",
"hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",
"status": "success"
}

Then, use the account associated with the keyring to issue a create-validator transaction which will register your validator on chain.

gaiad tx staking create-validator \
--amount=1000000uatom \
--pubkey=$(gaiad tendermint show-validator) \
--moniker="choose a moniker" \
--chain-id=$CHAIN_ID" \
--commission-rate="0.10" \
--commission-max-rate="0.20" \
--commission-max-change-rate="0.01" \
--min-self-delegation="1000000" \
--gas="auto" \
--gas-prices="0.0025uatom" \
--from=<key_moniker>
tip

Check this guide to edit your validator.

After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use statesync to catch up to the rest of the network.

You can use this script to modify your config.toml with the required statesync parameters.

# create the statesync script
$: cd $NODE_HOME
$: touch statesync.sh
$ chmod 700 statesync.sh # make executable

Paste the following instructions into the statesync.sh:

#!/bin/bash

SNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"

LATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \
BLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \
TRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)

sed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\1true| ; \
s|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\1\"$SNAP_RPC,$SNAP_RPC\"| ; \
s|^(trust_height[[:space:]]+=[[:space:]]+).*$|\1$BLOCK_HEIGHT| ; \
s|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\1\"$TRUST_HASH\"|" $NODE_HOME/config/config.toml

Then, you can execute the script:

$: ./statesync.sh # setup config.toml for statesync

Finally, copy the provider genesis and start your node:

$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/replicated-security/provider/provider-genesis.json
$: wget $GENESIS_URL -O genesis.json
$: genesis.json $NODE_HOME/config/genesis.json
# start the service
$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"

Additional scripts to setup your nodes are available here and here. The scripts will configure your node and create the required services - the scripts only work in linux environments.

Joining consumer chains

tip

Once you reach the active set on the provider chain, you will be required to validate all available consumer chains.

You can use the same consensus key on all consumer chains, or opt to use a different key on each consumer chain. +Check out this guide to learn more about key assignment in replicated security.

To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries.

info

When running the provider chain and consumers on the same machine please update the PORT numbers for each of them and make sure they do not overlap (otherwise the binaries will not start).

Important ports to re-configure:

  • --rpc.laddr
  • --p2p.laddr
  • --api.address
  • --grpc.address
  • --grpc-web.address

Re-using consensus key

To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the priv_validator_key.json into the home directory of your consumer chain (<consumer_home>/config/priv_validator_key.json).

When you start the chain, the consensus key will be the same on the provider and the consumer chain.

Assigning consensus keys

Whenever you initialize a new node, it will be configured with a consensus key you can use.

# machine running consumer chain
consumerd init <node_moniker> --home <home_path> --chain-id consumer-1

# use the output of this command to get the consumer chain consensus key
consumerd tendermint show-validator
# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}

Then, let the provider know which key you will be using for the consumer chain:

# machine running the provider chain
gaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b sync -y -o json

After this step, you are ready to copy the consumer genesis into your nodes's /config folder, start your consumer chain node and catch up to the network.

Baryon

You can find the onboarding repo instructions for the Baryon chain here

Noble

You can find the onboarding repo instructions for the Noble chain here

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/validators/joining-testnet.html.html b/legacy/v3.1.0/validators/joining-testnet.html.html new file mode 100644 index 0000000000..88c6bc1d1f --- /dev/null +++ b/legacy/v3.1.0/validators/joining-testnet.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/validators/overview.html b/legacy/v3.1.0/validators/overview.html new file mode 100644 index 0000000000..e1dc5cca23 --- /dev/null +++ b/legacy/v3.1.0/validators/overview.html @@ -0,0 +1,24 @@ + + + + + +Overview | Interchain Security + + + + +
+
Version: v3.1.0

Overview

tip

We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.

At present, replicated security requires all validators of the provider chain (ie. Cosmos Hub) to run validator nodes for all governance-approved consumer chains.

Once a ConsumerAdditionProposal passes, validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains.

Provider chain and consumer chains represent standalone chains that only share the validator set ie. the same validator operators are tasked with running all chains.

info

To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 180 validators for Cosmos Hub).

Startup sequence overview

Consumer chains cannot start and be secured by the validator set of the provider unless a ConsumerAdditionProposal is passed. +Each proposal contains defines a spawn_time - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider.

tip

Validators are required to run consumer chain binaries only after spawn_time has passed.

Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains.

The image below illustrates the startup sequence +startup

1. Consumer Chain init + 2. Genesis generation

Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ConsumerAdditionProposal

3. Submit Proposal

Consumer chain team (or their advocates) submits a ConsumerAdditionProposal. +The most important parameters for validators are:

  • spawn_time - the time after which the consumer chain must be started
  • genesis_hash - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and spawn_time is reached
  • binary_hash - hash of the consumer chain binary used to validate the software builds

4. CCV Genesis state generation

After reaching spawn_time the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain genesis.json. The CCV validator set consists of the validator set on the provider at spawn_time.

The state can be queried on the provider chain (in this case the Cosmos Hub):

 gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json

This is used by the launch coordinator to create the final genesis.json that will be distributed to validators in step 5.

5. Updating the genesis file

Upon reaching the spawn_time the initial validator set state will become available on the provider chain. The initial validator set is included in the final genesis.json of the consumer chain.

6. Chain start

info

The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences.

The new genesis.json containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided genesis.json to start their consumer chain node.

tip

Please pay attention to any onboarding repositories provided by the consumer chain teams. +Recommendations are available in Consumer Onboarding Checklist. +Another comprehensive guide is available in the Replicated Security testnet repo.

7. Creating IBC connections

Finally, to fully establish replicated security an IBC relayer is used to establish connections and create the required channels.

danger

The relayer can establish the connection only after the consumer chain starts producing blocks.

hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> 
hermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1
hermes start

Downtime Infractions

At present, the consumer chain can report evidence about downtime infractions to the provider chain. The min_signed_per_window and signed_blocks_window can be different on each consumer chain and are subject to changes via consumer chain governance.

info

Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains.

To unjail, the validator must wait for the jailing period to elapse on the provider chain and submit an unjail transaction on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains.

More information is available in Downtime Slashing documentation

Double-signing Infractions

To learn more about equivocation handling in replicated security check out the Slashing and EquivocationProposal documentation sections

Key assignment

Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use.

For more information check our the Key assignment overview and guide

References:

+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/validators/overview.html.html b/legacy/v3.1.0/validators/overview.html.html new file mode 100644 index 0000000000..db39cf3dd3 --- /dev/null +++ b/legacy/v3.1.0/validators/overview.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.1.0/validators/withdraw_rewards.html b/legacy/v3.1.0/validators/withdraw_rewards.html new file mode 100644 index 0000000000..d8b820a49e --- /dev/null +++ b/legacy/v3.1.0/validators/withdraw_rewards.html @@ -0,0 +1,20 @@ + + + + + +Withdrawing consumer chain validator rewards | Interchain Security + + + + +
+
Version: v3.1.0

Withdrawing consumer chain validator rewards

Here are example steps for withdrawing rewards from consumer chains in the provider chain

info

The examples used are from rs-testnet, the replicated security persistent testnet.

Validator operator address: cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 +Self-delegation address: cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

Prior to withdrawing rewards, query balances for self-delegation address:

gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

balances:
- amount: "1000000000000"
denom: uatom
pagination:
next_key: null
total: "0"

Querying validator rewards

Query rewards for the validator address:

gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6

rewards:
- amount: "158.069895000000000000"
denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD
- amount: "841842390516.072526500000000000"
denom: uatom

The ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD denom represents rewards from a consumer chain.

Withdrawing rewards and commission

1. Withdraw rewards

gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y

txhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A

2. Confirm withdrawal

After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:

gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

balances:
- amount: "216"
denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD
- amount: "2233766225342"
denom: uatom
pagination:
next_key: null
total: "0"
+ + + + \ No newline at end of file diff --git a/legacy/v3.1.0/validators/withdraw_rewards.html.html b/legacy/v3.1.0/validators/withdraw_rewards.html.html new file mode 100644 index 0000000000..62e81751f8 --- /dev/null +++ b/legacy/v3.1.0/validators/withdraw_rewards.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0.html b/legacy/v3.2.0.html new file mode 100644 index 0000000000..b28b14e050 --- /dev/null +++ b/legacy/v3.2.0.html @@ -0,0 +1,19 @@ + + + + + +Interchain Security Docs | Interchain Security + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0.html.html b/legacy/v3.2.0.html.html new file mode 100644 index 0000000000..aa907cd39d --- /dev/null +++ b/legacy/v3.2.0.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-001-key-assignment.html b/legacy/v3.2.0/adrs/adr-001-key-assignment.html new file mode 100644 index 0000000000..f0127a38ce --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-001-key-assignment.html @@ -0,0 +1,19 @@ + + + + + +Key Assignment | Interchain Security + + + + +
+
Version: v3.2.0

ADR 001: Key Assignment

Changelog

  • 2022-12-01: Initial Draft

Status

Accepted

Context

KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate.

Decision

It is possible to change the keys at any time by submitting a transaction (i.e., MsgAssignConsumerKey).

State required

  • ValidatorConsumerPubKey - Stores the validator assigned keys for every consumer chain.
ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey
  • ValidatorByConsumerAddr - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol.
ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress
  • KeyAssignmentReplacements - Stores the key assignments that need to be replaced in the current block. Needed to apply the key assignments received in a block to the validator updates sent to the consumer chains.
KeyAssignmentReplacementsBytePrefix | len(chainID) | chainID | providerConsAddress -> abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower},
  • ConsumerAddrsToPrune - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ValidatorByConsumerAddr.
ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses

Protocol overview

On receiving a MsgAssignConsumerKey(chainID, providerAddr, consumerKey) message:

// get validator from staking module  
validator, found := stakingKeeper.GetValidator(providerAddr)
if !found {
return ErrNoValidatorFound
}
providerConsAddr := validator.GetConsAddr()

// make sure consumer key is not in use
consumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)
if _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {
return ErrInvalidConsumerConsensusPubKey
}

// check whether the consumer chain is already registered
// i.e., a client to the consumer was already created
if _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {
// get the previous key assigned for this validator on this consumer chain
oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)
if found {
// mark this old consumer key as prunable once the VSCMaturedPacket
// for the current VSC ID is received
oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)
vscID := GetValidatorSetUpdateId()
AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)
} else {
// the validator had no key assigned on this consumer chain
oldConsumerKey := validator.TmConsPublicKey()
}

// check whether the validator is valid, i.e., its power is positive
if currentPower := stakingKeeper.GetLastValidatorPower(providerAddr); currentPower > 0 {
// to enable multiple calls of AssignConsumerKey in the same block by the same validator
// the key assignment replacement should not be overwritten
if _, found := GetKeyAssignmentReplacement(chainID, providerConsAddr); !found {
// store old key and power for modifying the valset update in EndBlock
oldKeyAssignment := abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower}
SetKeyAssignmentReplacement(chainID, providerConsAddr, oldKeyAssignment)
}
}
} else {
// if the consumer chain is not registered, then remove the previous reverse mapping
if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {
oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)
DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)
}
}


// set the mapping from this validator's provider address to the new consumer key
SetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)

// set the reverse mapping: from this validator's new consensus address
// on the consumer to its consensus address on the provider
SetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)

When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see MakeConsumerGenesis).

func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {
// ...
// get initial valset from the staking module
var updates []abci.ValidatorUpdate{}
stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {
validator := stakingKeeper.GetValidator(providerAddr)
providerKey := validator.TmConsPublicKey()
updates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})
return false
})

// applies the key assignment to the initial validator
for i, update := range updates {
providerAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)
if consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {
updates[i].PubKey = consumerKey
}
}
gen.InitialValSet = updates

// get a hash of the consumer validator set from the update
updatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)
hash := tendermint.NewValidatorSet(updatesAsValSet).Hash()

return gen, hash, nil
}

On EndBlock while queueing VSCPackets to send to registered consumer chains:

func QueueVSCPackets() {
valUpdateID := GetValidatorSetUpdateId()
// get the validator updates from the staking module
valUpdates := stakingKeeper.GetValidatorUpdates()

IterateConsumerChains(func(chainID, clientID string) (stop bool) {
// apply the key assignment to the validator updates
valUpdates := ApplyKeyAssignmentToValUpdates(chainID, valUpdates)
// ..
})
// ...
}

func ApplyKeyAssignmentToValUpdates(
chainID string,
valUpdates []abci.ValidatorUpdate,
) (newUpdates []abci.ValidatorUpdate) {
for _, valUpdate := range valUpdates {
providerAddr := utils.TMCryptoPublicKeyToConsAddr(valUpdate.PubKey)

// if a key assignment replacement is found, then
// remove the valupdate with the old consumer key
// and create two new valupdates
prevConsumerKey, _, found := GetKeyAssignmentReplacement(chainID, providerAddr)
if found {
// set the old consumer key's power to 0
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: prevConsumerKey,
Power: 0,
})
// set the new consumer key's power to the power in the update
newConsumerKey := GetValidatorConsumerPubKey(chainID, providerAddr)
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: newConsumerKey,
Power: valUpdate.Power,
})
// delete key assignment replacement
DeleteKeyAssignmentReplacement(chainID, providerAddr)
} else {
// there is no key assignment replacement;
// check if the validator's key is assigned
consumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr)
if found {
// replace the update containing the provider key
// with an update containing the consumer key
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: consumerKey,
Power: valUpdate.Power,
})
} else {
// keep the same update
newUpdates = append(newUpdates, valUpdate)
}
}
}

// iterate over the remaining key assignment replacements
IterateKeyAssignmentReplacements(chainID, func(
pAddr sdk.ConsAddress,
prevCKey tmprotocrypto.PublicKey,
power int64,
) (stop bool) {
// set the old consumer key's power to 0
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: prevCKey,
Power: 0,
})
// set the new consumer key's power to the power in key assignment replacement
newConsumerKey := GetValidatorConsumerPubKey(chainID, pAddr)
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: newConsumerKey,
Power: power,
})
return false
})

// remove all the key assignment replacements

return newUpdates
}

On receiving a SlashPacket from a consumer chain with id chainID for a infraction of a validator data.Validator:

func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {
// ...
// the slash packet validator address may be known only on the consumer chain;
// in this case, it must be mapped back to the consensus address on the provider chain
consumerAddr := sdk.ConsAddress(data.Validator.Address)
providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)
if !found {
// the validator has the same key on the consumer as on the provider
providerAddr = consumer
}
// ...
}

On receiving a VSCMatured:

func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {
// ...
// prune previous consumer validator address that are no longer needed
consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)
for _, addr := range consumerAddrs {
DeleteValidatorByConsumerAddr(chainID, addr)
}
DeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)
// ...
}

On stopping a consumer chain:

func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {
// ...
// deletes all the state needed for key assignments on this consumer chain
// ...
}

Consequences

Positive

  • Validators can use different consensus keys on the consumer chains.

Negative

  • None

Neutral

  • The consensus state necessary to create a client to the consumer chain must use the hash returned by the MakeConsumerGenesis method as the nextValsHash.
  • The consumer chain can no longer check the initial validator set against the consensus state on InitGenesis.

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-001-key-assignment.html.html b/legacy/v3.2.0/adrs/adr-001-key-assignment.html.html new file mode 100644 index 0000000000..6639d446cf --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-001-key-assignment.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-002-throttle.html b/legacy/v3.2.0/adrs/adr-002-throttle.html new file mode 100644 index 0000000000..eb33376ddf --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-002-throttle.html @@ -0,0 +1,19 @@ + + + + + +Jail Throttling | Interchain Security + + + + +
+
Version: v3.2.0

ADR 002: Jail Throttling

Changelog

  • 2023-01-26: Initial Draft
  • 2023-02-07: Property refined, ADR ready to review/merge

Status

Accepted

Context

The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols. In practice, this assumption may not hold. A malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider.

Before the throttling feature was implemented, the following attack was possible. Attacker(s) would create provider validators just below the provider's active set. Using a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once. Control of the provider would then pass over to the attackers' validators. This enables the attacker(s) to halt the provider. Or even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC.

Decision

The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack. Ie. this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time.

State Required - Slash Meter

There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time. This meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params.

State Required - Global entry queue

There exists a single queue which stores "global slash entries". These entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering. This queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.

State Required - Per-chain data queue

For each established consumer, there exists a queue which stores "throttled packet data". Ie. pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering. Order is enforced by IBC sequence number. These "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.

Reasoning - Multiple queues

For reasoning on why this feature was implemented with multiple queues, see spec. Specifically the section on VSC Maturity and Slashing Order. There are other ways to ensure such a property (like a queue of linked lists, etc.), but the implemented protocol seemed to be the most understandable and easiest to implement with a KV store.

Protocol Overview - OnRecvSlashPacket

Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:

  1. A global slash entry is queued.
  2. The data of such a packet is added to the per-chain queue.

Protocol Overview - OnRecvVSCMaturedPacket

Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue.

Endblocker Step 1 - Slash Meter Replenishment

Once the slash meter becomes not full, it'll be replenished after SlashMeterReplenishPeriod (param) by incrementing the meter with its allowance for the replenishment block, where allowance = SlashMeterReplenishFraction (param) * currentTotalVotingPower. The slash meter will never exceed its current allowance (fn of the total voting power for the block) in value. Note a few things:

  1. The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power. In such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods.
  2. Total voting power of a chain changes over time, especially as validators are jailed. As validators are jailed, total voting power decreases, and so does the jailing allowance. See below for more detailed throttling property discussion.
  3. The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1. If the SlashMeterReplenishFraction (param) is set too low, integer rounding will put this minimum value into effect. That is, if SlashMeterReplenishFraction * currentTotalVotingPower < 1, then the effective allowance would be 1. This min value of allowance ensures that there's some packets handled over time, even if that is a very long time. It's a crude solution to an edge case caused by too small of a replenishment fraction.

The behavior described above is achieved by executing CheckForSlashMeterReplenishment() every endblock, BEFORE HandleThrottleQueues() is executed.

Endblocker Step 2 - HandleLeadingVSCMaturedPackets

Every block it is possible that VSCMatured packet data was queued before any slash packet data. Since this "leading" VSCMatured packet data does not have to be throttled (see VSC Maturity and Slashing Order), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes.

Endblocker Step 3 - HandleThrottleQueues

Every endblocker the following pseudo-code is executed to handle data from the throttle queues.

meter := getSlashMeter()

// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist
while meter.IsPositiveOrZero() && entriesExist() {
// Get next entry in queue
entry := getNextGlobalSlashEntry()
// Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet
valPower := entry.getValPower()
meter = meter - valPower
// Using the per-chain queue, handle the single slash packet using its queued data,
// then handle all trailing VSCMatured packets for this consumer
handleSlashPacketAndTrailingVSCMaturedPackets(entry)
// Delete entry in global queue, delete handled data
entry.Delete()
deleteThrottledSlashPacketData()
deleteTrailingVSCMaturedPacketData()
}

System Properties

All CCV system properties should be maintained by implementing this feature, see: CCV spec - Consumer Initiated Slashing.

One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than MaxThrottledPackets (param), then the provider binary will panic, and the provider chain will halt. Therefore this param should be set carefully. See SetThrottledPacketDataSize. This behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators.

Main Throttling Property

Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions.

First, we define the following:

  • A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.
  • The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.
  • There is a list of honest validators s.t if they are jailed, X% of the initial validator set will be jailed.

For the following property to hold, these assumptions must be true:

  1. We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack.
  2. No validator has more than SlashMeterReplenishFraction of total voting power on the provider.
  3. SlashMeterReplenishFraction is large enough that SlashMeterReplenishFraction * currentTotalVotingPower > 1. Ie. the replenish fraction is set high enough that we can ignore the effects of rounding.
  4. SlashMeterReplenishPeriod is sufficiently longer than the time it takes to produce a block.

Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined.

Property:

The time it takes to jail/tombstone X% of the initial validator set will be greater than or equal to (X * SlashMeterReplenishPeriod / SlashMeterReplenishFraction) - 2 * SlashMeterReplenishPeriod

Intuition:

Let's use the following notation:

  • $C$: Number of replenishment cycles
  • $P$: $\text{SlashMeterReplenishPeriod}$
  • $F$: $\text{SlashMeterReplenishFraction}$
  • $V_{\mathit{max}}$: Max power of a validator as a fraction of total voting power

In $C$ number of replenishment cycles, the fraction of total voting power that can be removed, $a$, is $a \leq F \cdot C + V{\mathit{max}}$ (where $V{\mathit{max}}$ is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value).

So, we need at least $C \geq \frac{a - V_{\mathit{max}}}{F}$ cycles to remove $a$ fraction of the total voting power.

Since we defined the start of the attack to be the moment when the first slash request arrives, then $F$ fraction of the initial validator set can be jailed immediately. For the remaining $X - F$ fraction of the initial validator set to be jailed, it takes at least $C \geq \frac{(X - F) - V{\mathit{max}}}{F}$ cycles. Using the assumption that $V{\mathit{max}} \leq F$ (assumption 2), we get $C \geq \frac{X - 2F}{F}$ cycles.

In order to execute $C$ cycles, we need $C \cdot P$ time.

Thus, jailing the remaining $X - F$ fraction of the initial validator set corresponds to $\frac{P \cdot (X - 2F)}{F}$ time.

In other words, the attack must take at least $\frac{P \cdot X}{F} - 2P$ time (in the units of replenish period $P$).

This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests. For example, if SlashMeterReplenishFraction is set to 0.06, then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub. Note that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power.

Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings.

How Unjailing Affects the Main Throttling Property

Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained.

If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider.

In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack.

Consequences

Positive

  • The described attack is slowed down in seemingly all cases.
  • If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded.

Negative

  • Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below. However, this is sacrificing liveness in a edge case scenario for the sake of security. As an improvement, using retries would fully prevent this attack vector.

Neutral

  • Additional state is introduced to the provider chain.
  • VSCMatured and slash packet data is not always handled in the same block that it is received.

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-002-throttle.html.html b/legacy/v3.2.0/adrs/adr-002-throttle.html.html new file mode 100644 index 0000000000..06dde972f0 --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-002-throttle.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-003-equivocation-gov-proposal.html b/legacy/v3.2.0/adrs/adr-003-equivocation-gov-proposal.html new file mode 100644 index 0000000000..e109f0ff49 --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-003-equivocation-gov-proposal.html @@ -0,0 +1,19 @@ + + + + + +Equivocation governance proposal | Interchain Security + + + + +
+
Version: v3.2.0

ADR 003: Equivocation governance proposal

Changelog

  • 2023-02-06: Initial draft

Status

Accepted

Context

We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain.

For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence.

Decision

To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain.

A new kind of governance proposal is added to the provider module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain.

If such proposal passes, the proposal handler delegates to the evidence module to process the equivocation. This module ensures the evidence isn’t too old, or else ignores it (see code). Too old is determined by 2 consensus params :

  • evidence.max_age_duration number of nanoseconds before an evidence is considered too old
  • evidence.max_age_numblocks number of blocks before an evidence is considered too old.

On the hub, those parameters are equals to

// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682
(...)
"evidence": {
"max_age_num_blocks": "1000000",
"max_age_duration": "172800000000000",
(...)
},
(...)

A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the evidence module when the proposal passes and is handled by the hub.

For max_age_num_blocks=1M, the parameter is big enough if we consider the hub produces 12k blocks per day (blocks_per_year/365 = 436,0000/365). The evidence can be up to 83 days old (1,000,000/12,000) and not be ignored.

For max_age_duration=172,800,000,000,000, the parameter is too low, because the value is in nanoseconds so it’s 2 days. Fortunately the condition that checks those 2 parameters uses a AND, so if max_age_num_blocks condition passes, the evidence won’t be ignored.

Consequences

Positive

  • Remove the possibility from a malicious consumer chain to “attack” the provider chain by slashing/jailing validators.
  • Provide a more acceptable implementation for the validator community.

Negative

  • Punishment action of double-signing isn’t “automated”, a governance proposal is required which takes more time.
  • You need to pay 250ATOM to submit an equivocation evidence.

Neutral

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-003-equivocation-gov-proposal.html.html b/legacy/v3.2.0/adrs/adr-003-equivocation-gov-proposal.html.html new file mode 100644 index 0000000000..78c86c2a41 --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-003-equivocation-gov-proposal.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-005-cryptographic-equivocation-verification.html b/legacy/v3.2.0/adrs/adr-005-cryptographic-equivocation-verification.html new file mode 100644 index 0000000000..a5440e3e62 --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-005-cryptographic-equivocation-verification.html @@ -0,0 +1,56 @@ + + + + + +Cryptographic verification of equivocation evidence | Interchain Security + + + + +
+
Version: v3.2.0

ADR 005: Cryptographic verification of equivocation evidence

Changelog

  • 5/1/2023: First draft
  • 7/23/23: Add light client attacks handling

Status

Accepted

Context

Currently, we use a governance proposal to slash validators for equivocation (double signing and light client attacks). +Every proposal needs to go through a (two weeks) voting period before it can be approved. +Given a three-week unbonding period, this means that an equivocation proposal needs to be submitted within one week since the infraction occurred.

This ADR proposes a system to slash validators automatically for equivocation, immediately upon the provider chain's receipt of the evidence. Another thing to note is that we intend to introduce this system in stages, since even the partial ability to slash and/or tombstone is a strict improvement in security. +For the first stage of this work, we will only handle light client attacks.

Light Client Attack

In a nutshell, the light client is a process that solely verifies a specific state machine's +consensus without executing the transactions. The light clients get new headers by querying +multiple nodes, called primary and witness nodes.

Light clients download new headers committed on chain from a primary. Headers can be verified in two ways: sequentially, +where the block height of headers is serial, or using skipping. This second verification method allows light clients to download headers +with nonconsecutive block height, where some intermediate headers are skipped (see Tendermint Light Client, Figure 1 and Figure 3). +Additionally, light clients are cross-checking new headers obtained from a primary with witnesses to ensure all nodes share the same state.

A light client attack occurs when a Byzantine validator sends invalid headers to a light client. +As the light client doesn't execute transactions, it can be deceived into trusting corrupted application state transitions. +For instance, if a light client receives header A from the primary and header B from a witness for the same block height H, +and both headers are successfully verified, it indicates a light client attack. +Note that in this case, either the primary or the witness or both are malicious.

The types of light client attacks are defined by analyzing the differences between the conflicting headers. +There are three types of light client attacks: lunatic attack, equivocation attack, and amnesia attack. +For details, see the CometBFT specification.

When a light client agent detects two conflicting headers, it will initially verify their traces (see cometBFT detector) using its primary and witness nodes. +If these headers pass successful verification, the Byzantine validators will be identified based on the header's commit signatures +and the type of light client attack. The agent will then transmit this information to its nodes using a LightClientAttackEvidence to be eventually voted on and added to a block. +Note that from a light client agent perspective, it is not possible to establish whether a primary or a witness node, or both, are malicious. +Therefore, it will create and send two LightClientAttackEvidence: one against the primary (sent to the witness), and one against the witness (sent to the primary). +Both nodes will then verify it before broadcasting it and adding it to the evidence pool. +If a LightClientAttackEvidence is finally committed to a block, the chain's evidence module will execute it, resulting in the jailing and the slashing of the validators responsible for the light client attack.

Light clients are a core component of IBC. In the event of a light client attack, IBC relayers notify the affected chains by submitting an IBC misbehavior message. +A misbehavior message includes the conflicting headers that constitute a LightClientAttackEvidence. Upon receiving such a message, +a chain will first verify whether these headers would have convinced its light client. This verification is achieved by checking +the header states against the light client consensus states (see IBC misbehaviour handler). If the misbehaviour is successfully verified, the chain will then "freeze" the +light client, halting any further trust in or updating of its states.

Decision

In the first iteration of the feature, we will introduce a new endpoint: HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour). +The main idea is to leverage the current IBC misbehaviour handling and update it to solely jail and slash the validators that +performed a light client attack. This update will be made under the assumption that the chain connected via this light client +share the same validator set, as it is the case with Replicated Security.

This endpoint will reuse the IBC client libraries to verify that the misbehaviour headers would have fooled the light client. +Additionally, it’s crucial that the endpoint logic result in the slashing and jailing of validators under the same conditions +as a light client agent detector. Therefore, the endpoint will ensure that the two conditions are met: +the headers in the misbehaviour message have the same block height, and +the light client isn’t expired.

After having successfully verified a misbehaviour, the endpoint will execute the jailing and slashing of the malicious validators similarly as in the evidence module.

Current limitations:

  • This only handles light client attacks, not double signing. In the future, we will add the code to also verify double signing.

  • We cannot derive an infraction height from the evidence, so it is only possible to tombstone validators, not actually slash them. +To explain the technical reasons behind this limitation, let's recap the initial consumer initiated slashing logic. +In a nutshell, consumer heights are mapped to provider heights through VSCPackets, namely through the so called vscIDs. +When an infraction occurs on the consumer, a SlashPacket containing the vscID obtained from mapping the consumer infraction height +is sent to the provider. Upon receiving the packet, the provider maps the consumer infraction height to a local infraction height, +which is used to slash the misbehaving validator. In the context of untrusted consumer chains, all their states, including vscIDs, +could be corrupted and therefore cannot be used for slashing purposes.

  • Currently, the endpoint can only handle "equivocation" light client attacks. This is because the "lunatic" attacks require the endpoint to possess the ability to dissociate which header is conflicted or trusted upon receiving a misbehavior message. Without this information, it's not possible to define the Byzantine validators from the conflicting headers (see comment).

Consequences

Positive

  • After this ADR is applied, it will be possible for the provider chain to tombstone validators who committed a light client attack.

Negative

  • N/A

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-005-cryptographic-equivocation-verification.html.html b/legacy/v3.2.0/adrs/adr-005-cryptographic-equivocation-verification.html.html new file mode 100644 index 0000000000..b9db464305 --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-005-cryptographic-equivocation-verification.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html b/legacy/v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html new file mode 100644 index 0000000000..44ac9d2102 --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html @@ -0,0 +1,51 @@ + + + + + +ADR Template | Interchain Security + + + + +
+
Version: v3.2.0

ADR 007: Pause validator unbonding during equivocation proposal

Changelog

  • 2023-05-16: Initial Draft

Status

Proposed

Context

Currently, if an equivocation slashing proposal is created after more than one +week has passed since the equivocation, it is possible that the validator in +question could unbond and get away without being slashed, since the unbonding +period is 3 weeks, and the voting period is 2 weeks. For this reason, it might +be good to pause unbondings for validators named in an equivocation slashing +proposal until the proposal's voting period is over.

Decision

How

Pausing the unbonding period is already possible thanks to the changes in the +staking module of the cosmos-sdk:

  • stakingKeeper.PutUnbondingOnHold pauses an unbonding period
  • stakingKeeper.UnbondingCanComplete unpauses an unbonding period

These methods use a reference counter under the hood, that gets incremented +every time PutUnbondingOnHold is called, and decreased when +UnbondingCanComplete is called instead. A specific unbonding is considered +fully unpaused when its underlying reference counter reaches 0. Therefore, as +long as we safeguard consistency - i.e. we make sure we eventually decrement +the reference counter for each time we have incremented it - we can safely use +this existing mechanism without conflicts with the Completion of Unbonding +Operations system.

When pause

The unbonding period (if there is any unbonding) should be paused once an +equivocation proposal enters the voting period. For that, the gov module's +hook AfterProposalDeposit can be used.

If the hook is triggered with a an equivocation proposal in voting period, then +for each equivocation of the proposal, the unbonding operations of the related +validator that were initiated after the equivocation block time must be paused

  • i.e. the underlying reference counter has to be increased.

Note that even after the voting period has started, a proposal can receive +additional deposits. The hook is triggered however at arrival of a deposit, so +a check to verify that the proposal is not already in voting period is +required.

When unpause

We can use a gov module's hook also here and it is +AfterProposalVotingPeriodEnded.

If the hook is triggered with an equivocation proposal, then for each +associated equivocation, the unbonding operations of the related validator that +were initiated between the equivocation block time and the start of the +proposal voting period must be unpaused - i.e. decrease the underlying +reference counter - regardless of the proposal outcome.

Consequences

Positive

  • Validators subject to an equivocation proposal cannot finish unbonding +their tokens before the end of the voting period.

Negative

  • A malicious consumer chain could forge slash packets enabling submission of +an equivocation proposal on the provider chain, resulting in the freezing of +validator's unbondings for an undeterminated amount of time.
  • Misbehavior on a consumer chain can potentially go unpunished, if no one +submits an equivocation proposal in time, or if the proposal doesn't pass.

Neutral

  • This feature can't be used for social slashing, because an equivocation +proposal is only accepted if there's a slash log for the related +validator(s), meaning the consumer chain has reported the equivocation to +the provider chain.

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html b/legacy/v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html new file mode 100644 index 0000000000..88495b380d --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-008-throttle-retries.html b/legacy/v3.2.0/adrs/adr-008-throttle-retries.html new file mode 100644 index 0000000000..84b9f3d9ad --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-008-throttle-retries.html @@ -0,0 +1,19 @@ + + + + + +Throttle with retries | Interchain Security + + + + +
+
Version: v3.2.0

Throttle with retries

ADR 008: Throttle with retries

Changelog

  • 6/9/23: Initial draft
  • 6/22/23: added note on consumer pending packets storage optimization
  • 7/14/23: Added note on upgrade order

Status

Accepted

Context

For context on why the throttling mechanism exists, see ADR 002.

Note the terms slash throttling and jail throttling are synonymous, since in replicated security a SlashPacket simply jails a validator for downtime infractions.

Currently the throttling mechanism is designed so that provider logic (slash meter, etc.) dictates how many slash packets can be handled over time. Throttled slash packets are persisted on the provider, leading to multiple possible issues. Namely:

  • If slash or vsc matured packets are actually throttled/queued on the provider, state can grow and potentially lead to a DoS attack. We have short term solutions around this, but overall they come with their own weaknesses. See #594.
  • If a jailing attack described in ADR 002 were actually to be carried out with the current throttling design, we'd likely have to halt the provider, and perform an emergency upgrade and/or migration to clear the queues of slash packets that were deemed to be malicious. Alternatively, validators would just have to tough it out and wait for the queues to clear, during which all/most validators would be jailed. Right after being jailed, vals would have to unjail themselves promptly to ensure safety. The synchronous coordination required to maintain safety in such a scenario is not ideal.

So what's the solution? We can improve the throttling mechanism to instead queue/persist relevant data on each consumer, and have consumers retry slash requests as needed.

Decision

Consumer changes

Note the consumer already queues up both slash and vsc matured packets via AppendPendingPacket. Those packets are dequeued every endblock in SendPackets and sent to the provider.

Instead, we will now introduce the following logic on endblock:

  • Slash packets will always be sent to the provider once they're at the head of the queue. However, once sent, the consumer will not send any trailing vsc matured packets from the queue until the provider responds with an ack that the slash packet has been handled (ie. val was jailed). That is, slash packets block the sending of trailing vsc matured packets in the consumer queue.
  • If two slash packets are at the head of the queue, the consumer will send the first slash packet, and then wait for a success ack from the provider before sending the second slash packet. This seems like it'd simplify implementation.
  • VSC matured packets at the head of the queue (ie. NOT trailing a slash packet) can be sent immediately, and do not block any other packets in the queue, since the provider always handles them immediately.

To prevent the provider from having to keep track of what slash packets have been rejected, the consumer will have to retry the sending of slash packets over some period of time. This can be achieved with an on-chain consumer param. The suggested param value would probably be 1/2 of the provider's SlashMeterReplenishmentPeriod, although it doesn't matter too much as long as the param value is sane.

Note to prevent weird edge case behavior, a retry would not be attempted until either a success ack or failure ack has been recv from the provider.

With the behavior described, we maintain very similar behavior to the current throttling mechanism regarding the timing that slash and vsc matured packets are handled on the provider. Obviously the queueing and blocking logic is moved, and the two chains would have to send more messages between one another (only in the case the throttling mechanism is triggered).

In the normal case, when no or a few slash packets are being sent, the VSCMaturedPackets will not be delayed, and hence unbonding will not be delayed.

For implementation of this design, see throttle_retry.go.

Consumer pending packets storage optimization

In addition to the mentioned consumer changes above. An optimization will need to be made to the consumer's pending packets storage to properly implement the feature from this ADR.

The consumer ccv module previously queued "pending packets" to be sent on each endblocker in SendPackets. These packets are queued in state with a protobuf list of ConsumerPacketData. For a single append operation, the entire list is deserialized, then a packet is appended to that list, and the list is serialized again. See older version of AppendPendingPacket. That is, a single append operation has O(N) complexity, where N is the size of the list.

This poor append performance isn't a problem when the pending packets list is small. But with this ADR being implemented, the pending packets list could potentially grow to the order of thousands of entries, in the scenario that a slash packet is bouncing.

We can improve the append time for this queue by converting it from a protobuf-esq list, to a queue implemented with sdk-esq code. The idea is to persist an uint64 index that will be incremented each time you queue up a packet. You can think of this as storing the tail of the queue. Then, packet data will be keyed by that index, making the data naturally ordered byte-wise for sdk's iterator. The index will also be stored in the packet data value bytes, so that the index can later be used to delete certain packets from the queue.

Two things are achieved with this approach:

  • More efficient packet append/enqueue times
  • The ability to delete select packets from the queue (previously all packets were deleted at once)

Provider changes

The main change needed for the provider is the removal of queuing logic for slash and vsc matured packets upon being received.

Instead, the provider will consult the slash meter to determine if a slash packet can be handled immediately. If not, the provider will return an ack message to the consumer communicating that the slash packet could not be handled, and needs to be sent again in the future (retried).

VSCMatured packets will always be handled immediately upon being received by the provider.

Note spec. Specifically the section on VSC Maturity and Slashing Order. Previously the onus was on the provider to maintain this property via queuing packets and handling them FIFO.

Now this property will be maintained by the consumer sending packets in the correct order, and blocking the sending of VSCMatured packets as needed. Then, the ordered IBC channel will ensure that Slash/VSCMatured packets are received in the correct order on the provider.

The provider's main responsibility regarding throttling will now be to determine if a recv slash packet can be handled via slash meter etc., and appropriately ack to the sending consumer.

Why the provider can handle VSCMatured packets immediately

First we answer, what does a VSCMatured packet communicate to the provider? A VSCMatured packet communicates that a VSC has been applied to a consumer long enough that infractions committed on the consumer could have been submitted.

If the consumer is following the queuing/blocking protocol described. No bad behavior occurs, VSC Maturity and Slashing Order property is maintained.

If a consumer sends VSCMatured packets too leniently: The consumer is malicious and sending duplicate vsc matured packets, or sending the packets sooner than the ccv protocol specifies. In this scenario, the provider needs to handle vsc matured packets immediately to prevent DOS, state bloat, or other issues. The only possible negative outcome is that the malicious consumer may not be able to jail a validator who should have been jailed. The malicious behavior only creates a negative outcome for the chain that is being malicious.

If a consumer blocks the sending of VSCMatured packets: The consumer is malicious and blocking vsc matured packets that should have been sent. This will block unbonding only up until the VSC timeout period has elapsed. At that time, the consumer is removed. Again the malicious behavior only creates a negative outcome for the chain that is being malicious.

Splitting of PRs and Upgrade Order

This feature will implement consumer changes in #1024. Note these changes should be deployed to prod for all consumers before the provider changes are deployed to prod. That is the consumer changes in #1024 are compatible with the current ("v1") provider implementation of throttling that's running on the Cosmos Hub as of July 2023.

Once all consumers have deployed the changes in #1024, the provider changes from (TBD) can be deployed to prod, fully enabling v2 throttling.

Consequences

  • Consumers will now have to manage their own queues, and retry logic.
  • Consumers still aren't trustless, but the provider is now less susceptible to mismanaged or malicious consumers.
  • Recovering from the "jailing attack" is more elegant.
  • Some issues like #1001 will now be handled implicitly by the improved throttling mechanism.
  • Slash and vsc matured packets can be handled immediately once recv by the provider if the slash meter allows.
  • In general, we reduce the amount of computation that happens in the provider end-blocker.

Positive

  • We no longer have to reason about a "global queue" and a "chain specific queue", and keeping those all in-sync. Now slash and vsc matured packet queuing is handled on each consumer individually.
  • Due to the above, the throttling protocol becomes less complex overall.
  • We no longer have to worry about throttle related DoS attack on the provider, since no queuing exists on the provider.

Negative

  • Increased number of IBC packets being relayed anytime throttling logic is triggered.
  • Consumer complexity increases, since consumers now have manage queuing themselves, and implement packet retry logic.

Neutral

  • Core throttling logic on the provider remains unchanged, ie. slash meter, replenishment cycles, etc.

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-008-throttle-retries.html.html b/legacy/v3.2.0/adrs/adr-008-throttle-retries.html.html new file mode 100644 index 0000000000..f7d888f1d0 --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-008-throttle-retries.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-009-soft-opt-out.html b/legacy/v3.2.0/adrs/adr-009-soft-opt-out.html new file mode 100644 index 0000000000..e53dfda7dd --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-009-soft-opt-out.html @@ -0,0 +1,19 @@ + + + + + +Soft Opt-Out | Interchain Security + + + + +
+
Version: v3.2.0

Soft Opt-Out

ADR 009: Soft Opt-Out

Changelog

  • 6/13/23: Initial draft of ADR. Feature already implemented and in production.

Status

Accepted

Context

Some small validators may not have the resources needed to validate all consumer chains. Therefore a need exists to allow the bottom x% of validators to opt-out of validating a consumer chain. Meaning downtime infractions for these validators are dropped without ever reaching the provider.

This document specifies a modification to the ccv protocol which allows the bottom x% of the validator set by power to opt out of validating consumer chains without being jailed or otherwise punished for it. The feature is implemented with entirely consumer-side code.

Decision

A consumer param exists, known as SoftOptOutThreshold, which is a string decimal in the range of [0, 0.2], that determines the portion of validators which are allowed to opt out of validating that specific consumer.

In every consumer beginblocker, a function is ran which determines the so called smallest non opt-out voting power. Validators with voting power greater than or equal to this value must validate the consumer chain, while validators below this value may opt out of validating the consumer chain.

The smallest non opt-out voting power is recomputed every beginblocker in UpdateSmallestNonOptOutPower(). In a nutshell, the method obtains the total voting power of the consumer, iterates through the full valset (ordered power ascending) keeping track of a power sum, and when powerSum / totalPower > SoftOptOutThreshold, the SmallestNonOptOutPower is found and persisted.

Then, whenever the Slash() interface is executed on the consumer, if the voting power of the relevant validator being slashed is less than SmallestNonOptOutPower for that block, the slash request is dropped and never sent to the provider.

Consequences

Positive

  • Small validators can opt out of validating specific consumers without being punished for it.

Negative

  • The bottom x% is still part of the total voting power of the consumer chain. This means that if the soft opt-out threshold is set to 10% for example, and every validator in the bottom 10% opts out from validating the consumer, then a 24% downtime of the remaining voting power would halt the chain. This may be especially problematic during consumer upgrades.
  • In nominal scenarios, consumers with soft opt out enabled will be constructing slash packets for small vals, which may be dropped. This is wasted computation, but necessary to keep implementation simple. Note that the sdk's full downtime logic is always executed on the consumer, which can be computationally expensive and slow down certain blocks.

Neutral

  • Validators in the bottom of the valset who don't have to validate, may receive large delegation(s) which suddenly boost the validator to the subset that has to validate. This may catch the validator off guard.

References

  • Original issue with some napkin math #784
+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-009-soft-opt-out.html.html b/legacy/v3.2.0/adrs/adr-009-soft-opt-out.html.html new file mode 100644 index 0000000000..bdbb2cc4ac --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-009-soft-opt-out.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-010-standalone-changeover.html b/legacy/v3.2.0/adrs/adr-010-standalone-changeover.html new file mode 100644 index 0000000000..b57e216fa7 --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-010-standalone-changeover.html @@ -0,0 +1,19 @@ + + + + + +Standalone to Consumer Changeover | Interchain Security + + + + +
+
Version: v3.2.0

Standalone to Consumer Changeover

ADR 010: Standalone to Consumer Changeover

Changelog

  • 6/30/23: Feature completed, first draft of ADR.

Status

Implemented

Context

Stride will be the first consumer to "changeover" from a standalone cosmos blockchain, to a consumer chain secured by the Cosmos Hub. This document will outline the changes made to the replicated security protocol to support this changeover process.

Decision

Process

Prior to the changeover, the consumer chain will have an existing staking keeper and validator set, these may be referred to as the "standalone staking keeper" and "standalone validator set" respectively.

The first step in the changeover process is to submit a ConsumerAdditionProposal. If the proposal passes, the provider will create a new IBC client for the consumer at spawn time, with the provider's validator set. A consumer genesis will also be constructed by the provider for validators to query. Within this consumer genesis contains the initial validator set for the consumer to apply after the changeover.

Next, the standalone consumer chain runs an upgrade which adds the CCV module, and is properly setup to execute changeover logic.

The consumer upgrade height must be reached after the provider has created the new IBC client. Any replicated security validators who will run the consumer, but are not a part of the sovereign validator set, must sync up a full node before the consumer upgrade height is reached. The disc state of said full node will be used to run the consumer chain after the changeover has completed.

The meat of the changeover logic is that the consumer chain validator set is updated to that which was specified by the provider via the queried consumer genesis. Validators which were a part of the old set, but not the new set, are given zero voting power. Once these validator updates are given to Comet, the set is committed, and in effect 2 blocks later (see FirstConsumerHeight).

A relayer then establishes the new IBC connection between the provider and consumer. The CCV channel handshake is started on top of this connection. Once the CCV channel is established and VSC packets are being relayed, the consumer chain is secured by the provider.

Changes to CCV Protocol

  • Consumer Genesis state is updated to include a PreCCV boolean. When this boolean is set true in the consumer genesis JSON, special logic is executed on InitGenesis to trigger the changeover process on the consumer's first endblocker after the upgrade which adds the CCV module. Note that InitGenesis is not automatically called during chain upgrades, so the consumer must manually call the consumer's InitGenesis method in an upgrade handler.
  • The ConsumerAdditionProposal type is updated to include a DistributionTransmissionChannel field. This field allows the consumer to use an existing IBC transfer channel to send rewards as a part of the CCV protocol. Consumers that're not changing over from a standalone chain will leave this field blank, indicating that a new transfer channel should be created on top of the same connection as the CCV channel.
  • The CCV consumer keeper is updated to contain an optional reference to the standalone staking keeper. The standalone staking keeper is used to slash for infractions that happened before the changeover was completed. Ie. any infraction from a block height before the changeover, that is submitted after the changeover, will call the standalone staking keeper's slash method. Note that a changeover consumer's standalone staking keeper becomes a democracy module keeper, so it is possible for a governance token to be slashed.

Consequences

Positive

  • Existing cosmos chains are now able to onboard over to a consumer chain secured by a provider.
  • The previous staking keepers for such chains can be transitioned to democracy staking module keepers.

Negative

  • The delineation between different types of consumers in this repo becomes less clear. Ie. there is code in the democracy consumer's app.go that only applies to a previously standalone chain, but that file also serves as the base for a normal democracy consumer launched with RS from genesis.

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-010-standalone-changeover.html.html b/legacy/v3.2.0/adrs/adr-010-standalone-changeover.html.html new file mode 100644 index 0000000000..e47adb6042 --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-010-standalone-changeover.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-011-improving-test-confidence.html b/legacy/v3.2.0/adrs/adr-011-improving-test-confidence.html new file mode 100644 index 0000000000..edde93e105 --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-011-improving-test-confidence.html @@ -0,0 +1,29 @@ + + + + + +Improving testing and increasing confidence | Interchain Security + + + + +
+
Version: v3.2.0

ADR 11: Improving testing and increasing confidence

Changelog

  • 2023-08-11: Proposed, first draft of ADR.

Status

Proposed

Context

Testing, QA, and maintenance of interchain-security libraries is an ever-evolving area of software engineering we have to keep incrementally improving. The purpose of the QA process is to catch bugs as early as possible. In an ideal development workflow a bug should never reach production. A bug found in the specification stage is a lot cheaper to resolve than a bug discovered in production (or even in testnet). Ideally, all bugs should be found during the CI execution, and we hope that no bugs will ever even reach the testnet (although nothing can replace actual system stress test under load interacting with users).

During development and testnet operation the following types of bugs were the most commonly found:

  • improper iterator usage
  • unbounded array access/iteration
  • improper input handling and validation
  • improper cached context usage
  • non-determinism check (improper use of maps in go, relying on random values)
  • KV store management and/or how keys are defined
  • deserialization issues arising from consumer/provider versioning mismatch

Such bugs can be discovered earlier with better tooling. Some of these bugs can induce increases in block times, chain halts, state corruption, or introduce an attack surface which is difficult to remove if other systems have started depending on that behavior.

Current state of testing

Our testing suites consist of multiple parts, each with their own trade-offs and benefits with regards to code coverage, complexity and confidence they provide.

Unit testing

Unit testing is employed mostly for testing single-module functionality. It is the first step in testing and often the most practical. While highly important, unit tests often test a single piece of code and don't test relationships between different moving parts, this makes them less valuable when dealing with multi-module interactions.

Unit tests often employ mocks to abstract parts of the system that are not under test. Mocks are not equivalent to actual models and should not be treated as such.

Out of all the approaches used, unit testing has the most tools available and the coverage can simply be displayed as % of code lines tested. Although this is a very nice and very easy to understand metric, it does not speak about the quality of the test coverage.

Since distributed systems testing is a lot more involved, unit tests are oftentimes not sufficient to cover complex interactions. Unit tests are still necessary and helpful, but in cases where unit tests are not helpful e2e or integration tests should be favored.

Integration testing

With integration testing we test the multi-module interactions while isolating them from the remainder of the system. +Integration tests can uncover bugs that are often missed by unit tests.

It is very difficult to gauge the actual test coverage imparted by integration tests and the available tooling is limited. +In interchain-security we employ the ibc-go/testing framework to test interactions in-memory.

At present, integration testing does not involve the consensus layer - it is only concerned with application level state and logic.

End-to-end testing

In our context end-to-end testing comprises of tests that use the actual application binaries in an isolated environment (e.g. docker container). During test execution the inputs are meant to simulate actual user interaction, either by submitting transactions/queries using the command line or using gRPC/REST APIs and checking for state changes after an action has been performed. With this testing strategy we also include the consensus layer in all of our runs. This is the closest we can get to testing user interactions without starting a full testnet.

End-to-end testing strategies vary between different teams and projects and we strive to unify our approach to the best of our ability (at least for ICS and gaia).

The available tooling does not give us significant (or relevant) line of code coverage information since most of the tools are geared towards analyzing unit tests and simple code branch evaluation.

We aim to adapt our best practices by learning from other similar systems and projects such as cosmos-sdk, ibc-go and CometBFT.

Decision

1. Connect specifications to code and tooling

Oftentimes, specifications are disconnected from the development and QA processes. This gives rise to problems where the specification does not reflect the actual state of the system and vice-versa. +Usually specifications are just text files that are rarely used and go unmaintained after a while, resulting in consistency issues and misleading instructions/expectations about system behavior.

Decision context and hypothesis

Specifications written in a dedicated and executable specification language are easier to maintain than the ones written entirely in text. +Additionally, we can create models based on the specification OR make the model equivalent to a specification.

Models do not care about the intricacies of implementation and neither do specifications. Since both models and specifications care about concisely and accurately describing a system (such as a finite state machine), we see a benefit of adding model based tools (such as quint) to our testing and development workflows.

Main benefit

MBT tooling can be used to generate test traces that can be executed by multiple different testing setups.

2. Improve e2e tooling

Matrix tests

Instead of only running tests against current main branch we should adopt an approach where we also:

  • run regression tests against different released software versions (ICS v1 vs v2 vs v3)
  • run non-determinism tests to uncover issues quickly

Matrix tests can be implemented using CometMock and refactoring our current e2e CI setup.

Introducing e2e regression testing

This e2e test suite would execute using a cronjob in our CI (nightly, multiple times a day etc.)

Briefly, the same set of traces is run against different maintained versions of the software and the main branch. +This would allow us to discover potential issues during development instead of in a testnet scenarios.

The most valuable issues that can be discovered in this way are state breaking changes, regressions and version incompatibilities.

The setup is illustrated by the image below. +e2e matrix tests

This table explains which versions are tested against each other for the same set of test traces:

  • ✅ marks a passing test
  • ❌ marks a failing test
USES: ICS v1 PROVIDERstart chainadd keydelegateundelegateredelegatedowntimeequivocationstop chain
v1 consumer (sdk45,ibc4.3)
v2 consumer (sdk45, ibc4.4)
v3 consumer (sdk47, ibc7)
main consumer
neutron
stride

Introducing e2e CometMock tests

CometMock is a mock implementation of the CometBFT consensus engine. It supports most operations performed by CometBFT while also being lightweight and relatively easy to use.

CometMock tests allow more nuanced control of test scenarios because CometMock can "fool" the blockchain app into thinking that a certain number of blocks had passed. +This allows us to test very nuanced scenarios, difficult edge cases and long-running operations (such as unbonding operations).

Examples of tests made easier with CometMock are listed below:

  • regression tests
  • non-determinism tests
  • upgrade tests
  • state-breaking changes

With CometMock, the matrix test approach can also be used. The image below illustrates a CometMock setup that can be used to discover non-deterministic behavior and state-breaking changes. +e2e matrix tests

This table explains which versions are tested against each other for the same set of test traces:

  • ✅ marks a passing test
  • ❌ marks a failing test
SCENARIOstart chainadd keydelegateundelegateredelegatedowntimeequivocationstop chain
v3 provi + v3 consu
main provi + main consu
commit provi + commit consu

Briefly; multiple versions of the application are run against the same CometMock instance and any deviations in app behavior would result in app hash errors (the apps would be in different states after performing the same set of actions).

3. Introduce innovative testing approaches

When discussing e2e testing, some very important patterns emerge - especially if test traces are used instead of ad-hoc tests written by hand.

We see a unique opportunity to clearly identify concerns and modularize the testing architecture.

The e2e testing frameworks can be split into a pipeline consisting of 3 parts: model, driver and harness.

Model

Model is the part of the system that can emulate the behavior of the system under test. +Ideally, it is very close to the specification and is written in a specification language such as quint, TLA+ or similar. +One of the purposes of the model is that it can be used to generate test traces.

Driver

The purpose of the driver is to accept test traces (generated by the model or written by hand), process them and provide inputs to the next part of the pipeline.

Basically, the driver sits between the model and the actual infrastructure on which the test traces are being executed on.

Harness

Harness is the infrastructure layer of the pipeline that accepts inputs from the driver.

There can be multiple harnesses as long as they can perform four things:

  • bootstrap a test execution environment (local, docker, k8s…)
  • accept inputs from drivers
  • perform the action specified by the driver
  • report results after performing actions

Consequences

The procedure outlined in this ADR is not an all-or-nothing approach. Concepts introduced here do not rely on each other, so this ADR may only be applied partially without negative impact on test coverage and code confidence.

Positive

  1. introduction of maintainable MBT solutions
  • improvement over the current "difftest" setup that relies on an opinionated typescript model and go driver
  1. increased code coverage and confidence
  • using CometMock allows us to run more tests in less time
  • adding matrix e2e tests allows us to quickly pinpoint differences between code versions

Negative

It might be easier to forgo the MBT tooling and instead focus on pure property based testing

The solutions are potentially expensive if we increase usage of the CI pipeline - this is fixed by running "expensive" tests using a cronjob, instead of running them on every commit.

Neutral

The process of changing development and testing process is not something that can be thought of and delivered quickly. Luckily, the changes can be rolled out incrementally without impacting existing workflows.

References

Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-011-improving-test-confidence.html.html b/legacy/v3.2.0/adrs/adr-011-improving-test-confidence.html.html new file mode 100644 index 0000000000..5c737b0e68 --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-011-improving-test-confidence.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-012-separate-releasing.html b/legacy/v3.2.0/adrs/adr-012-separate-releasing.html new file mode 100644 index 0000000000..7ced3f0843 --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-012-separate-releasing.html @@ -0,0 +1,19 @@ + + + + + +Separate Releasing | Interchain Security + + + + +
+
Version: v3.2.0

ADR 012: Separate Releasing

Changelog

  • {8/18/22}: Initial draft of idea in #801
  • {8/22/22}: Put idea in this ADR

Status

Accepted

Context

Spike results

I explored the idea of #801 with this spike branch. Here's my conclusions:

Splitting this repo to have multiple go.mods is possible. However there are various intricacies involved in decoupling the package hierarchy to have x/ccv/types as the lowest level dep, with x/ccv/consumer and x/ccv/provider being one dep layer above, with high-level tests depending on all three of the mentioned packages. I'd estimate this decoupling would take 2-5 workdays to finish, and require significant review effort.

Why go.mod split is not the way to go

Let's take a step back and remember the issue we're trying to solve - We need a clean way to decouple semver/releasing for the consumer and provider modules. After more consideration, splitting up go.mods gives us little benefit in achieving this. Reasons:

  • The go.mod dependency system is tied to git tags for the entire repo (ex: require github.com/cometbft/cometbft v0.37.2 refers to a historical tag for the entire cometbft repo).
  • It'd be an odd dev experience to allow modules to reference past releases of other modules in the same repo. When would we ever want the consumer module to reference a past release of the types module for example?
  • If we allow for go.mod replace statements to build from local source code, why split up the package deps at all?
  • Splitting go.mods adds a bunch of complexity with go.work files and all that shiz. VSCode does not play well with multiple module repos either.

Why separate repos is cool but also not the way to go

All this considered, the cleanest solution to decoupling semver/releasing for the consumer and provider modules would be to have multiple repos, each with their own go.mod (3-4 repos total including high level tests). With this scheme we could separately tag each repo as changes are merged, they could share some code from types being an external dep, etc.

I don't think any of us want to split up the monorepo, that's a lot of work and seems like bikeshedding. There's another solution that's very simple..

Decision

Slightly adapting the current semver ruleset:

  • A library API breaking change to EITHER the provider or consumer module will result in an increase of the MAJOR version number for BOTH modules (X.y.z-provider AND X.y.z-consumer).
  • A state breaking change (change requiring coordinated upgrade and/or state migration) will result in an increase of the MINOR version number for the AFFECTED module(s) (x.Y.z-provider AND/OR x.Y.z-consumer).
  • Any other changes (including node API breaking changes) will result in an increase of the PATCH version number for the AFFECTED module(s) (x.y.Z-provider AND/OR x.y.Z-consumer).

Example release flow

We upgrade main to use a new version of SDK. This is a major version bump, triggering a new release for both the provider and consumer modules, v5.0.0-provider and v5.0.0-consumer.

  • A state breaking change is merged to main for the provider module. We release only a v5.1.0-provider off main.
  • Another state breaking change is merged to main for the provider module. We release only a v5.2.0-provider off main.
  • At this point, the latest consumer version is still v5.0.0-consumer. We now merge a state breaking change for the consumer module to main, and consequently release v5.1.0-consumer. Note that v5.1.0-consumer is tagged off a LATER commit from main than v5.2.0-provider. This is fine, as the consumer module should not be affected by the provider module's state breaking changes.
  • Once either module sees a library API breaking change, we bump the major version for both modules. For example, we merge a library API breaking change to main for the provider module. We release v6.0.0-provider and v6.0.0-consumer off main. Note that most often, a library API breaking change will affect both modules simultaneously (example being bumping sdk version).

Consequences

Positive

  • Consumer repos have clear communication of what tagged versions are relevant to them. Consumer devs should know to never reference an ICS version that starts with provider, even if it'd technically build.
  • Consumer and provider modules do not deviate as long as we continually release off a shared main branch. Backporting remains relatively unchanged besides being explicit about what module(s) your changes should affect.
  • No code changes, just changes in process. Very simple.

Negative

  • Slightly more complexity.
  • This solution does not allow having provider and consumer on separate versions of e.g. the Cosmos SDK

Neutral

References

Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-012-separate-releasing.html.html b/legacy/v3.2.0/adrs/adr-012-separate-releasing.html.html new file mode 100644 index 0000000000..4ff2f2a6f5 --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-012-separate-releasing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-013-equivocation-slashing.html b/legacy/v3.2.0/adrs/adr-013-equivocation-slashing.html new file mode 100644 index 0000000000..c3d36c654a --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-013-equivocation-slashing.html @@ -0,0 +1,39 @@ + + + + + +Slashing on the provider for consumer equivocation | Interchain Security + + + + +
+
Version: v3.2.0

ADR 013: Slashing on the provider for consumer equivocation

Changelog

  • 1st Sept. 2023: Initial draft

Status

Proposed

Context

This ADR presents some approaches on how to slash on the provider chain validators that performed equivocations on consumer chains. +Currently, the provider chain can receive and verify evidence of equivocation, but it cannot slash the misbehaving validator.

In the remainder of this section, we explain how slashing is performed on a single chain and show why slashing on the provider for equivocation on the consumer is challenging.

Note that future versions of the Cosmos SDK, CometBFT, and ibc-go could modify the way we slash, etc. Therefore, a future reader of this ADR, should note that when we refer to Cosmos SDK, CometBFT, and ibc-go we specifically refer to their v0.47, v0.37 and v7.3.0 versions respectively.

Single-chain slashing

Slashing is implemented across the slashing +and staking modules. +The slashing module's keeper calls the staking module's Slash() method, passing among others, the infractionHeight (i.e., the height when the equivocation occurred), the validator's power at the infraction height, and the slashFactor (currently set to 5% in case of equivocation on the Cosmos Hub).

Slashing undelegations and redelegations

To slash undelegations, Slash goes through all undelegations and checks whether they started before or after the infraction occurred. If an undelegation started before the infractionHeight, then it is not slashed, otherwise it is slashed by slashFactor.

The slashing of redelegations happens in a similar way, meaning that Slash goes through all redelegations and checks whether the redelegations started before or after the infractionHeight.

Slashing delegations

Besides undelegations and redelegations, the validator's delegations need to also be slashed. +This is performed by deducting the appropriate amount of tokens from the validator. Note that this deduction is computed based on the voting power the misbehaving validator had at the height of the equivocation. As a result of the tokens deduction, +the tokens per share +reduce and hence later on, when delegators undelegate or redelegate, the delegators retrieve back less +tokens, effectively having their tokens slashed. The rationale behind this slashing mechanism, as mentioned in the Cosmos SDK documentation

[...] is to simplify the accounting around slashing. Rather than iteratively slashing the tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, effectively reducing the value of each issued delegator share.

This approach of slashing delegations does not utilize the +infractionHeight in any way and hence the following scenario could occur:

  1. a validator V performs an equivocation at a height Hi
  2. a new delegator D delegates to V after height Hi
  3. evidence of the equivocation by validator V is received
  4. the tokens of delegator D are slashed

In the above scenario, delegator D is slashed, even though D's voting power did not contribute to the infraction.

Old evidence

In the single-chain case, old evidence (e.g., from 3 years ago) is ignored. This is achieved through +CometBFT that ignores old evidence based on the parameters MaxAgeNumBlocks and MaxAgeDuration (see here). +Additionally, note that when the evidence is sent by CometBFT to the application, the evidence is rechecked in the evidence module of Cosmos SDK and if it is old, the evidence is ignored. +In Cosmos Hub, the MaxAgeNumBlocks is set to 1000000 (i.e., ~70 days if we assume we need ~6 sec per block) and MaxAgeDuration is set to 172800000000000 ns (i.e., 2 days). Because of this check, we can easily exclude old evidence.

Slashing for equivocation on the consumer

In the single-chain case, slashing requires both the infractionHeight and the voting power. +In order to slash on the provider for an equivocation on a consumer, we need to have both the provider's infractionHeight and voting power. +Note that the infractionHeight on the consumer chain must be mapped to a height on the provider chain. +Unless we have a way to find the corresponding infractionHeight and power on the provider chain, we cannot slash for equivocation on the consumer in the same way as we would slash in the single-chain case.

The challenge of figuring out the corresponding infractionHeight and power values on the provider chain is due to the following trust assumption:

  • We trust the consensus layer and validator set of the consumer chains, but we do not trust the application layer.

As a result, we cannot trust anything that stems from the application state of a consumer chain.

Note that when a relayer or a user sends evidence through a MsgSubmitConsumerDoubleVoting message, the provider gets access to DuplicateVoteEvidence:

type DuplicateVoteEvidence struct {
VoteA *Vote `json:"vote_a"`
VoteB *Vote `json:"vote_b"`

// abci specific information
TotalVotingPower int64
ValidatorPower int64
Timestamp time.Time
}

The "abci specific information" fields cannot be trusted because they are not signed. Therefore, +we can use neither ValidatorPower for slashing on the provider chain, nor the Timestamp to check the evidence age. We can get the infractionHeight from the votes, but this infractionHeight corresponds to the infraction height on the consumer and not on the provider chain. +Similarly, when a relayer or a user sends evidence through a MsgSubmitConsumerMisbehaviour message, the provider gets access to Misbehaviour that we cannot use to extract the infraction height, power, or the time on the provider chain.

Proposed solution

As a first iteration, we propose the following approach. At the moment the provider receives evidence of equivocation on a consumer:

  1. slash all the undelegations and redelegations using slashFactor;
  2. slash all delegations using as voting power the sum of the voting power of the misbehaving validator and the power of all the ongoing undelegations and redelegations.

Evidence expiration: Additionally, because we cannot infer the actual time of the evidence (i.e., the timestamp of the evidence cannot be trusted), we do not consider evidence expiration and hence old evidence is never ignored (e.g., the provider would act on 3 year-old evidence of equivocation on a consumer). +Additionally, we do not need to store equivocation evidence to avoid slashing a validator more than once, because we do not slash tombstoned validators and we tombstone a validator when slashed.

We do not act on evidence that was signed by a validator consensus key that is pruned when we receive the evidence. We prune a validator's consensus key if the validator has assigned a new consumer key (using MsgAssignConsumerKey) and an unbonding period on the consumer chain has elapsed (see key assignment ADR). Note that the provider chain is informed that the unbonding period has elapsed on the consumer when the provider receives a VSCMaturedPacket and because of this, if the consumer delays the sending of a VSCMaturedPacket, we would delay the pruning of the key as well.

Implementation

The following logic needs to be added to the HandleConsumerDoubleVoting and HandleConsumerMisbehaviour methods:

undelegationsInTokens := sdk.NewInt(0)
for _, v := range k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validatorAddress) {
for _, entry := range v.Entries {
if entry.IsMature(now) && !entry.OnHold() {
// undelegation no longer eligible for slashing, skip it
continue
}
undelegationsInTokens = undelegationsInTokens.Add(entry.InitialBalance)
}
}

redelegationsInTokens := sdk.NewInt(0)
for _, v := range k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validatorAddress) {
for _, entry := range v.Entries {
if entry.IsMature(now) && !entry.OnHold() {
// redelegation no longer eligible for slashing, skip it
continue
}
redelegationsInTokens = redelegationsInTokens.Add(entry.InitialBalance)
}
}

infractionHeight := 0
undelegationsAndRedelegationsInPower = sdk.TokensToConsensusPower(undelegationsInTokens.Add(redelegationsInTokens))
totalPower := validator's voting power + undelegationsAndRedelegationsInPower
slashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)

k.stakingKeeper.Slash(ctx, validatorConsAddress, infractionHeight, totalPower, slashFraction, DoubleSign)

Infraction height: We provide a zero infractionHeight to the Slash method in order to slash all ongoing undelegations and redelegations (see checks in Slash, SlashUnbondingDelegation, and SlashRedelegation).

Power: We pass the sum of the voting power of the misbehaving validator when the evidence was received (i.e., at evidence height) and the power of all the ongoing undelegations and redelegations. +If we assume that the slashFactor is 5%, then the voting power we pass is power + totalPower(undelegations) + totalPower(redelegations). +Hence, when the Slash method slashes all the undelegations and redelegations it would end up with 0.05 * power + 0.05 * totalPower(undelegations) + 0.05 * totalPower(redelegations) - 0.05 * totalPower(undelegations) - 0.05 * totalPower(redelegations) = 0.05 * power and hence it would slash 5% of the validator's power when the evidence is received.

Positive

With the proposed approach we can quickly implement slashing functionality on the provider chain for consumer chain equivocations. +This approach does not need to change the staking module and therefore does not change in any way how slashing is performed today for a single chain.

Negative

  • We definitely slash more when it comes to undelegations and redelegations because we slash for all of them without considering an infractionHeight.
  • We potentially slash more than what we would have slashed if we knew the voting power at the corresponding infractionHeight in the provider chain.
  • We slash on old evidence of equivocation on a consumer.

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-013-equivocation-slashing.html.html b/legacy/v3.2.0/adrs/adr-013-equivocation-slashing.html.html new file mode 100644 index 0000000000..66e1fe65c7 --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-013-equivocation-slashing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-template.html b/legacy/v3.2.0/adrs/adr-template.html new file mode 100644 index 0000000000..dfbeb92cd3 --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-template.html @@ -0,0 +1,22 @@ + + + + + +ADR Template | Interchain Security + + + + +
+
Version: v3.2.0

ADR {ADR-NUMBER}: {TITLE}

Changelog

  • {date}: {changelog}

Status

A decision may be "proposed" if it hasn't been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement.

{Deprecated|Proposed|Accepted}

Context

This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution.

Decision

This section explains all of the details of the proposed solution, including implementation details. +It should also describe affects / corollary items that may need to be changed as a part of this. +If the proposed change will be large, please also indicate a way to do the change to maximize ease of review. +(e.g. the optimal split of things to do between separate PR's)

Consequences

This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones.

Positive

Negative

Neutral

References

Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!

  • {reference link}
+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/adr-template.html.html b/legacy/v3.2.0/adrs/adr-template.html.html new file mode 100644 index 0000000000..03b943d529 --- /dev/null +++ b/legacy/v3.2.0/adrs/adr-template.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/intro.html b/legacy/v3.2.0/adrs/intro.html new file mode 100644 index 0000000000..19411e2736 --- /dev/null +++ b/legacy/v3.2.0/adrs/intro.html @@ -0,0 +1,22 @@ + + + + + +ADRs | Interchain Security + + + + +
+
Version: v3.2.0

Architecture Decision Records (ADR)

This is a location to record all high-level architecture decisions in the Interchain Security project.

You can read more about the ADR concept in this blog post.

An ADR should provide:

  • Context on the relevant goals and the current state
  • Proposed changes to achieve the goals
  • Summary of pros and cons
  • References
  • Changelog

Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and +justification for a change in architecture, or for the architecture of something +new. The spec is much more compressed and streamlined summary of everything as +it is or should be.

If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match.

Note the context/background should be written in the present tense.

To suggest an ADR, please make use of the ADR template provided.

Table of Contents

ADR #DescriptionStatus
001Consumer chain key assignmentAccepted, Implemented
002Jail ThrottlingAccepted, Implemented
003Equivocation governance proposalAccepted, Implemented
004Denom DOS fixesAccepted, Implemented
005Cryptographic verification of equivocation evidenceAccepted, In-progress
007Pause validator unbonding during equivocation proposalProposed
008Throttle with retriesAccepted, In-progress
009Soft Opt-outAccepted, Implemented
010Standalone to Consumer ChangeoverAccepted, Implemented
011Improving testing and increasing confidenceProposed
012Separate ReleasingProposed
013Slashing on the provider for consumer equivocationProposed
+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/adrs/intro.html.html b/legacy/v3.2.0/adrs/intro.html.html new file mode 100644 index 0000000000..2bed7fc1fb --- /dev/null +++ b/legacy/v3.2.0/adrs/intro.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/consumer-development/app-integration.html b/legacy/v3.2.0/consumer-development/app-integration.html new file mode 100644 index 0000000000..4274dd5082 --- /dev/null +++ b/legacy/v3.2.0/consumer-development/app-integration.html @@ -0,0 +1,23 @@ + + + + + +Developing an ICS consumer chain | Interchain Security + + + + +
+
Version: v3.2.0

Developing an ICS consumer chain

When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol. +To help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications.

Basic consumer chain

The source code for the example app can be found here.

Please note that consumer chains do not implement the staking module - the validator set is replicated from the provider, meaning that the provider and the consumer use the same validator set and their stake on the provider directly determines their stake on the consumer. +At present there is no opt-in mechanism available, so all validators of the provider must also validate on the provider chain.

Your chain should import the consumer module from x/consumer and register it in the correct places in your app.go. +The x/consumer module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in. +You should not need to manage or override any code from the x/consumer module.

Democracy consumer chain

The source code for the example app can be found here.

This type of consumer chain wraps the basic CosmosSDK x/distribution, x/staking and x/governance modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system.

This allows the consumer chain to leverage those modules while also using the x/consumer module.

With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.

Standalone chain to consumer chain changeover

This feature is being actively worked on. Information will be provided at a later time.

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/consumer-development/app-integration.html.html b/legacy/v3.2.0/consumer-development/app-integration.html.html new file mode 100644 index 0000000000..ea0cbe15dd --- /dev/null +++ b/legacy/v3.2.0/consumer-development/app-integration.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/consumer-development/changeover-procedure.html b/legacy/v3.2.0/consumer-development/changeover-procedure.html new file mode 100644 index 0000000000..04cba50d46 --- /dev/null +++ b/legacy/v3.2.0/consumer-development/changeover-procedure.html @@ -0,0 +1,19 @@ + + + + + +Changeover Procedure | Interchain Security + + + + +
+
Version: v3.2.0

Changeover Procedure

Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.

The relevant protocol specifications are available below:

Overview

Standalone to consumer changeover procedure can rougly be separated into 4 parts:

1. ConsumerAddition proposal submitted to the provider chain

The proposal is equivalent to the "normal" ConsumerAddition proposal submitted by new consumer chains.

However, here are the most important notes and differences between a new consumer chain and a standalone chain performing a changeover:

  • chain_id must be equal to the standalone chain id
  • initial_height field has additional rules to abide by:
caution
{
...
"initial_height" : {
// must correspond to current revision number of standalone chain
// e.g. stride-1 => "revision_number": 1
"revision_number": 1,

// must correspond to a height that is at least 1 block after the upgrade
// that will add the `consumer` module to the standalone chain
// e.g. "upgrade_height": 100 => "revision_height": 101
"revision_height": 1,
},
...
}

RevisionNumber: 0, RevisionHeight: 111

  • genesis_hash can be safely ignored because the chain is already running. A hash of the standalone chain's initial genesis may be used

  • binary_hash may not be available ahead of time. All chains performing the changeover go through rigorous testing - if bugs are caught and fixed the hash listed in the proposal may not be the most recent one.

  • spawn_time listed in the proposal MUST be before the upgrade_height listed in the the upgrade proposal on the standalone chain.

    caution

    spawn_time must occur before the upgrade_height on the standalone chain is reached becasue the provider chain must generate the ConsumerGenesis that contains the validator set that will be used after the changeover.

  • unbonding_period must correspond to the value used on the standalone chain. Otherwise, the clients used for the ccv protocol may be incorrectly initialized.

  • distribution_transmission_channel should be set.

note

Populating distribution_transmission_channel will enable the standalone chain to re-use one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ibc denom that may already be in use.

If the parameter is not set, a new channel will be created.

  • ccv_timeout_period has no important notes

  • transfer_timeout_period has no important notes

  • consumer_redistribution_fraction has no important notes

  • blocks_per_distribution_transmission has no important notes

  • historical_entries has no important notes

2. upgrade proposal on standalone chain

The standalone chain creates an upgrade proposal to include the interchain-security/x/ccv/consumer module.

caution

The upgrade height in the proposal should correspond to a height that is after the spawn_time in the consumer addition proposal submitted to the provider chain.

Otherwise, the upgrade is indistinguishable from a regular on-chain upgrade proposal.

3. spawn time is reached

When the spawn_time is reached on the provider it will generate a ConsumerGenesis that contains the validator set that will supercede the standalone validator set.

This ConsumerGenesis must be available on the standalone chain during the on-chain upgrade.

4. standalone chain upgrade

Performing the on-chain upgrade on the standalone chain will add the ccv/consumer module and allow the chain to become a consumer of replicated security.

caution

The ConsumerGenesis must be exported to a file and placed in the correct folder on the standalone chain before the upgade.

The file must be placed at the exact specified location, otherwise the upgrade will not be executed correctly.

Usually the file is placed in $NODE_HOME/config, but the file name and the exact directory is dictated by the upgrade code on the standalone chain.

  • please check exact instructions provided by the standalone chain team

After the genesis.json file has been made available, the process is equivalent to a normal on-chain upgrade. The standalone validator set will sign the next couple of blocks before transferring control to provider validator set.

The standalone validator set can still be slashed for any infractions if evidence is submitted within the unboding_period.

Notes

The changeover procedure may be updated in the future to create a seamless way of providing the validator set information to the standalone chain.

Onboarding Checklist

This onboarding checklist is slightly different from the one under Onboarding

Additionally, you can check the testnet repo for a comprehensive guide on preparing and launching consumer chains.

1. Complete testing & integration

  • test integration with gaia
  • test your protocol with supported relayer versions (minimum hermes 1.4.1)
  • test the changeover procedure
  • reach out to the ICS team if you are facing issues

2. Create an Onboarding Repository

To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain.

This should include (at minimum):

  • genesis.json with CCV data (after spawn time passes)
  • information about relevant seed/peer nodes you are running
  • relayer information (compatible versions)
  • copy of your governance proposal (as JSON)
  • a script showing how to start your chain and connect to peers (optional)
  • take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable

Example of such a repository can be found here.

3. Submit a ConsumerChainAddition Governance Proposal to the provider

Before you submit a ConsumerChainAddition proposal, please provide a spawn_time that is before the the upgrade_height of the upgrade that will introduce the ccv module to your chain.

danger

If the spawn_time happens after your upgrade_height the provider will not be able to communicate the new validator set to be used after the changeover.

Additionally, reach out to the community via the forum to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers.

  • determine your chain's spawn time
  • determine consumer chain parameters to be put in the proposal
  • take note to include a link to your onboarding repository

Example of a consumer chain addition proposal.

// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain or add a standalone chain.
// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.
// It is recommended that spawn time occurs after the proposal end time and that it is scheduled to happen before the standalone chain upgrade
// that sill introduce the ccv module.
{
// Title of the proposal
"title": "Changeover Standalone chain",
// Description of the proposal
// format the text as a .md file and include the file in your onboarding repository
"description": ".md description of your chain and all other relevant information",
// Proposed chain-id of the new consumer chain.
// Must be unique from all other consumer chain ids of the executing provider chain.
"chain_id": "standalone-1",
// Initial height of new consumer chain.
// For a completely new chain, this will be {0,1}.
"initial_height" : {
// must correspond to current revision number of standalone chain
// e.g. standalone-1 => "revision_number": 1
"revision_number": 1,

// must correspond to a height that is at least 1 block after the upgrade
// that will add the `consumer` module to the standalone chain
// e.g. "upgrade_height": 100 => "revision_height": 101
"revision_number": 1,
},
// Hash of the consumer chain genesis state without the consumer CCV module genesis params.
// => not relevant for changeover procedure
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
// Hash of the consumer chain binary that should be run by validators on standalone chain upgrade
// => not relevant for changeover procedure as it may become stale
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
// Unbonding period for the consumer chain.
// It should should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
// IBC transfer packets will timeout after this interval elapses.
"transfer_timeout_period": 1800000000000,
// The fraction of tokens allocated to the consumer redistribution address during distribution events.
// The fraction is a string representing a decimal number. For example "0.75" would represent 75%.
// The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.
"consumer_redistribution_fraction": "0.75",
// BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.
// eg. send rewards to the provider every 1000 blocks
"blocks_per_distribution_transmission": 1000,
// The number of historical info entries to persist in store.
// This param is a part of the cosmos sdk staking module. In the case of
// a ccv enabled consumer chain, the ccv module acts as the staking module.
"historical_entries": 10000,
// The ID of a token transfer channel used for the Reward Distribution
// sub-protocol. If DistributionTransmissionChannel == "", a new transfer
// channel is created on top of the same connection as the CCV channel.
// Note that transfer_channel_id is the ID of the channel end on the consumer chain.
// it is most relevant for chains performing a standalone to consumer changeover
// in order to maintan the existing ibc transfer channel
"distribution_transmission_channel": "channel-123" // NOTE: use existing transfer channel if available
}

3. Submit an Upgrade Proposal & Prepare for Changeover

This proposal should add the ccv consumer module to your chain.

  • proposal upgrade_height must happen after spawn_time in the ConsumerAdditionProposal
  • advise validators about the exact procedure for your chain and point them to your onboarding repository

4. Upgrade time 🚀

  • after spawn_time, request ConsumerGenesis from the provider and place it in <CURRENT_USER_HOME_DIR>/.sovereign/config/genesis.json
  • upgrade the binary to the one listed in your UpgradeProposal

The chain starts after at least 66.67% of standalone voting power comes online. The consumer chain is considered interchain secured once the "old" validator set signs a couple of blocks and transfers control to the provider validator set.

  • provide a repo with onboarding instructions for validators (it should already be listed in the proposal)
  • genesis.json after spawn_time obtained from provider (MUST contain the initial validator set)
  • maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)
+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/consumer-development/changeover-procedure.html.html b/legacy/v3.2.0/consumer-development/changeover-procedure.html.html new file mode 100644 index 0000000000..c4117760ae --- /dev/null +++ b/legacy/v3.2.0/consumer-development/changeover-procedure.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/consumer-development/consumer-chain-governance.html b/legacy/v3.2.0/consumer-development/consumer-chain-governance.html new file mode 100644 index 0000000000..35b111eb6a --- /dev/null +++ b/legacy/v3.2.0/consumer-development/consumer-chain-governance.html @@ -0,0 +1,19 @@ + + + + + +Consumer Chain Governance | Interchain Security + + + + +
+
Version: v3.2.0

Consumer Chain Governance

Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We'll cover what these are in the "Whitelist" section below.

Democracy module

The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy.

Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus.

For an example, see the Democracy Consumer

CosmWasm

There are several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain.

For an example, see Neutron.

The Whitelist

Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see Neutron's whitelist.

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/consumer-development/consumer-chain-governance.html.html b/legacy/v3.2.0/consumer-development/consumer-chain-governance.html.html new file mode 100644 index 0000000000..93bf8766cf --- /dev/null +++ b/legacy/v3.2.0/consumer-development/consumer-chain-governance.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/consumer-development/offboarding.html b/legacy/v3.2.0/consumer-development/offboarding.html new file mode 100644 index 0000000000..00b920a93f --- /dev/null +++ b/legacy/v3.2.0/consumer-development/offboarding.html @@ -0,0 +1,19 @@ + + + + + +Offboarding Checklist | Interchain Security + + + + +
+
Version: v3.2.0

Consumer Offboarding

To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).

// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.
// If it passes, all the consumer chain's state is removed from the provider chain. The outstanding unbonding
// operation funds are released.
{
// the title of the proposal
"title": "This was a great chain",
"description": "Here is a .md formatted string specifying removal details",
// the chain-id of the consumer chain to be stopped
"chain_id": "consumerchain-1",
// the time on the provider chain at which all validators are responsible to stop their consumer chain validator node
"stop_time": "2023-03-07T12:40:00.000000Z",
}

More information will be listed in a future version of this document.

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/consumer-development/offboarding.html.html b/legacy/v3.2.0/consumer-development/offboarding.html.html new file mode 100644 index 0000000000..33862c917c --- /dev/null +++ b/legacy/v3.2.0/consumer-development/offboarding.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/consumer-development/onboarding.html b/legacy/v3.2.0/consumer-development/onboarding.html new file mode 100644 index 0000000000..bff830b217 --- /dev/null +++ b/legacy/v3.2.0/consumer-development/onboarding.html @@ -0,0 +1,20 @@ + + + + + +Onboarding Checklist | Interchain Security + + + + +
+
Version: v3.2.0

Consumer Onboarding Checklist

The following checklists will aid in onboarding a new consumer chain to replicated security.

Additionally, you can check the testnet repo for a comprehensive guide on preparing and launching consumer chains.

1. Complete testing & integration

  • test integration with gaia
  • test your protocol with supported relayer versions (minimum hermes 1.4.1)
  • reach out to the ICS team if you are facing issues

2. Create an Onboarding Repository

To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain.

This should include (at minimum):

  • genesis.json without CCV data (before the proposal passes)
  • genesis.json with CCV data (after spawn time passes)
  • information about relevant seed/peer nodes you are running
  • relayer information (compatible versions)
  • copy of your governance proposal (as JSON)
  • a script showing how to start your chain and connect to peers (optional)
  • take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable

Example of such a repository can be found here.

3. Submit a Governance Proposal

Before you submit a ConsumerChainAddition proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch. +If possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues.

Additionally, reach out to the community via the forum to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers.

  • determine your chain's spawn time
  • determine consumer chain parameters to be put in the proposal
  • take note to include a link to your onboarding repository
  • describe the purpose and benefits of running your chain

Example of a consumer chain addition proposal.

// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.
// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.
// It is recommended that spawn time occurs after the proposal end time.
{
// Title of the proposal
"title": "Add consumer chain",
// Description of the proposal
// format the text as a .md file and include the file in your onboarding repository
"description": ".md description of your chain and all other relevant information",
// Proposed chain-id of the new consumer chain.
// Must be unique from all other consumer chain ids of the executing provider chain.
"chain_id": "newchain-1",
// Initial height of new consumer chain.
// For a completely new chain, this will be {0,1}.
"initial_height" : {
"revision_height": 0,
"revision_number": 1,
},
// Hash of the consumer chain genesis state without the consumer CCV module genesis params.
// It is used for off-chain confirmation of genesis.json validity by validators and other parties.
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
// Hash of the consumer chain binary that should be run by validators on chain initialization.
// It is used for off-chain confirmation of binary validity by validators and other parties.
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
// Unbonding period for the consumer chain.
// It should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
// IBC transfer packets will timeout after this interval elapses.
"transfer_timeout_period": 1800000000000,
// The fraction of tokens allocated to the consumer redistribution address during distribution events.
// The fraction is a string representing a decimal number. For example "0.75" would represent 75%.
// The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.
"consumer_redistribution_fraction": "0.75",
// BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.
// eg. send rewards to the provider every 1000 blocks
"blocks_per_distribution_transmission": 1000,
// The number of historical info entries to persist in store.
// This param is a part of the cosmos sdk staking module. In the case of
// a ccv enabled consumer chain, the ccv module acts as the staking module.
"historical_entries": 10000,
// The ID of a token transfer channel used for the Reward Distribution
// sub-protocol. If DistributionTransmissionChannel == "", a new transfer
// channel is created on top of the same connection as the CCV channel.
// Note that transfer_channel_id is the ID of the channel end on the consumer chain.
// it is most relevant for chains performing a sovereign to consumer changeover
// in order to maintain the existing ibc transfer channel
"distribution_transmission_channel": "channel-123"
}

4. Launch

The consumer chain starts after at least 66.67% of all provider's voting power comes online. The consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer

  • provide a repo with onboarding instructions for validators (it should already be listed in the proposal)
  • genesis.json with ccv data populated (MUST contain the initial validator set)
  • maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)
  • have a block explorer in place to track chain activity & health
+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/consumer-development/onboarding.html.html b/legacy/v3.2.0/consumer-development/onboarding.html.html new file mode 100644 index 0000000000..4b05fac46d --- /dev/null +++ b/legacy/v3.2.0/consumer-development/onboarding.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/faq.html b/legacy/v3.2.0/faq.html new file mode 100644 index 0000000000..85575189c0 --- /dev/null +++ b/legacy/v3.2.0/faq.html @@ -0,0 +1,24 @@ + + + + + +Frequently Asked Questions | Interchain Security + + + + +
+
Version: v3.2.0

Frequently Asked Questions

What is the meaning of Validator Set Replication?

VSR simply means that the same validator set is used to secure both the provider and consumer chains. VSR is ensured through ICS protocol which keeps consumers up to date with the validator set of the provider.

What is a consumer chain?

Consumer chain is blockchain operated by the same validator operators as the provider chain. The ICS protocol ensures the validator set replication properties (informs consumer chain about the current state of the validator set on the provider)

Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements.

What happens to consumer if provider is down?

In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set.

The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness.

However, if the trusting_period (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain. +This means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about.

Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point. +At the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.

What happens to provider if consumer is down?

Consumer chains do not impact the provider chain. +The ICS protocol is concerned only with validator set replication and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events).

Can I run the provider and consumer chains on the same machine?

Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation.

Can the consumer chain have its own token?

As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees.

How are Tx fees paid on consumer?

The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations.

Are there any restrictions the consumer chains need to abide by?

No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way. +The only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain.

What's in it for the validators and stakers?

The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by consumer_redistribution_fraction. The rewards are distributed (sent to the provider) every blocks_per_distribution_transmission.

note

consumer_redistribution_fraction and blocks_per_distribution_transmission are parameters defined in the ConsumerAdditionProposal used to create the consumer chain. These parameters can be changed via consumer chain governance.

Can the consumer chain have its own governance?

Yes.

In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.

Validators can also be representatives but representatives are not required to run validator nodes.

This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance.

Can validators opt-out of replicated security?

At present, the validators cannot opt-out of validating consumer chains.

There are multiple opt-out mechanisms under active research.

How does Equivocation Governance Slashing work?

To avoid potential attacks directed at provider chain validators, a new mechanism was introduced:

When a validator double-signs on the consumer chain, a special type of slash packet is relayed to the provider chain. The provider will store information about the double signing validator and allow a governance proposal to be submitted. +If the double-signing proposal passes, the offending validator will be slashed on the provider chain and tombstoned. Tombstoning will permanently exclude the validator from the active set of the provider.

caution

An equivocation proposal cannot be submitted for a validator that did not double sign on any of the consumer chains.

Can Consumer Chains perform Software Upgrades?

Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM).

Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module.

How can I connect to the testnets?

Check out the Joining Replicated Security testnet section.

How do I start using ICS?

To become a consumer chain use this checklist and check the App integration section

Which relayers are supported?

Currently supported versions:

  • Hermes 1.4.1
  • Support for the CCV module was added to the Go relayer in v2.2.0 but v2.4.0 has significant performance fixes which makes it the earliest suggested version to use.

How does key delegation work in ICS?

You can check the Key Assignment Guide for specific instructions.

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/faq.html.html b/legacy/v3.2.0/faq.html.html new file mode 100644 index 0000000000..b911e2c275 --- /dev/null +++ b/legacy/v3.2.0/faq.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/features/key-assignment.html b/legacy/v3.2.0/features/key-assignment.html new file mode 100644 index 0000000000..5ee038c182 --- /dev/null +++ b/legacy/v3.2.0/features/key-assignment.html @@ -0,0 +1,20 @@ + + + + + +Key Assignment | Interchain Security + + + + +
+
Version: v3.2.0

Key Assignment

Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate. +There are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains.

The feature is outlined in this ADR-001

By sending an AssignConsumerKey transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator.

tip

Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity.

Rules

  • a key can be assigned before the consumer addition proposal passes on the provider
  • validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider
  • validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X
  • a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain
tip

Validators can use a different key for each consumer chain.

Adding a key

First, create a new node on the consumer chain using the equivalent:

consumerd init <moniker>

Then query your node for the consensus key.

consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}

Then, make an assign-consensus-key transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain.

gaiad tx provider assign-consensus-key <consumer-chain-id> '<pubkey>' --from <tx-signer> --home <home_dir> --gas 900000 -b sync -y -o json
  • consumer-chain-id is the string identifier of the consumer chain, as assigned on the provider chain
  • consumer-pub-key has the following format {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}

Check that the key was assigned correctly by querying the provider:

gaiad query provider validator-consumer-key <consumer-chain-id> cosmosvalcons1e....3xsj3ayzf4uv6

You must use a valcons address. You can obtain it by querying your node on the provider gaiad tendermint show-address

OR

gaiad query provider validator-provider-key <consumer-chain-id> consumervalcons1e....123asdnoaisdao

You must use a valcons address. You can obtain it by querying your node on the consumer consumerd tendermint show-address

Changing a key

To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied

Removing a key

To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the Adding a key section and using your provider consensus key.

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/features/key-assignment.html.html b/legacy/v3.2.0/features/key-assignment.html.html new file mode 100644 index 0000000000..522e64361b --- /dev/null +++ b/legacy/v3.2.0/features/key-assignment.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/features/proposals.html b/legacy/v3.2.0/features/proposals.html new file mode 100644 index 0000000000..2395a0546f --- /dev/null +++ b/legacy/v3.2.0/features/proposals.html @@ -0,0 +1,26 @@ + + + + + +ICS Provider Proposals | Interchain Security + + + + +
+
Version: v3.2.0

ICS Provider Proposals

Interchain security module introduces 3 new proposal types to the provider.

The proposals are used to propose upcoming interchain security events through governance.

ConsumerAdditionProposal

info

If you are preparing a ConsumerAdditionProposal you can find more information in the consumer onboarding checklist.

Proposal type used to suggest adding a new consumer chain.

When proposals of this type are passed and the spawn_time specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain.

Minimal example:

{
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
"title": "Add consumer chain",
"description": ".md description of your chain and all other relevant information",
"chain_id": "newchain-1",
"initial_height" : {
"revision_height": 0,
"revision_number": 1,
},
// Unbonding period for the consumer chain.
// It should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
"transfer_timeout_period": 1800000000000,
"consumer_redistribution_fraction": "0.75",
"blocks_per_distribution_transmission": 1000,
"historical_entries": 10000,
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1"
// relevant for chains performing a sovereign to consumer changeover
// in order to maintain the existing ibc transfer channel
"distribution_transmission_channel": "channel-123"
}

More examples can be found in the replicated security testnet repository here and here.

ConsumerRemovalProposal

Proposal type used to suggest removing an existing consumer chain.

When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain. +After the consumer chain removal, the chain in question will no longer be secured by the provider's validator set.

info

The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain. +Additional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set. +More information will be made available in the Consumer Offboarding Checklist.

Minimal example:

{
// the time on the provider chain at which all validators are responsible to stop their consumer chain validator node
"stop_time": "2023-03-07T12:40:00.000000Z",
// the chain-id of the consumer chain to be stopped
"chain_id": "consumerchain-1",
"title": "This was a great chain",
"description": "Here is a .md formatted string specifying removal details"
}

EquivocationProposal

tip

EquivocationProposal will only be accepted on the provider chain if at least one of the consumer chains submits equivocation evidence to the provider. +Sending equivocation evidence to the provider is handled automatically by the interchain security protocol when an equivocation infraction is detected on the consumer chain.

Proposal type used to suggest slashing a validator for double signing on consumer chain. +When proposals of this type are passed, the validator in question will be slashed for equivocation on the provider chain.

danger

Take note that an equivocation slash causes a validator to be tombstoned (can never re-enter the active set). +Tombstoning a validator on the provider chain will remove the validator from the validator set of all consumer chains.

Minimal example:

{
"title": "Validator-1 double signed on consumerchain-1",
"description": "Here is more information about the infraction so you can verify it yourself",
// the list of equivocations that will be processed
"equivocations": [
{
"height": 14444680,
"time": "2023-02-28T20:40:00.000000Z",
"power": 5500000,
"consensus_address": "<consensus address ON THE PROVIDER>"
}
]
}

ChangeRewardDenomProposal

tip

ChangeRewardDenomProposal will only be accepted on the provider chain if at least one of the denomsToAdd or denomsToRemove fields is populated with at least one denom. Also, a denom cannot be repeated in both sets.

Proposal type used to mutate the set of denoms accepted by the provider as rewards.

Minimal example:

{
"title": "Add untrn as a reward denom",
"description": "Here is more information about the proposal",
"denomsToAdd": ["untrn"],
"denomsToRemove": []
}

Notes

When submitting equivocation evidence through an EquivocationProposal please take note that you need to use the consensus address (valcons) of the offending validator on the provider chain. +Besides that, the height and the time fields should be mapped to the provider chain to avoid your evidence being rejected.

Before submitting the proposal please check that the evidence is not outdated by comparing the infraction height with the max_age_duration and max_age_num_blocks consensus parameters of the provider chain.

Gaia example:

➜  ~ cat genesis.json | jq ".consensus_params"
{
"block": {
...
},
"evidence": {
"max_age_duration": "172800000000000",
"max_age_num_blocks": "1000000",
"max_bytes": "50000"
},
"validator": {
...
},
"version": {}
}

Any EquivocationProposal transactions that submit evidence with height older than max_age_num_blocks and time older than max_age_duration will be considered invalid.

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/features/proposals.html.html b/legacy/v3.2.0/features/proposals.html.html new file mode 100644 index 0000000000..2d83a7c135 --- /dev/null +++ b/legacy/v3.2.0/features/proposals.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/features/reward-distribution.html b/legacy/v3.2.0/features/reward-distribution.html new file mode 100644 index 0000000000..5882321a32 --- /dev/null +++ b/legacy/v3.2.0/features/reward-distribution.html @@ -0,0 +1,25 @@ + + + + + +Reward distribution | Interchain Security + + + + +
+
Version: v3.2.0

Reward distribution

Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators. +In replicated security block rewards and fees are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel that gets created during consumer chain initialization.

Reward distribution on the provider is handled by the distribution module - validators and delegators receive a fraction of the consumer chain tokens as staking rewards. +The distributed reward tokens are IBC tokens and therefore cannot be staked on the provider chain.

Sending and distributing rewards from consumer chains to provider chain is handled by the Reward Distribution sub-protocol.

Note

The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the ConsumerRewardsPool. +There is a new transaction type called RegisterConsumerRewardDenom. This transaction allows consumer chains to register denoms to be used as consumer chain rewards on the provider. +The cost to register a denom is configurable (ConsumerRewardDenomRegistrationFee chain param) and the full amount of this fee is transferred to the community pool of the provider chain. Only denoms registered through this transaction are then transferred from the ConsumerRewardsPool to the FeePoolAddress, to be distributed out to delegators and validators.

Instructions for adding a denom

The transaction must be carried out on the provider chain. Please use the ibc/* denom trace format.

tip
# reward denoms must be registered on the provider chain (gaia in this example)
gaiad tx provider register-consumer-reward-denom ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9 --from mykey

Parameters

tip

The following chain parameters dictate consumer chain distribution amount and frequency. +They are set at consumer genesis and blocks_per_distribution_transmission, consumer_redistribution_fraction +transfer_timeout_period must be provided in every ConsumerChainAddition proposal.

consumer_redistribution_fraction

The fraction of tokens allocated to the consumer redistribution address during distribution events. The fraction is a string representing a decimal number. For example "0.75" would represent 75%.

tip

Example:

With consumer_redistribution_fraction set to 0.75 the consumer chain would send 75% of its block rewards and accumulated fees to the consumer redistribution address, and the remaining 25% to the provider chain every n blocks where n == blocks_per_distribution_transmission.

blocks_per_distribution_transmission

The number of blocks between IBC token transfers from the consumer chain to the provider chain.

transfer_timeout_period

Timeout period for consumer chain reward distribution IBC packets.

distribution_transmission_channel

Provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.

provider_fee_pool_addr_str

Provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/features/reward-distribution.html.html b/legacy/v3.2.0/features/reward-distribution.html.html new file mode 100644 index 0000000000..3e9e2ef3e1 --- /dev/null +++ b/legacy/v3.2.0/features/reward-distribution.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/features/slashing.html b/legacy/v3.2.0/features/slashing.html new file mode 100644 index 0000000000..eaf674d553 --- /dev/null +++ b/legacy/v3.2.0/features/slashing.html @@ -0,0 +1,22 @@ + + + + + +Consumer Initiated Slashing | Interchain Security + + + + +
+
Version: v3.2.0

Consumer Initiated Slashing

A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain. +In essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake).

To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized. +Any infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains.

In the current implementation there are 2 important changes brought by the interchain security module:

Downtime infractions

reported by consumer chains are acted upon on the provider as soon as the provider receives the infraction evidence.

Instead of slashing, the provider will only jail offending validator for the duration of time established in the chain parameters.

info

Slash throttling (sometimes called jail throttling) mechanism ensures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider.

Double-signing (equivocation)

infractions are not acted upon immediately.

Upon receiving double signing evidence, the provider chain will take note of the evidence and allow for EquivocationProposal to be submitted to slash the offending validator. +Any EquivocationProposals to slash a validator that has not double signed on any of the consumer chains will be automatically rejected by the provider chain.

info

The offending validator will only be slashed (and tombstoned) if an EquivocationProposal is accepted and passed through governance.

The offending validator will effectively get slashed and tombstoned on all consumer chains.

You can find instructions on creating EquivocationProposals here.

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/features/slashing.html.html b/legacy/v3.2.0/features/slashing.html.html new file mode 100644 index 0000000000..bc05d16806 --- /dev/null +++ b/legacy/v3.2.0/features/slashing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/introduction/overview.html b/legacy/v3.2.0/introduction/overview.html new file mode 100644 index 0000000000..fe8a232df5 --- /dev/null +++ b/legacy/v3.2.0/introduction/overview.html @@ -0,0 +1,19 @@ + + + + + +Overview | Interchain Security + + + + +
+
Version: v3.2.0

Overview

info

Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.


Replicated security allows anyone to launch a "consumer" blockchain using the same validator set as the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit the full security and decentralization of the provider.

Why Replicated Security?

  • Full provider security. At launch, consumer chains are secured by the full validator set and market cap of the provider chain.
  • Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum.
  • Projects keep majority of gas fees. Depending on configuration, these fees either go to the project’s community DAO, or can be used in the protocol in other ways.
  • No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. A governance vote will take place for a chain to get adopted by the provider validators which will encourage participation and signal strong buy-in into the project's long-term success.
  • Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set.

Core protocol

info

Protocol specification is available as ICS-028 in the IBC repository.

Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer.

To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider.

Downtime Slashing

If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period.

Equivocation (Double Sign) Slashing

Evidence of equivocation must be submitted to provider governance and be voted on. This behavior is an extra safeguard before a validator is slashed, and may be replaced by a more automated system in the future.

Tokenomics and Rewards

Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance.

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/introduction/overview.html.html b/legacy/v3.2.0/introduction/overview.html.html new file mode 100644 index 0000000000..d8d9aa7575 --- /dev/null +++ b/legacy/v3.2.0/introduction/overview.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/introduction/params.html b/legacy/v3.2.0/introduction/params.html new file mode 100644 index 0000000000..5a1e8eb4ba --- /dev/null +++ b/legacy/v3.2.0/introduction/params.html @@ -0,0 +1,21 @@ + + + + + +Interchain Security Parameters | Interchain Security + + + + +
+
Version: v3.2.0

Interchain Security Parameters

The parameters necessary for Interchain Security (ICS) are defined in

  • the Params structure in proto/interchain_security/ccv/provider/v1/provider.proto for the provider;
  • the Params structure in proto/interchain_security/ccv/consumer/v1/consumer.proto for the consumer.

Time-based parameters

ICS relies on the following time-based parameters.

ProviderUnbondingPeriod

is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance.

ConsumerUnbondingPeriod

is the unbonding period on the consumer chain.

info

ConsumerUnbondingPeriod is set via the ConsumerAdditionProposal governance proposal to add a new consumer chain. +It is recommended that every consumer chain set and unbonding period shorter than ProviderUnbondingPeriod


Example:

ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day

Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer.

TrustingPeriodFraction

is used to calculate the TrustingPeriod of created IBC clients on both provider and consumer chains.

Setting TrustingPeriodFraction to 0.5 would result in the following:

TrustingPeriodFraction = 0.5
ProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5
ConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5

Note that a light clients must be updated within the TrustingPeriod in order to avoid being frozen.

For more details, see the IBC specification of Tendermint clients.

CCVTimeoutPeriod

is the period used to compute the timeout timestamp when sending IBC packets.

For more details, see the IBC specification of Channel & Packet Semantics.

danger

If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed.

CCVTimeoutPeriod may have different values on the provider and consumer chains.

  • CCVTimeoutPeriod on the provider must be larger than ConsumerUnbondingPeriod
  • CCVTimeoutPeriod on the consumer is initial set via the ConsumerAdditionProposal

InitTimeoutPeriod

is the maximum allowed duration for CCV channel initialization to execute.

For any consumer chain, if the CCV channel is not established within InitTimeoutPeriod then the consumer chain will be removed and therefore will not be secured by the provider chain.

The countdown starts when the spawn_time specified in the ConsumerAdditionProposal is reached.

VscTimeoutPeriod

is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live. +If the VscTimeoutPeriod is ever reached for a consumer chain that chain will be considered not live and removed from interchain security.

tip

VscTimeoutPeriod MUST be larger than the ConsumerUnbondingPeriod.

BlocksPerDistributionTransmission

is the number of blocks between rewards transfers from the consumer to the provider.

TransferPeriodTimeout

is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider.

If this timeout expires, then the transfer is attempted again after BlocksPerDistributionTransmission blocks.

  • TransferPeriodTimeout on the consumer is initial set via the ConsumerAdditionProposal gov proposal to add the consumer
  • TransferPeriodTimeout should be smaller than BlocksPerDistributionTransmission x avg_block_time

Slash Throttle Parameters

SlashMeterReplenishPeriod

exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed.

The meter is replenished to an amount equal to the slash meter allowance for that block, or SlashMeterReplenishFraction * CurrentTotalVotingPower.

SlashMeterReplenishFraction

exists on the provider as the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs.

This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a sdk.Dec when used.

MaxThrottledPackets

exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value.

This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness.

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/introduction/params.html.html b/legacy/v3.2.0/introduction/params.html.html new file mode 100644 index 0000000000..e9c9684e8c --- /dev/null +++ b/legacy/v3.2.0/introduction/params.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/introduction/technical-specification.html b/legacy/v3.2.0/introduction/technical-specification.html new file mode 100644 index 0000000000..286acd7c4c --- /dev/null +++ b/legacy/v3.2.0/introduction/technical-specification.html @@ -0,0 +1,19 @@ + + + + + +Technical Specification | Interchain Security + + + + +
+
Version: v3.2.0

Technical Specification

For a technical deep dive into the replicated security protocol, see the specification.

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/introduction/technical-specification.html.html b/legacy/v3.2.0/introduction/technical-specification.html.html new file mode 100644 index 0000000000..9382e70c94 --- /dev/null +++ b/legacy/v3.2.0/introduction/technical-specification.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/introduction/terminology.html b/legacy/v3.2.0/introduction/terminology.html new file mode 100644 index 0000000000..19e0ca6608 --- /dev/null +++ b/legacy/v3.2.0/introduction/terminology.html @@ -0,0 +1,20 @@ + + + + + +Terminology | Interchain Security + + + + +
+
Version: v3.2.0

Terminology

You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.

Shared Security

Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share its proof-of-stake security with another blockchain or off-chain process.

Interchain Security

Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC.

Replicated Security

A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC. Note this documentation is focused on explaining the concepts from replicated security.

Mesh security

A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see Replicated vs. Mesh Security on the Informal Blog.

Consumer Chain

Chain that is secured by the validator set of the provider, instead of its own. +Replicated security allows the provider chain validator set to validate blocks on the consumer chain.

Standalone Chain

Chain that is secured by its own validator set. This chain does not participate in replicated security.

Standalone chains may sometimes be called "sovereign" - the terms are synonymous.

Changeover Procedure

Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/introduction/terminology.html.html b/legacy/v3.2.0/introduction/terminology.html.html new file mode 100644 index 0000000000..a2d3bf1695 --- /dev/null +++ b/legacy/v3.2.0/introduction/terminology.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/validators/changeover-procedure.html b/legacy/v3.2.0/validators/changeover-procedure.html new file mode 100644 index 0000000000..3547672b81 --- /dev/null +++ b/legacy/v3.2.0/validators/changeover-procedure.html @@ -0,0 +1,21 @@ + + + + + +Validator instructions for Changeover Procedure | Interchain Security + + + + +
+
Version: v3.2.0

Validator instructions for Changeover Procedure

More details available in Changeover Procedure documentation.

A major difference betwen launching a new consumer chain vs. onboarding a standalone chain to ICS is that there is no consumer genesis available for the standalone chain. Since a standalone chain already exists, its state must be preserved once it transitions to being a consumer chain.

Timeline

Upgrading standalone chains can be best visualised using a timeline, such as the one available Excalidraw graphic by Stride.

There is some flexibility with regards to how the changeover procedure is executed, so please make sure to follow the guides provided by the team doing the changeover.

Standalone to consumer transition timeline

1. ConsumerAdditionProposal on provider chain

This step will add the standalone chain to the list of consumer chains secured by the provider. +This step dictates the spawn_time. After spawn_time the CCV state (initial validator set of the provider) will be available to the consumer.

To obtain it from the provider use:

gaiad q provider consumer-genesis stride-1 -o json > ccv-state.json
jq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' genesis.json ccv-state.json > ccv.json

2. SoftwareUpgradeProposal on the standalone/consumer chain

This upgrade proposal will introduce ICS to the standalone chain, making it a consumer.

3. Assigning a consumer key

After spawn_time, make sure to assign a consumer key if you intend to use one.

Instructions are available here

4. Perform the software ugprade on standalone chain

Please use instructions provided by the standalone chain team and make sure to reach out if you are facing issues. +The upgrade preparation depends on your setup, so please make sure you prepare ahead of time.

danger

The ccv.json from step 1. must be made available on the machine running the standalone/consumer chain at standalone chain upgrade_height. This file contains the initial validator set and parameters required for normal ICS operation.

Usually, the file is placed in $NODE_HOME/config but this is not a strict requirement. The exact details are available in the upgrade code of the standalone/consumer chain.

Performing this upgrade will transition the standalone chain to be a consumer chain.

After 3 blocks, the standalone chain will stop using the "old" validator set and begin using the provider validator set.

FAQ

Can I reuse the same validator key for the consumer chain that I am already using on the standalone chain? Will I need to perform a AssignConsumerKey tx with this key before spawn time?

Validators must either assign a key or use the same key as on the provider.

If you are validating both the standalone and the provider, you can use your current standalone key with some caveats:

  • you must submit an AssignConsumerKey tx with your current standalone validator key
  • it is best to submit AssignConsumerKey tx before spawn_time
  • if you do not submit the Tx, it is assumed that you will be re-using your provider key to validate the standalone/consumer chain

Can I continue using the same node that was validating the standalone chain?

Yes.

Please assign your consensus key as stated aboce.

Can I set up a new node to validate the standalone/consumer chain after it transitions to replicated security?

Yes.

If you are planning to do this please make sure that the node is synced with standalone network and to submit AssignConsumerKey tx before spawn_time.

What happens to the standalone validator set after it after it transitions to replicated security?

The standalone chain validators will stop being validators after the first 3 blocks are created while using replicated security. The standalone validators will become governors and still can receive delegations if the consumer chain is using the consumer-democracy module.

Governors DO NOT VALIDATE BLOCKS.

Instead, they can participate in the governance process and take on other chain-specific roles.

Credits

Thank you Stride team for providing detailed instructions about the changeover procedure.

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/validators/changeover-procedure.html.html b/legacy/v3.2.0/validators/changeover-procedure.html.html new file mode 100644 index 0000000000..8898509662 --- /dev/null +++ b/legacy/v3.2.0/validators/changeover-procedure.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/validators/joining-neutron.html b/legacy/v3.2.0/validators/joining-neutron.html new file mode 100644 index 0000000000..8c76560e3b --- /dev/null +++ b/legacy/v3.2.0/validators/joining-neutron.html @@ -0,0 +1,19 @@ + + + + + +Joining Neutron | Interchain Security + + + + +
+
Version: v3.2.0

Joining Neutron

Neutron is the first consumer chain to implement ICS.

You can find instructions on joining the mainnet here.

To join Neutron chain on the replicated security testnet check here

Resources

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/validators/joining-neutron.html.html b/legacy/v3.2.0/validators/joining-neutron.html.html new file mode 100644 index 0000000000..8a547e49aa --- /dev/null +++ b/legacy/v3.2.0/validators/joining-neutron.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/validators/joining-stride.html b/legacy/v3.2.0/validators/joining-stride.html new file mode 100644 index 0000000000..d2bf1b2a7b --- /dev/null +++ b/legacy/v3.2.0/validators/joining-stride.html @@ -0,0 +1,19 @@ + + + + + +Joining Stride | Interchain Security + + + + +
+
Version: v3.2.0

Joining Stride

Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.

stride-1 network (mainnet) will perform a software upgrade and at height 4616678 that will transition the network to using the Cosmos Hub's (cosmoshub-4) validator set.

You can find instructions about the Stride consumer chain launch and joining the mainnet here.

This Excalidraw graphic explains the timeline of Stride's changeover procedure.

Note

Stride re-uses an existing transfer channel to send consumer rewards to the provider chain, in order to preserve existing transfer IBC denom between stride-1 and cosmoshub-4.

Resources

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/validators/joining-stride.html.html b/legacy/v3.2.0/validators/joining-stride.html.html new file mode 100644 index 0000000000..3d9bfadf7b --- /dev/null +++ b/legacy/v3.2.0/validators/joining-stride.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/validators/joining-testnet.html b/legacy/v3.2.0/validators/joining-testnet.html new file mode 100644 index 0000000000..6478eec604 --- /dev/null +++ b/legacy/v3.2.0/validators/joining-testnet.html @@ -0,0 +1,20 @@ + + + + + +Joining Replicated Security testnet | Interchain Security + + + + +
+
Version: v3.2.0

Joining Replicated Security testnet

Introduction

This short guide will teach you how to join the Replicated Security testnet.

The experience gained in the testnet will prepare you for validating interchain secured chains.

tip

Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set.

For general information about running cosmos-sdk based chains check out the validator basics and Running a Node section of Cosmos SDK docs

Joining the provider chain

info

At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain.

A comprehensive guide is available here.

Initialization

First, initialize your $NODE_HOME using the provider chain binary.

NODE_MONIKER=<your_node>
CHAIN_ID=provider
NODE_HOME=<path_to_your_home>

gaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME

Add your key to the keyring - more details available here.

In this example we will use the test keyring-backend. This option is not safe to use in production.

gaiad keys add <key_moniker> --keyring-backend test

# save the address as variable for later use
MY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)

Before issuing any transactions, use the provider testnet faucet to add funds to your address.

curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider

# example output:
{
"address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",
"amount": "10000000uatom",
"chain": "provider",
"hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",
"status": "success"
}

Then, use the account associated with the keyring to issue a create-validator transaction which will register your validator on chain.

gaiad tx staking create-validator \
--amount=1000000uatom \
--pubkey=$(gaiad tendermint show-validator) \
--moniker="choose a moniker" \
--chain-id=$CHAIN_ID" \
--commission-rate="0.10" \
--commission-max-rate="0.20" \
--commission-max-change-rate="0.01" \
--min-self-delegation="1000000" \
--gas="auto" \
--gas-prices="0.0025uatom" \
--from=<key_moniker>
tip

Check this guide to edit your validator.

After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use statesync to catch up to the rest of the network.

You can use this script to modify your config.toml with the required statesync parameters.

# create the statesync script
$: cd $NODE_HOME
$: touch statesync.sh
$ chmod 700 statesync.sh # make executable

Paste the following instructions into the statesync.sh:

#!/bin/bash

SNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"

LATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \
BLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \
TRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)

sed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\1true| ; \
s|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\1\"$SNAP_RPC,$SNAP_RPC\"| ; \
s|^(trust_height[[:space:]]+=[[:space:]]+).*$|\1$BLOCK_HEIGHT| ; \
s|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\1\"$TRUST_HASH\"|" $NODE_HOME/config/config.toml

Then, you can execute the script:

$: ./statesync.sh # setup config.toml for statesync

Finally, copy the provider genesis and start your node:

$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/replicated-security/provider/provider-genesis.json
$: wget $GENESIS_URL -O genesis.json
$: genesis.json $NODE_HOME/config/genesis.json
# start the service
$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"

Additional scripts to setup your nodes are available here and here. The scripts will configure your node and create the required services - the scripts only work in linux environments.

Joining consumer chains

tip

Once you reach the active set on the provider chain, you will be required to validate all available consumer chains.

You can use the same consensus key on all consumer chains, or opt to use a different key on each consumer chain. +Check out this guide to learn more about key assignment in replicated security.

To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries.

info

When running the provider chain and consumers on the same machine please update the PORT numbers for each of them and make sure they do not overlap (otherwise the binaries will not start).

Important ports to re-configure:

  • --rpc.laddr
  • --p2p.laddr
  • --api.address
  • --grpc.address
  • --grpc-web.address

Re-using consensus key

To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the priv_validator_key.json into the home directory of your consumer chain (<consumer_home>/config/priv_validator_key.json).

When you start the chain, the consensus key will be the same on the provider and the consumer chain.

Assigning consensus keys

Whenever you initialize a new node, it will be configured with a consensus key you can use.

# machine running consumer chain
consumerd init <node_moniker> --home <home_path> --chain-id consumer-1

# use the output of this command to get the consumer chain consensus key
consumerd tendermint show-validator
# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}

Then, let the provider know which key you will be using for the consumer chain:

# machine running the provider chain
gaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b sync -y -o json

After this step, you are ready to copy the consumer genesis into your nodes's /config folder, start your consumer chain node and catch up to the network.

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/validators/joining-testnet.html.html b/legacy/v3.2.0/validators/joining-testnet.html.html new file mode 100644 index 0000000000..b378240a0d --- /dev/null +++ b/legacy/v3.2.0/validators/joining-testnet.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/validators/overview.html b/legacy/v3.2.0/validators/overview.html new file mode 100644 index 0000000000..fa63df6c9d --- /dev/null +++ b/legacy/v3.2.0/validators/overview.html @@ -0,0 +1,24 @@ + + + + + +Overview | Interchain Security + + + + +
+
Version: v3.2.0

Overview

tip

We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.

At present, replicated security requires all validators of the provider chain (ie. Cosmos Hub) to run validator nodes for all governance-approved consumer chains.

Once a ConsumerAdditionProposal passes, validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains.

Provider chain and consumer chains represent standalone chains that only share the validator set ie. the same validator operators are tasked with running all chains.

info

To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 180 validators for Cosmos Hub).

Startup sequence overview

Consumer chains cannot start and be secured by the validator set of the provider unless a ConsumerAdditionProposal is passed. +Each proposal contains defines a spawn_time - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider.

tip

Validators are required to run consumer chain binaries only after spawn_time has passed.

Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains.

The image below illustrates the startup sequence +startup

1. Consumer Chain init + 2. Genesis generation

Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ConsumerAdditionProposal

3. Submit Proposal

Consumer chain team (or their advocates) submits a ConsumerAdditionProposal. +The most important parameters for validators are:

  • spawn_time - the time after which the consumer chain must be started
  • genesis_hash - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and spawn_time is reached
  • binary_hash - hash of the consumer chain binary used to validate the software builds

4. CCV Genesis state generation

After reaching spawn_time the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain genesis.json. The CCV validator set consists of the validator set on the provider at spawn_time.

The state can be queried on the provider chain (in this case the Cosmos Hub):

 gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json

This is used by the launch coordinator to create the final genesis.json that will be distributed to validators in step 5.

5. Updating the genesis file

Upon reaching the spawn_time the initial validator set state will become available on the provider chain. The initial validator set is included in the final genesis.json of the consumer chain.

6. Chain start

info

The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences.

The new genesis.json containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided genesis.json to start their consumer chain node.

tip

Please pay attention to any onboarding repositories provided by the consumer chain teams. +Recommendations are available in Consumer Onboarding Checklist. +Another comprehensive guide is available in the Replicated Security testnet repo.

7. Creating IBC connections

Finally, to fully establish replicated security an IBC relayer is used to establish connections and create the required channels.

danger

The relayer can establish the connection only after the consumer chain starts producing blocks.

hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> 
hermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1
hermes start

Downtime Infractions

At present, the consumer chain can report evidence about downtime infractions to the provider chain. The min_signed_per_window and signed_blocks_window can be different on each consumer chain and are subject to changes via consumer chain governance.

info

Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains.

To unjail, the validator must wait for the jailing period to elapse on the provider chain and submit an unjail transaction on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains.

More information is available in Downtime Slashing documentation

Double-signing Infractions

To learn more about equivocation handling in replicated security check out the Slashing and EquivocationProposal documentation sections

Key assignment

Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use.

For more information check our the Key assignment overview and guide

References:

+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/validators/overview.html.html b/legacy/v3.2.0/validators/overview.html.html new file mode 100644 index 0000000000..ce6d3c77b5 --- /dev/null +++ b/legacy/v3.2.0/validators/overview.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.2.0/validators/withdraw_rewards.html b/legacy/v3.2.0/validators/withdraw_rewards.html new file mode 100644 index 0000000000..e91cfc909c --- /dev/null +++ b/legacy/v3.2.0/validators/withdraw_rewards.html @@ -0,0 +1,20 @@ + + + + + +Withdrawing consumer chain validator rewards | Interchain Security + + + + +
+
Version: v3.2.0

Withdrawing consumer chain validator rewards

Here are example steps for withdrawing rewards from consumer chains in the provider chain

info

The examples used are from rs-testnet, the replicated security persistent testnet.

Validator operator address: cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 +Self-delegation address: cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

Prior to withdrawing rewards, query balances for self-delegation address:

gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

balances:
- amount: "1000000000000"
denom: uatom
pagination:
next_key: null
total: "0"

Querying validator rewards

Query rewards for the validator address:

gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6

rewards:
- amount: "158.069895000000000000"
denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD
- amount: "841842390516.072526500000000000"
denom: uatom

The ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD denom represents rewards from a consumer chain.

Withdrawing rewards and commission

1. Withdraw rewards

gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y

txhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A

2. Confirm withdrawal

After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:

gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

balances:
- amount: "216"
denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD
- amount: "2233766225342"
denom: uatom
pagination:
next_key: null
total: "0"
+ + + + \ No newline at end of file diff --git a/legacy/v3.2.0/validators/withdraw_rewards.html.html b/legacy/v3.2.0/validators/withdraw_rewards.html.html new file mode 100644 index 0000000000..52a08d48d2 --- /dev/null +++ b/legacy/v3.2.0/validators/withdraw_rewards.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0.html b/legacy/v3.3.0.html new file mode 100644 index 0000000000..ed3c92e986 --- /dev/null +++ b/legacy/v3.3.0.html @@ -0,0 +1,19 @@ + + + + + +Interchain Security Docs | Interchain Security + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0.html.html b/legacy/v3.3.0.html.html new file mode 100644 index 0000000000..79abb929ea --- /dev/null +++ b/legacy/v3.3.0.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-001-key-assignment.html b/legacy/v3.3.0/adrs/adr-001-key-assignment.html new file mode 100644 index 0000000000..3001db3a67 --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-001-key-assignment.html @@ -0,0 +1,19 @@ + + + + + +Key Assignment | Interchain Security + + + + +
+
Version: v3.3.0

ADR 001: Key Assignment

Changelog

  • 2022-12-01: Initial Draft

Status

Accepted

Context

KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate.

Decision

It is possible to change the keys at any time by submitting a transaction (i.e., MsgAssignConsumerKey).

State required

  • ValidatorConsumerPubKey - Stores the validator assigned keys for every consumer chain.
ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey
  • ValidatorByConsumerAddr - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol.
ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress
  • KeyAssignmentReplacements - Stores the key assignments that need to be replaced in the current block. Needed to apply the key assignments received in a block to the validator updates sent to the consumer chains.
KeyAssignmentReplacementsBytePrefix | len(chainID) | chainID | providerConsAddress -> abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower},
  • ConsumerAddrsToPrune - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ValidatorByConsumerAddr.
ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses

Protocol overview

On receiving a MsgAssignConsumerKey(chainID, providerAddr, consumerKey) message:

// get validator from staking module  
validator, found := stakingKeeper.GetValidator(providerAddr)
if !found {
return ErrNoValidatorFound
}
providerConsAddr := validator.GetConsAddr()

// make sure consumer key is not in use
consumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)
if _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {
return ErrInvalidConsumerConsensusPubKey
}

// check whether the consumer chain is already registered
// i.e., a client to the consumer was already created
if _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {
// get the previous key assigned for this validator on this consumer chain
oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)
if found {
// mark this old consumer key as prunable once the VSCMaturedPacket
// for the current VSC ID is received
oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)
vscID := GetValidatorSetUpdateId()
AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)
} else {
// the validator had no key assigned on this consumer chain
oldConsumerKey := validator.TmConsPublicKey()
}

// check whether the validator is valid, i.e., its power is positive
if currentPower := stakingKeeper.GetLastValidatorPower(providerAddr); currentPower > 0 {
// to enable multiple calls of AssignConsumerKey in the same block by the same validator
// the key assignment replacement should not be overwritten
if _, found := GetKeyAssignmentReplacement(chainID, providerConsAddr); !found {
// store old key and power for modifying the valset update in EndBlock
oldKeyAssignment := abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower}
SetKeyAssignmentReplacement(chainID, providerConsAddr, oldKeyAssignment)
}
}
} else {
// if the consumer chain is not registered, then remove the previous reverse mapping
if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {
oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)
DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)
}
}


// set the mapping from this validator's provider address to the new consumer key
SetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)

// set the reverse mapping: from this validator's new consensus address
// on the consumer to its consensus address on the provider
SetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)

When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see MakeConsumerGenesis).

func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {
// ...
// get initial valset from the staking module
var updates []abci.ValidatorUpdate{}
stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {
validator := stakingKeeper.GetValidator(providerAddr)
providerKey := validator.TmConsPublicKey()
updates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})
return false
})

// applies the key assignment to the initial validator
for i, update := range updates {
providerAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)
if consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {
updates[i].PubKey = consumerKey
}
}
gen.InitialValSet = updates

// get a hash of the consumer validator set from the update
updatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)
hash := tendermint.NewValidatorSet(updatesAsValSet).Hash()

return gen, hash, nil
}

On EndBlock while queueing VSCPackets to send to registered consumer chains:

func QueueVSCPackets() {
valUpdateID := GetValidatorSetUpdateId()
// get the validator updates from the staking module
valUpdates := stakingKeeper.GetValidatorUpdates()

IterateConsumerChains(func(chainID, clientID string) (stop bool) {
// apply the key assignment to the validator updates
valUpdates := ApplyKeyAssignmentToValUpdates(chainID, valUpdates)
// ..
})
// ...
}

func ApplyKeyAssignmentToValUpdates(
chainID string,
valUpdates []abci.ValidatorUpdate,
) (newUpdates []abci.ValidatorUpdate) {
for _, valUpdate := range valUpdates {
providerAddr := utils.TMCryptoPublicKeyToConsAddr(valUpdate.PubKey)

// if a key assignment replacement is found, then
// remove the valupdate with the old consumer key
// and create two new valupdates
prevConsumerKey, _, found := GetKeyAssignmentReplacement(chainID, providerAddr)
if found {
// set the old consumer key's power to 0
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: prevConsumerKey,
Power: 0,
})
// set the new consumer key's power to the power in the update
newConsumerKey := GetValidatorConsumerPubKey(chainID, providerAddr)
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: newConsumerKey,
Power: valUpdate.Power,
})
// delete key assignment replacement
DeleteKeyAssignmentReplacement(chainID, providerAddr)
} else {
// there is no key assignment replacement;
// check if the validator's key is assigned
consumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr)
if found {
// replace the update containing the provider key
// with an update containing the consumer key
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: consumerKey,
Power: valUpdate.Power,
})
} else {
// keep the same update
newUpdates = append(newUpdates, valUpdate)
}
}
}

// iterate over the remaining key assignment replacements
IterateKeyAssignmentReplacements(chainID, func(
pAddr sdk.ConsAddress,
prevCKey tmprotocrypto.PublicKey,
power int64,
) (stop bool) {
// set the old consumer key's power to 0
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: prevCKey,
Power: 0,
})
// set the new consumer key's power to the power in key assignment replacement
newConsumerKey := GetValidatorConsumerPubKey(chainID, pAddr)
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: newConsumerKey,
Power: power,
})
return false
})

// remove all the key assignment replacements

return newUpdates
}

On receiving a SlashPacket from a consumer chain with id chainID for a infraction of a validator data.Validator:

func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {
// ...
// the slash packet validator address may be known only on the consumer chain;
// in this case, it must be mapped back to the consensus address on the provider chain
consumerAddr := sdk.ConsAddress(data.Validator.Address)
providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)
if !found {
// the validator has the same key on the consumer as on the provider
providerAddr = consumer
}
// ...
}

On receiving a VSCMatured:

func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {
// ...
// prune previous consumer validator address that are no longer needed
consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)
for _, addr := range consumerAddrs {
DeleteValidatorByConsumerAddr(chainID, addr)
}
DeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)
// ...
}

On stopping a consumer chain:

func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {
// ...
// deletes all the state needed for key assignments on this consumer chain
// ...
}

Consequences

Positive

  • Validators can use different consensus keys on the consumer chains.

Negative

  • None

Neutral

  • The consensus state necessary to create a client to the consumer chain must use the hash returned by the MakeConsumerGenesis method as the nextValsHash.
  • The consumer chain can no longer check the initial validator set against the consensus state on InitGenesis.

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-001-key-assignment.html.html b/legacy/v3.3.0/adrs/adr-001-key-assignment.html.html new file mode 100644 index 0000000000..948d0b309f --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-001-key-assignment.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-002-throttle.html b/legacy/v3.3.0/adrs/adr-002-throttle.html new file mode 100644 index 0000000000..9735c8206f --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-002-throttle.html @@ -0,0 +1,52 @@ + + + + + +Jail Throttling | Interchain Security + + + + +
+
Version: v3.3.0

ADR 002: Jail Throttling

Changelog

  • 2023-01-26: Initial Draft
  • 2023-02-07: Property refined, ADR ready to review/merge
  • 2023-11-22: Refactor for better understanding

Status

Accepted

Context

The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols. +In practice, this assumption may not hold. +A malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider.

Before the throttling feature was implemented, the following attack was possible. +Attacker(s) would create provider validators just below the provider's active set. +Using a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once. +Control of the provider would then pass over to the attackers' validators. +This enables the attacker(s) to halt the provider. +Or even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC.

Decision

The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack, +i.e., this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time.

Required State

Slash meter: There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time. +This meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params.

Global entry queue: There exists a single queue which stores "global slash entries". +These entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering. +This queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.

Per-chain data queue: For each established consumer, there exists a queue which stores "throttled packet data", +i.e.,pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering. +Order is enforced by IBC sequence number. +These "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.

Note: The reason for a multiple-queue design is the VSC Maturity and Slashing Order property (see spec). +There are other ways to ensure such a property (like a queue of linked lists, etc.), but the proposed approach seemed to be the most understandable and easiest to implement with a KV store.

Params

SlashMeterReplenishPeriod -- the period after which the slash meter is replenished.

SlashMeterReplenishFraction -- the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs. This param also serves as a maximum fraction of total voting power that the slash meter can hold.

MaxThrottledPackets -- the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value. +This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness.

Protocol Overview

OnRecvSlashPacket

Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:

  1. A global slash entry is queued.
  2. The data of such a packet is added to the per-chain queue.

OnRecvVSCMaturedPacket

Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue.

Endblocker

In the EndBlock of the provider CCV module, there are three actions performed:

  • replenish the slash meter;
  • handle the leading VSCMaturedPackets;
  • and handle the throttle queues.
Slash Meter Replenishment

Once the slash meter becomes not full, it'll be replenished after SlashMeterReplenishPeriod by incrementing the meter with its allowance for the replenishment block, where allowance = SlashMeterReplenishFraction * currentTotalVotingPower. +The slash meter will never exceed its current allowance (function of the total voting power for the block) in value.

Note a few things:

  1. The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power. +In such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods.
  2. Total voting power of a chain changes over time, especially as validators are jailed. +As validators are jailed, total voting power decreases, and so does the jailing allowance. +See below for more detailed throttling property discussion.
  3. The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1. +If the SlashMeterReplenishFraction is set too low, integer rounding will put this minimum value into effect. +That is, if SlashMeterReplenishFraction * currentTotalVotingPower < 1, then the effective allowance would be 1. +This min value of allowance ensures that there's some packets handled over time, even if that is a very long time. +It's a crude solution to an edge case caused by too small of a replenishment fraction.

The behavior described above is achieved by executing CheckForSlashMeterReplenishment() every EndBlock, BEFORE HandleThrottleQueues() is executed.

Handle Leading VSCMaturedPackets

In every block, it is possible that VSCMaturedPacket data was queued before any slash packet data. +Since this "leading" VSCMatured packet data does not have to be throttled (see VSC Maturity and Slashing Order), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes.

Handle Throttle Queues

In every EndBlock, the following logic is executed to handle data from the throttle queues.

meter := getSlashMeter()

// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist
while meter.IsPositiveOrZero() && entriesExist() {
// Get next entry in queue
entry := getNextGlobalSlashEntry()
// Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet
valPower := entry.getValPower()
meter = meter - valPower
// Using the per-chain queue, handle the single slash packet using its queued data,
// then handle all trailing VSCMatured packets for this consumer
handleSlashPacketAndTrailingVSCMaturedPackets(entry)
// Delete entry in global queue, delete handled data
entry.Delete()
deleteThrottledSlashPacketData()
deleteTrailingVSCMaturedPacketData()
}

System Properties

All CCV system properties should be maintained by implementing this feature, see CCV spec - Consumer Initiated Slashing.

One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than MaxThrottledPackets, then the provider binary will panic, and the provider chain will halt. +Therefore this param should be set carefully. See SetThrottledPacketDataSize. +This behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators.

Main Throttling Property

Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions.

First, we introduce the following definitions:

  • A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.
  • The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.
  • There is a list of honest validators such that if they are jailed, X% of the initial validator set will be jailed.

For the Throttling Property to hold, the following assumptions must be true:

  1. We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack.
  2. No validator has more than SlashMeterReplenishFraction of total voting power on the provider.
  3. SlashMeterReplenishFraction is large enough that SlashMeterReplenishFraction * currentTotalVotingPower > 1, +i.e., the replenish fraction is set high enough that we can ignore the effects of rounding.
  4. SlashMeterReplenishPeriod is sufficiently longer than the time it takes to produce a block.

Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined.

Throttling Property: The time it takes to jail/tombstone X% of the initial validator set will be greater than or equal to +$\mathit{SlashMeterReplenishPeriod} \cdot \frac{X}{\mathit{SlashMeterReplenishFraction}} - 2 \cdot \mathit{SlashMeterReplenishPeriod}$.

Intuition

Let's use the following notation:

  • $C$: Number of replenishment cycles
  • $P$: $\mathit{SlashMeterReplenishPeriod}$
  • $F$: $\mathit{SlashMeterReplenishFraction}$
  • $V_{\mathit{max}}$: Max power of a validator as a fraction of total voting power

In $C$ number of replenishment cycles, the fraction of total voting power that can be removed, $a$, is $a \leq F \cdot C + V{\mathit{max}}$ (where $V{\mathit{max}}$ is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value).

So, we need at least $C \geq \frac{a - V_{\mathit{max}}}{F}$ cycles to remove $a$ fraction of the total voting power.

Since we defined the start of the attack to be the moment when the first slash request arrives, then $F$ fraction of the initial validator set can be jailed immediately. For the remaining $X - F$ fraction of the initial validator set to be jailed, it takes at least $C \geq \frac{(X - F) - V{\mathit{max}}}{F}$ cycles. Using the assumption that $V{\mathit{max}} \leq F$ (assumption 2), we get $C \geq \frac{X - 2F}{F}$ cycles.

In order to execute $C$ cycles, we need $C \cdot P$ time.

Thus, jailing the remaining $X - F$ fraction of the initial validator set corresponds to $\frac{P \cdot (X - 2F)}{F}$ time.

In other words, the attack must take at least $\frac{P \cdot X}{F} - 2P$ time (in the units of replenish period $P$).

This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests. +For example, if SlashMeterReplenishFraction is set to 0.06, then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub. +Note that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power.

Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings.

How Unjailing Affects the Main Throttling Property

Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained.

If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider.

In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack.

Consequences

Positive

  • The described attack is slowed down in seemingly all cases.
  • If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded.

Negative

  • Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below. +However, this is sacrificing liveness in a edge case scenario for the sake of security. +As an improvement, using retries would fully prevent this attack vector.

Neutral

  • Additional state is introduced to the provider chain.
  • VSCMatured and slash packet data is not always handled in the same block that it is received.

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-002-throttle.html.html b/legacy/v3.3.0/adrs/adr-002-throttle.html.html new file mode 100644 index 0000000000..137833e7ad --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-002-throttle.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-003-equivocation-gov-proposal.html b/legacy/v3.3.0/adrs/adr-003-equivocation-gov-proposal.html new file mode 100644 index 0000000000..49a384f306 --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-003-equivocation-gov-proposal.html @@ -0,0 +1,19 @@ + + + + + +Equivocation governance proposal | Interchain Security + + + + +
+
Version: v3.3.0

ADR 003: Equivocation governance proposal

Changelog

  • 2023-02-06: Initial draft

Status

Accepted

Context

We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain.

For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence.

Decision

To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain.

A new kind of governance proposal is added to the provider module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain.

If such proposal passes, the proposal handler delegates to the evidence module to process the equivocation. This module ensures the evidence isn’t too old, or else ignores it (see code). Too old is determined by 2 consensus params :

  • evidence.max_age_duration number of nanoseconds before an evidence is considered too old
  • evidence.max_age_numblocks number of blocks before an evidence is considered too old.

On the hub, those parameters are equals to

// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682
(...)
"evidence": {
"max_age_num_blocks": "1000000",
"max_age_duration": "172800000000000",
(...)
},
(...)

A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the evidence module when the proposal passes and is handled by the hub.

For max_age_num_blocks=1M, the parameter is big enough if we consider the hub produces 12k blocks per day (blocks_per_year/365 = 436,0000/365). The evidence can be up to 83 days old (1,000,000/12,000) and not be ignored.

For max_age_duration=172,800,000,000,000, the parameter is too low, because the value is in nanoseconds so it’s 2 days. Fortunately the condition that checks those 2 parameters uses a AND, so if max_age_num_blocks condition passes, the evidence won’t be ignored.

Consequences

Positive

  • Remove the possibility from a malicious consumer chain to “attack” the provider chain by slashing/jailing validators.
  • Provide a more acceptable implementation for the validator community.

Negative

  • Punishment action of double-signing isn’t “automated”, a governance proposal is required which takes more time.
  • You need to pay 250ATOM to submit an equivocation evidence.

Neutral

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-003-equivocation-gov-proposal.html.html b/legacy/v3.3.0/adrs/adr-003-equivocation-gov-proposal.html.html new file mode 100644 index 0000000000..cc5048a04a --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-003-equivocation-gov-proposal.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-005-cryptographic-equivocation-verification.html b/legacy/v3.3.0/adrs/adr-005-cryptographic-equivocation-verification.html new file mode 100644 index 0000000000..6311a5bcef --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-005-cryptographic-equivocation-verification.html @@ -0,0 +1,85 @@ + + + + + +Cryptographic verification of equivocation evidence | Interchain Security + + + + +
+
Version: v3.3.0

ADR 005: Cryptographic verification of equivocation evidence

Changelog

  • 5/1/2023: First draft
  • 7/23/2023: Add light client attacks handling
  • 9/6/2023: Add double signing attacks handling
  • 11/3/2023: Update limitations to clarify amnesia attacks are ignored

Status

Accepted

Context

Currently, we use a governance proposal to slash validators for equivocation (double signing and light client attacks). +Every proposal needs to go through a (two weeks) voting period before it can be approved. +Given a three-week unbonding period, this means that an equivocation proposal needs to be submitted within one week since the infraction occurred.

This ADR proposes a system to slash validators automatically for equivocation, immediately upon the provider chain's receipt of the evidence. Another thing to note is that we intend to introduce this system in stages, since even the partial ability to slash and/or tombstone is a strict improvement in security. +The feature is implemented in two parts, each with its dedicated endpoint. One endpoint handles light client attacks, while the other handles double signing attacks.

Light Client Attack

In a nutshell, the light client is a process that solely verifies a specific state machine's +consensus without executing the transactions. The light clients get new headers by querying +multiple nodes, called primary and witness nodes.

Light clients download new headers committed on chain from a primary. Headers can be verified in two ways: sequentially, +where the block height of headers is serial, or using skipping. This second verification method allows light clients to download headers +with nonconsecutive block height, where some intermediate headers are skipped (see Tendermint Light Client, Figure 1 and Figure 3). +Additionally, light clients are cross-checking new headers obtained from a primary with witnesses to ensure all nodes share the same state.

A light client attack occurs when a Byzantine validator sends invalid headers to a light client. +As the light client doesn't execute transactions, it can be deceived into trusting corrupted application state transitions. +For instance, if a light client receives header A from the primary and header B from a witness for the same block height H, +and both headers are successfully verified, it indicates a light client attack. +Note that in this case, either the primary or the witness or both are malicious.

The types of light client attacks are defined by analyzing the differences between the conflicting headers. +There are three types of light client attacks: lunatic attack, equivocation attack, and amnesia attack. +For details, see the CometBFT specification.

When a light client agent detects two conflicting headers, it will initially verify their traces (see cometBFT detector) using its primary and witness nodes. +If these headers pass successful verification, the Byzantine validators will be identified based on the header's commit signatures +and the type of light client attack. The agent will then transmit this information to its nodes using a LightClientAttackEvidence evidence to be eventually voted on and added to a block. +Note that from a light client agent perspective, it is not possible to establish whether a primary or a witness node, or both, are malicious. +Therefore, it will create and send two evidences: one against the primary (sent to the witness), and one against the witness (sent to the primary). +Both nodes will then verify it before broadcasting it and adding it to the evidence pool. +If an evidence is finally committed to a block, the chain's evidence module will execute it, resulting in the jailing and the slashing of the validators responsible for the light client attack.

Light clients are a core component of IBC. In the event of a light client attack, IBC relayers notify the affected chains by submitting an IBC misbehavior message. +A misbehavior message includes the conflicting headers that constitute a light client attack evidence. Upon receiving such a message, +a chain will first verify whether these headers would have convinced its light client. This verification is achieved by checking +the header states against the light client consensus states (see IBC misbehaviour handler). If the misbehaviour is successfully verified, the chain will then "freeze" the +light client, halting any further trust in or updating of its states.

Double Signing Attack

A double signing attack, also known as equivocation, +occurs when a validator votes for two different blocks in the same round of the CometBFT consensus. +This consensus mechanism operates with multiple voting rounds at each block height, +and it strictly prohibits sending two votes of the same type during a round +(see CometBFT State Machine Overview).

When a node observes two votes from the same peer, it will use these two votes to create +a DuplicateVoteEvidence +evidence and gossip it to the other nodes in the network +(see CometBFT equivocation detection). +Each node will then verify the evidence according to the CometBFT rules that define a valid double signing infraction, and based on this verification, they will decide whether to add the evidence to a block. +During the evidence verification process, the signatures of the conflicting votes must be verified successfully. +Note that this is achieved using the public key of the misbehaving validator, along with the chain ID of the chain where the infraction occurred (see CometBFT equivocation verification).

Once a double signing evidence is committed to a block, the consensus layer will report the equivocation to the evidence module of the Cosmos SDK application layer. +The application will, in turn, punish the malicious validator through jailing, tombstoning and slashing +(see handleEquivocationEvidence).

Decision

Light Client Attack

In the first part of the feature, we introduce a new endpoint: HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour). +The main idea is to leverage the current IBC misbehaviour handling and update it to solely jail and slash the validators that +performed a light client attack. Note that in this context, we assume that chains connected via a light client +share the same validator set, as is the case with Replicated Security.

This endpoint reuses the IBC client libraries to verify that the misbehaviour headers would have fooled the light client. +Additionally, it’s crucial that the endpoint logic results in the slashing and jailing of validators under the same conditions +as a light client agent detector. Therefore, the endpoint ensures that the two conditions are met: +the headers in the misbehaviour message have the same block height, and +the light client isn’t expired.

After having successfully verified a misbehaviour, the endpoint executes the jailing and slashing of the malicious validators similarly as in the evidence module.

Double Signing Attack

In the second part of the feature, we introduce a new endpoint HandleConsumerDoubleVoting( +ctx sdk.Context, evidence *tmtypes.DuplicateVoteEvidence, chainID string, pubkey cryptotypes.PubKey). +Simply put, the handling logic verifies a double signing evidence against a provided +public key and chain ID and, if successful, executes the jailing of the malicious validator who double voted.

We define a new +MsgSubmitConsumerDoubleVoting message to report a double voting evidence observed +on a consumer chain to the endpoint of the provider chain. This message contains two fields: +a double signing evidence +duplicate_vote_evidence and a light client header for the infraction block height, +referred to as infraction_block_header. +The latter provides the malicious validator's public key and the chain ID required to verify the signature of the votes contained in the evidence.

Note that double signing evidence is not verified using the same conditions as in the implementation CometBFT (see +verify(evidence types.Evidence) method). Specifically, we do not check that the evidence hasn't expired. +More details can be found in the "Current limitations" section below.

Upon a successful equivocation verification, the misbehaving validator is jailed for the maximum time +(see DoubleSignJailEndTime +in the SDK evidence module).

Current limitations:

  • We cannot derive an infraction height from the evidence, so it is only possible to jail validators, not actually slash them. +To explain the technical reasons behind this limitation, let's recap the initial consumer initiated slashing logic. +In a nutshell, consumer heights are mapped to provider heights through VSCPackets, namely through the so called vscIDs. +When an infraction occurs on the consumer, a SlashPacket containing the vscID obtained from mapping the consumer infraction height +is sent to the provider. Upon receiving the packet, the provider maps the consumer infraction height to a local infraction height, +which is used to slash the misbehaving validator. In the context of untrusted consumer chains, all their states, including vscIDs, +could be corrupted and therefore cannot be used for slashing purposes.

  • For the same reasons explained above, the age of a consumer double signing evidence can't be verified, +either using its infraction height or its unsigned timestamp. Note that changes the jailing behaviour, potentially leading to a validator's jailing based on some "old" evidence from a consumer, which wouldn't occur if the consumer were a standalone chain.

  • In the first stage of this feature, validators are jailed indefinitely without being tombstoned. +The underlying reason is that a malicious validator could take advantage of getting tombstoned +to avoid being slashed on the provider (see comment).

  • Currently, the endpoint can only handle equivocation light client attacks. This is because the lunatic attacks require the endpoint to possess the ability to dissociate which header is conflicted or trusted upon receiving a misbehavior message. Without this information, it's not possible to extract the Byzantine validators from the conflicting headers (see comment). In addition, "amnesia" attacks are ignored, similar to CometBFT (see ADR-056).

Consequences

Positive

  • It is now possible for the provider chain to jail validators who committed +light client or double signing attacks on a consumer chain.

Negative

  • N/A

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-005-cryptographic-equivocation-verification.html.html b/legacy/v3.3.0/adrs/adr-005-cryptographic-equivocation-verification.html.html new file mode 100644 index 0000000000..9727987049 --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-005-cryptographic-equivocation-verification.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html b/legacy/v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html new file mode 100644 index 0000000000..22118434e0 --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html @@ -0,0 +1,51 @@ + + + + + +ADR Template | Interchain Security + + + + +
+
Version: v3.3.0

ADR 007: Pause validator unbonding during equivocation proposal

Changelog

  • 2023-05-16: Initial Draft

Status

Proposed

Context

Currently, if an equivocation slashing proposal is created after more than one +week has passed since the equivocation, it is possible that the validator in +question could unbond and get away without being slashed, since the unbonding +period is 3 weeks, and the voting period is 2 weeks. For this reason, it might +be good to pause unbondings for validators named in an equivocation slashing +proposal until the proposal's voting period is over.

Decision

How

Pausing the unbonding period is already possible thanks to the changes in the +staking module of the cosmos-sdk:

  • stakingKeeper.PutUnbondingOnHold pauses an unbonding period
  • stakingKeeper.UnbondingCanComplete unpauses an unbonding period

These methods use a reference counter under the hood, that gets incremented +every time PutUnbondingOnHold is called, and decreased when +UnbondingCanComplete is called instead. A specific unbonding is considered +fully unpaused when its underlying reference counter reaches 0. Therefore, as +long as we safeguard consistency - i.e. we make sure we eventually decrement +the reference counter for each time we have incremented it - we can safely use +this existing mechanism without conflicts with the Completion of Unbonding +Operations system.

When pause

The unbonding period (if there is any unbonding) should be paused once an +equivocation proposal enters the voting period. For that, the gov module's +hook AfterProposalDeposit can be used.

If the hook is triggered with a an equivocation proposal in voting period, then +for each equivocation of the proposal, the unbonding operations of the related +validator that were initiated after the equivocation block time must be paused

  • i.e. the underlying reference counter has to be increased.

Note that even after the voting period has started, a proposal can receive +additional deposits. The hook is triggered however at arrival of a deposit, so +a check to verify that the proposal is not already in voting period is +required.

When unpause

We can use a gov module's hook also here and it is +AfterProposalVotingPeriodEnded.

If the hook is triggered with an equivocation proposal, then for each +associated equivocation, the unbonding operations of the related validator that +were initiated between the equivocation block time and the start of the +proposal voting period must be unpaused - i.e. decrease the underlying +reference counter - regardless of the proposal outcome.

Consequences

Positive

  • Validators subject to an equivocation proposal cannot finish unbonding +their tokens before the end of the voting period.

Negative

  • A malicious consumer chain could forge slash packets enabling submission of +an equivocation proposal on the provider chain, resulting in the freezing of +validator's unbondings for an undeterminated amount of time.
  • Misbehavior on a consumer chain can potentially go unpunished, if no one +submits an equivocation proposal in time, or if the proposal doesn't pass.

Neutral

  • This feature can't be used for social slashing, because an equivocation +proposal is only accepted if there's a slash log for the related +validator(s), meaning the consumer chain has reported the equivocation to +the provider chain.

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html b/legacy/v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html new file mode 100644 index 0000000000..6ce06a1c2f --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-008-throttle-retries.html b/legacy/v3.3.0/adrs/adr-008-throttle-retries.html new file mode 100644 index 0000000000..b4ea6b12cc --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-008-throttle-retries.html @@ -0,0 +1,47 @@ + + + + + +Throttle with retries | Interchain Security + + + + +
+
Version: v3.3.0

Throttle with retries

ADR 008: Throttle with retries

Changelog

  • 6/9/23: Initial draft
  • 6/22/23: added note on consumer pending packets storage optimization
  • 7/14/23: Added note on upgrade order

Status

Accepted

Context

For context on why the throttling mechanism exists, see ADR 002.

Note the terms slash throttling and jail throttling are synonymous, since in replicated security a SlashPacket simply jails a validator for downtime infractions.

Currently the throttling mechanism is designed so that provider logic (slash meter, etc.) dictates how many SlashPackets can be handled over time. +Throttled SlashPackets are persisted on the provider, leading to multiple possible issues. Namely:

  • If SlashPackets or VSCMaturedPackets are actually throttled/queued on the provider, state can grow and potentially lead to a DoS attack. +We have short term solutions around this, but overall they come with their own weaknesses. +See #594.
  • If a jailing attack described in ADR 002 were actually to be carried out with the current throttling design, we'd likely have to halt the provider, and perform an emergency upgrade and/or migration to clear the queues of SlashPackets that were deemed to be malicious. +Alternatively, validators would just have to tough it out and wait for the queues to clear, during which all/most validators would be jailed. +Right after being jailed, validators would have to unjail themselves promptly to ensure safety. +The coordination required to maintain safety in such a scenario is not ideal.

As as solution, we can improve the throttling mechanism to instead queue/persist relevant data on each consumer, and have consumers retry slash requests as needed.

Decision

Consumer changes

Note the consumer already queues up both SlashPackets and VSCMaturedPackets via AppendPendingPacket. +Those packets are dequeued in every EndBlock in SendPackets and sent to the provider.

Instead, we will now introduce the following logic on EndBlock:

  • Slash packets will always be sent to the provider once they're at the head of the queue. +However, once sent, the consumer will not send any subsequent VSCMaturedPackets from the queue until the provider responds with an acknowledgement that the sent SlashPacket has been handled, i.e., validator was jailed. +That is, SlashPackets block the sending of subsequent VSCMaturedPackets in the consumer queue.
  • If two SlashPackets are at the head of the queue, the consumer will send the first SlashPacket, and then wait for a success acknowledgement from the provider before sending the second SlashPacket. +This seems like it'd simplify implementation.
  • VSCMaturedPackets at the head of the queue (i.e., NOT following a SlashPacket) can be sent immediately, and do not block any other packets in the queue, since the provider always handles them immediately.

To prevent the provider from having to keep track of what SlashPackets have been rejected, the consumer will have to retry the sending of SlashPackets over some period of time. +This can be achieved with an on-chain consumer param, i.e., RetryDelayPeriod. +To reduce the amount of redundant re-sends, we recommend setting RetryDelayPeriod ~ SlashMeterReplenishmentPeriod, i.e., waiting for the provider slash meter to be replenished before resending the rejected SlashPacket.

Note to prevent weird edge case behavior, a retry would not be attempted until either a success or failure acknowledgement has been received from the provider.

With the behavior described, we maintain very similar behavior to the previous throttling mechanism regarding the timing that SlashPackets and VSCMaturedPackets are handled on the provider. +Obviously the queueing and blocking logic is moved, and the two chains would have to send more messages between one another (only in the case the throttling mechanism is triggered).

In the normal case, when no or a few SlashPackets are being sent, the VSCMaturedPackets will not be delayed, and hence unbonding will not be delayed.

For the implementation of this design, see throttle_retry.go.

Consumer pending packets storage optimization

In addition to the mentioned consumer changes, an optimization will need to be made to the consumer's pending packets storage to properly implement the feature from this ADR.

The consumer ccv module previously queued "pending packets" to be sent in each EndBlock in SendPackets. +These packets are queued in state with a protobuf list of ConsumerPacketData. +For a single append operation, the entire list is deserialized, then a packet is appended to that list, and the list is serialized again. +See older version of AppendPendingPacket. +That is, a single append operation has O(N) complexity, where N is the size of the list.

This poor append performance isn't a problem when the pending packets list is small. +But with this ADR being implemented, the pending packets list could potentially grow to the order of thousands of entries when SlashPackets need to be resent.

We can improve the append time for this queue by converting it from a protobuf-esq list, to a queue implemented with sdk-esq code. +The idea is to persist an uint64 index that will be incremented each time you queue up a packet. +You can think of this as storing the tail of the queue. +Then, packet data will be keyed by that index, making the data naturally ordered byte-wise for sdk's iterator. +The index will also be stored in the packet data value bytes, so that the index can later be used to delete certain packets from the queue.

Two things are achieved with this approach:

  • More efficient packet append/enqueue times
  • The ability to delete select packets from the queue (previously all packets were deleted at once)

Provider changes

The main change needed for the provider is the removal of queuing logic for SlashPackets and VSCMaturedPackets upon being received.

Instead, the provider will consult the slash meter to determine if a SlashPacket can be handled immediately. +If not, the provider will return an acknowledgement message to the consumer communicating that the SlashPacket could not be handled, and needs to be sent again in the future (retried).

VSCMaturedPackets will always be handled immediately upon being received by the provider.

Note spec. Specifically the section on VSC Maturity and Slashing Order. Previously the onus was on the provider to maintain this property via queuing packets and handling them FIFO.

Now this property will be maintained by the consumer sending packets in the correct order, and blocking the sending of VSCMaturedPackets as needed. Then, the ordered IBC channel will ensure that SlashPackets and VSCMaturedPackets are received in the correct order on the provider.

The provider's main responsibility regarding throttling will now be to determine if a received SlashPacket can be handled via slash meter etc., and appropriately acknowledge to the sending consumer.

Handling VSCMaturedPackets immediately

Why the provider can handle VSCMatured packets immediately

A VSCMaturedPacket communicates to the provider that sufficient time passed on the consumer since the corresponding VSCPacket has been applied (on the consumer) such that infractions committed on the consumer could have been submitted.

If the consumer is following the queuing/blocking protocol described, then no bad behavior occurs and the VSC Maturity and Slashing Order property is maintained.

If a consumer sends VSCMaturedPackets too leniently -- the consumer is malicious and sends duplicate VSCMaturedPackets, or sends the packets sooner than the CCV protocol specifies -- then the provider needs to handle VSCMaturedPackets immediately to prevent DOS, state bloat, or other issues. +The only possible negative outcome is that the malicious consumer may not be able to jail a validator who should have been jailed. +The malicious behavior only creates a negative outcome for the consumer chain that is being malicious.

If a consumer blocks the sending of VSCMaturedPackets, then unbonding operations on the provider will be delayed, but only until the VSC timeout period has elapsed. +At that time, the consumer is removed. +Again the malicious behavior only creates a negative outcome for the consumer chain that is being malicious.

Splitting of PRs and Upgrade Order

This feature will implement consumer changes in #1024.

These changes should be deployed to production for all consumers before the provider changes are deployed to production.

In other words, the consumer changes in #1024 are compatible with the current ("v1") provider implementation of throttling that's running on the Cosmos Hub as of July 2023.

Once all consumers have deployed the changes in #1024, the provider changes from #1321 can be deployed to production, fully enabling v2 throttling.

Consequences

  • Consumers will now have to manage their own queues, and retry logic.
  • Consumers still aren't trustless, but the provider is now less susceptible to mismanaged or malicious consumers.
  • Recovering from the "jailing attack" is more elegant.
  • Some issues like #1001 will now be handled implicitly by the improved throttling mechanism.
  • SlashPackets and VSCMaturedPackets can be handled immediately once received by the provider if the slash meter allows.
  • In general, we reduce the amount of computation that happens in the provider EndBlock.

Positive

  • We no longer have to reason about a "global queue" and a "chain specific queue", and keeping those all in-sync. +Now SlashPackets and VSCMaturedPackets queuing is handled on each consumer individually.
  • Due to the above, the throttling protocol becomes less complex overall.
  • We no longer have to worry about throttle related DoS attack on the provider, since no queuing exists on the provider.

Negative

  • Increased number of IBC packets being relayed anytime throttling logic is triggered.
  • Consumer complexity increases, since consumers now have manage queuing themselves, and implement packet retry logic.

Neutral

  • Core throttling logic on the provider remains unchanged, i.e., slash meter, replenishment cycles, etc.

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-008-throttle-retries.html.html b/legacy/v3.3.0/adrs/adr-008-throttle-retries.html.html new file mode 100644 index 0000000000..0e915ea5c5 --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-008-throttle-retries.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-009-soft-opt-out.html b/legacy/v3.3.0/adrs/adr-009-soft-opt-out.html new file mode 100644 index 0000000000..5e8b202bbc --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-009-soft-opt-out.html @@ -0,0 +1,19 @@ + + + + + +Soft Opt-Out | Interchain Security + + + + +
+
Version: v3.3.0

Soft Opt-Out

ADR 009: Soft Opt-Out

Changelog

  • 6/13/23: Initial draft of ADR. Feature already implemented and in production.

Status

Accepted

Context

Some small validators may not have the resources needed to validate all consumer chains. Therefore a need exists to allow the bottom x% of validators to opt-out of validating a consumer chain. Meaning downtime infractions for these validators are dropped without ever reaching the provider.

This document specifies a modification to the ccv protocol which allows the bottom x% of the validator set by power to opt out of validating consumer chains without being jailed or otherwise punished for it. The feature is implemented with entirely consumer-side code.

Decision

A consumer param exists, known as SoftOptOutThreshold, which is a string decimal in the range of [0, 0.2], that determines the portion of validators which are allowed to opt out of validating that specific consumer.

In every consumer beginblocker, a function is ran which determines the so called smallest non opt-out voting power. Validators with voting power greater than or equal to this value must validate the consumer chain, while validators below this value may opt out of validating the consumer chain.

The smallest non opt-out voting power is recomputed every beginblocker in UpdateSmallestNonOptOutPower(). In a nutshell, the method obtains the total voting power of the consumer, iterates through the full valset (ordered power ascending) keeping track of a power sum, and when powerSum / totalPower > SoftOptOutThreshold, the SmallestNonOptOutPower is found and persisted.

Then, whenever the Slash() interface is executed on the consumer, if the voting power of the relevant validator being slashed is less than SmallestNonOptOutPower for that block, the slash request is dropped and never sent to the provider.

Consequences

Positive

  • Small validators can opt out of validating specific consumers without being punished for it.

Negative

  • The bottom x% is still part of the total voting power of the consumer chain. This means that if the soft opt-out threshold is set to 10% for example, and every validator in the bottom 10% opts out from validating the consumer, then a 24% downtime of the remaining voting power would halt the chain. This may be especially problematic during consumer upgrades.
  • In nominal scenarios, consumers with soft opt out enabled will be constructing slash packets for small vals, which may be dropped. This is wasted computation, but necessary to keep implementation simple. Note that the sdk's full downtime logic is always executed on the consumer, which can be computationally expensive and slow down certain blocks.

Neutral

  • Validators in the bottom of the valset who don't have to validate, may receive large delegation(s) which suddenly boost the validator to the subset that has to validate. This may catch the validator off guard.

References

  • Original issue with some napkin math #784
+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-009-soft-opt-out.html.html b/legacy/v3.3.0/adrs/adr-009-soft-opt-out.html.html new file mode 100644 index 0000000000..053275b3d6 --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-009-soft-opt-out.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-010-standalone-changeover.html b/legacy/v3.3.0/adrs/adr-010-standalone-changeover.html new file mode 100644 index 0000000000..599ba16849 --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-010-standalone-changeover.html @@ -0,0 +1,19 @@ + + + + + +Standalone to Consumer Changeover | Interchain Security + + + + +
+
Version: v3.3.0

Standalone to Consumer Changeover

ADR 010: Standalone to Consumer Changeover

Changelog

  • 6/30/23: Feature completed, first draft of ADR.

Status

Implemented

Context

Stride will be the first consumer to "changeover" from a standalone cosmos blockchain, to a consumer chain secured by the Cosmos Hub. This document will outline the changes made to the replicated security protocol to support this changeover process.

Decision

Process

Prior to the changeover, the consumer chain will have an existing staking keeper and validator set, these may be referred to as the "standalone staking keeper" and "standalone validator set" respectively.

The first step in the changeover process is to submit a ConsumerAdditionProposal. If the proposal passes, the provider will create a new IBC client for the consumer at spawn time, with the provider's validator set. A consumer genesis will also be constructed by the provider for validators to query. Within this consumer genesis contains the initial validator set for the consumer to apply after the changeover.

Next, the standalone consumer chain runs an upgrade which adds the CCV module, and is properly setup to execute changeover logic.

The consumer upgrade height must be reached after the provider has created the new IBC client. Any replicated security validators who will run the consumer, but are not a part of the sovereign validator set, must sync up a full node before the consumer upgrade height is reached. The disc state of said full node will be used to run the consumer chain after the changeover has completed.

The meat of the changeover logic is that the consumer chain validator set is updated to that which was specified by the provider via the queried consumer genesis. Validators which were a part of the old set, but not the new set, are given zero voting power. Once these validator updates are given to Comet, the set is committed, and in effect 2 blocks later (see FirstConsumerHeight).

A relayer then establishes the new IBC connection between the provider and consumer. The CCV channel handshake is started on top of this connection. Once the CCV channel is established and VSC packets are being relayed, the consumer chain is secured by the provider.

Changes to CCV Protocol

  • Consumer Genesis state is updated to include a PreCCV boolean. When this boolean is set true in the consumer genesis JSON, special logic is executed on InitGenesis to trigger the changeover process on the consumer's first endblocker after the upgrade which adds the CCV module. Note that InitGenesis is not automatically called during chain upgrades, so the consumer must manually call the consumer's InitGenesis method in an upgrade handler.
  • The ConsumerAdditionProposal type is updated to include a DistributionTransmissionChannel field. This field allows the consumer to use an existing IBC transfer channel to send rewards as a part of the CCV protocol. Consumers that're not changing over from a standalone chain will leave this field blank, indicating that a new transfer channel should be created on top of the same connection as the CCV channel.
  • The CCV consumer keeper is updated to contain an optional reference to the standalone staking keeper. The standalone staking keeper is used to slash for infractions that happened before the changeover was completed. Ie. any infraction from a block height before the changeover, that is submitted after the changeover, will call the standalone staking keeper's slash method. Note that a changeover consumer's standalone staking keeper becomes a democracy module keeper, so it is possible for a governance token to be slashed.

Consequences

Positive

  • Existing cosmos chains are now able to onboard over to a consumer chain secured by a provider.
  • The previous staking keepers for such chains can be transitioned to democracy staking module keepers.

Negative

  • The delineation between different types of consumers in this repo becomes less clear. Ie. there is code in the democracy consumer's app.go that only applies to a previously standalone chain, but that file also serves as the base for a normal democracy consumer launched with RS from genesis.

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-010-standalone-changeover.html.html b/legacy/v3.3.0/adrs/adr-010-standalone-changeover.html.html new file mode 100644 index 0000000000..4a532b04de --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-010-standalone-changeover.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-011-improving-test-confidence.html b/legacy/v3.3.0/adrs/adr-011-improving-test-confidence.html new file mode 100644 index 0000000000..1ef207da9c --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-011-improving-test-confidence.html @@ -0,0 +1,29 @@ + + + + + +Improving testing and increasing confidence | Interchain Security + + + + +
+
Version: v3.3.0

ADR 11: Improving testing and increasing confidence

Changelog

  • 2023-08-11: Proposed, first draft of ADR.

Status

Proposed

Context

Testing, QA, and maintenance of interchain-security libraries is an ever-evolving area of software engineering we have to keep incrementally improving. The purpose of the QA process is to catch bugs as early as possible. In an ideal development workflow a bug should never reach production. A bug found in the specification stage is a lot cheaper to resolve than a bug discovered in production (or even in testnet). Ideally, all bugs should be found during the CI execution, and we hope that no bugs will ever even reach the testnet (although nothing can replace actual system stress test under load interacting with users).

During development and testnet operation the following types of bugs were the most commonly found:

  • improper iterator usage
  • unbounded array access/iteration
  • improper input handling and validation
  • improper cached context usage
  • non-determinism check (improper use of maps in go, relying on random values)
  • KV store management and/or how keys are defined
  • deserialization issues arising from consumer/provider versioning mismatch

Such bugs can be discovered earlier with better tooling. Some of these bugs can induce increases in block times, chain halts, state corruption, or introduce an attack surface which is difficult to remove if other systems have started depending on that behavior.

Current state of testing

Our testing suites consist of multiple parts, each with their own trade-offs and benefits with regards to code coverage, complexity and confidence they provide.

Unit testing

Unit testing is employed mostly for testing single-module functionality. It is the first step in testing and often the most practical. While highly important, unit tests often test a single piece of code and don't test relationships between different moving parts, this makes them less valuable when dealing with multi-module interactions.

Unit tests often employ mocks to abstract parts of the system that are not under test. Mocks are not equivalent to actual models and should not be treated as such.

Out of all the approaches used, unit testing has the most tools available and the coverage can simply be displayed as % of code lines tested. Although this is a very nice and very easy to understand metric, it does not speak about the quality of the test coverage.

Since distributed systems testing is a lot more involved, unit tests are oftentimes not sufficient to cover complex interactions. Unit tests are still necessary and helpful, but in cases where unit tests are not helpful e2e or integration tests should be favored.

Integration testing

With integration testing we test the multi-module interactions while isolating them from the remainder of the system. +Integration tests can uncover bugs that are often missed by unit tests.

It is very difficult to gauge the actual test coverage imparted by integration tests and the available tooling is limited. +In interchain-security we employ the ibc-go/testing framework to test interactions in-memory.

At present, integration testing does not involve the consensus layer - it is only concerned with application level state and logic.

End-to-end testing

In our context end-to-end testing comprises of tests that use the actual application binaries in an isolated environment (e.g. docker container). During test execution the inputs are meant to simulate actual user interaction, either by submitting transactions/queries using the command line or using gRPC/REST APIs and checking for state changes after an action has been performed. With this testing strategy we also include the consensus layer in all of our runs. This is the closest we can get to testing user interactions without starting a full testnet.

End-to-end testing strategies vary between different teams and projects and we strive to unify our approach to the best of our ability (at least for ICS and gaia).

The available tooling does not give us significant (or relevant) line of code coverage information since most of the tools are geared towards analyzing unit tests and simple code branch evaluation.

We aim to adapt our best practices by learning from other similar systems and projects such as cosmos-sdk, ibc-go and CometBFT.

Decision

1. Connect specifications to code and tooling

Oftentimes, specifications are disconnected from the development and QA processes. This gives rise to problems where the specification does not reflect the actual state of the system and vice-versa. +Usually specifications are just text files that are rarely used and go unmaintained after a while, resulting in consistency issues and misleading instructions/expectations about system behavior.

Decision context and hypothesis

Specifications written in a dedicated and executable specification language are easier to maintain than the ones written entirely in text. +Additionally, we can create models based on the specification OR make the model equivalent to a specification.

Models do not care about the intricacies of implementation and neither do specifications. Since both models and specifications care about concisely and accurately describing a system (such as a finite state machine), we see a benefit of adding model based tools (such as quint) to our testing and development workflows.

Main benefit

MBT tooling can be used to generate test traces that can be executed by multiple different testing setups.

2. Improve e2e tooling

Matrix tests

Instead of only running tests against current main branch we should adopt an approach where we also:

  • run regression tests against different released software versions (ICS v1 vs v2 vs v3)
  • run non-determinism tests to uncover issues quickly

Matrix tests can be implemented using CometMock and refactoring our current e2e CI setup.

Introducing e2e regression testing

This e2e test suite would execute using a cronjob in our CI (nightly, multiple times a day etc.)

Briefly, the same set of traces is run against different maintained versions of the software and the main branch. +This would allow us to discover potential issues during development instead of in a testnet scenarios.

The most valuable issues that can be discovered in this way are state breaking changes, regressions and version incompatibilities.

The setup is illustrated by the image below. +e2e matrix tests

This table explains which versions are tested against each other for the same set of test traces:

  • ✅ marks a passing test
  • ❌ marks a failing test
USES: ICS v1 PROVIDERstart chainadd keydelegateundelegateredelegatedowntimeequivocationstop chain
v1 consumer (sdk45,ibc4.3)
v2 consumer (sdk45, ibc4.4)
v3 consumer (sdk47, ibc7)
main consumer
neutron
stride

Introducing e2e CometMock tests

CometMock is a mock implementation of the CometBFT consensus engine. It supports most operations performed by CometBFT while also being lightweight and relatively easy to use.

CometMock tests allow more nuanced control of test scenarios because CometMock can "fool" the blockchain app into thinking that a certain number of blocks had passed. +This allows us to test very nuanced scenarios, difficult edge cases and long-running operations (such as unbonding operations).

Examples of tests made easier with CometMock are listed below:

  • regression tests
  • non-determinism tests
  • upgrade tests
  • state-breaking changes

With CometMock, the matrix test approach can also be used. The image below illustrates a CometMock setup that can be used to discover non-deterministic behavior and state-breaking changes. +e2e matrix tests

This table explains which versions are tested against each other for the same set of test traces:

  • ✅ marks a passing test
  • ❌ marks a failing test
SCENARIOstart chainadd keydelegateundelegateredelegatedowntimeequivocationstop chain
v3 provi + v3 consu
main provi + main consu
commit provi + commit consu

Briefly; multiple versions of the application are run against the same CometMock instance and any deviations in app behavior would result in app hash errors (the apps would be in different states after performing the same set of actions).

3. Introduce innovative testing approaches

When discussing e2e testing, some very important patterns emerge - especially if test traces are used instead of ad-hoc tests written by hand.

We see a unique opportunity to clearly identify concerns and modularize the testing architecture.

The e2e testing frameworks can be split into a pipeline consisting of 3 parts: model, driver and harness.

Model

Model is the part of the system that can emulate the behavior of the system under test. +Ideally, it is very close to the specification and is written in a specification language such as quint, TLA+ or similar. +One of the purposes of the model is that it can be used to generate test traces.

Driver

The purpose of the driver is to accept test traces (generated by the model or written by hand), process them and provide inputs to the next part of the pipeline.

Basically, the driver sits between the model and the actual infrastructure on which the test traces are being executed on.

Harness

Harness is the infrastructure layer of the pipeline that accepts inputs from the driver.

There can be multiple harnesses as long as they can perform four things:

  • bootstrap a test execution environment (local, docker, k8s…)
  • accept inputs from drivers
  • perform the action specified by the driver
  • report results after performing actions

Consequences

The procedure outlined in this ADR is not an all-or-nothing approach. Concepts introduced here do not rely on each other, so this ADR may only be applied partially without negative impact on test coverage and code confidence.

Positive

  1. introduction of maintainable MBT solutions
  • improvement over the current "difftest" setup that relies on an opinionated typescript model and go driver
  1. increased code coverage and confidence
  • using CometMock allows us to run more tests in less time
  • adding matrix e2e tests allows us to quickly pinpoint differences between code versions

Negative

It might be easier to forgo the MBT tooling and instead focus on pure property based testing

The solutions are potentially expensive if we increase usage of the CI pipeline - this is fixed by running "expensive" tests using a cronjob, instead of running them on every commit.

Neutral

The process of changing development and testing process is not something that can be thought of and delivered quickly. Luckily, the changes can be rolled out incrementally without impacting existing workflows.

References

Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-011-improving-test-confidence.html.html b/legacy/v3.3.0/adrs/adr-011-improving-test-confidence.html.html new file mode 100644 index 0000000000..0d9502d82f --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-011-improving-test-confidence.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-012-separate-releasing.html b/legacy/v3.3.0/adrs/adr-012-separate-releasing.html new file mode 100644 index 0000000000..426c0a756a --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-012-separate-releasing.html @@ -0,0 +1,23 @@ + + + + + +Separate Releasing | Interchain Security + + + + +
+
Version: v3.3.0

ADR 012: Separate Releasing

Changelog

  • {8/18/22}: Initial draft of idea in #801
  • {8/22/22}: Put idea in this ADR
  • {11/10/22}: Reject this ADR

Status

Rejected

Context

Spike results

I explored the idea of #801 with this spike branch. Here's my conclusions:

Splitting this repo to have multiple go.mods is possible. However there are various intricacies involved in decoupling the package hierarchy to have x/ccv/types as the lowest level dep, with x/ccv/consumer and x/ccv/provider being one dep layer above, with high-level tests depending on all three of the mentioned packages. I'd estimate this decoupling would take 2-5 workdays to finish, and require significant review effort.

Why go.mod split is not the way to go

Let's take a step back and remember the issue we're trying to solve - We need a clean way to decouple semver/releasing for the consumer and provider modules. After more consideration, splitting up go.mods gives us little benefit in achieving this. Reasons:

  • The go.mod dependency system is tied to git tags for the entire repo (ex: require github.com/cometbft/cometbft v0.37.2 refers to a historical tag for the entire cometbft repo).
  • It'd be an odd dev experience to allow modules to reference past releases of other modules in the same repo. When would we ever want the consumer module to reference a past release of the types module for example?
  • If we allow for go.mod replace statements to build from local source code, why split up the package deps at all?
  • Splitting go.mods adds a bunch of complexity with go.work files and all that shiz. VSCode does not play well with multiple module repos either.

Why separate repos is cool but also not the way to go

All this considered, the cleanest solution to decoupling semver/releasing for the consumer and provider modules would be to have multiple repos, each with their own go.mod (3-4 repos total including high level tests). With this scheme we could separately tag each repo as changes are merged, they could share some code from types being an external dep, etc.

I don't think any of us want to split up the monorepo, that's a lot of work and seems like bikeshedding. There's another solution that's very simple..

Decision

Slightly adapting the current semver ruleset:

  • A library API breaking change to EITHER the provider or consumer module will result in an increase of the MAJOR version number for BOTH modules (X.y.z-provider AND X.y.z-consumer).
  • A state breaking change (change requiring coordinated upgrade and/or state migration) will result in an increase of the MINOR version number for the AFFECTED module(s) (x.Y.z-provider AND/OR x.Y.z-consumer).
  • Any other changes (including node API breaking changes) will result in an increase of the PATCH version number for the AFFECTED module(s) (x.y.Z-provider AND/OR x.y.Z-consumer).

Example release flow

We upgrade main to use a new version of SDK. This is a major version bump, triggering a new release for both the provider and consumer modules, v5.0.0-provider and v5.0.0-consumer.

  • A state breaking change is merged to main for the provider module. We release only a v5.1.0-provider off main.
  • Another state breaking change is merged to main for the provider module. We release only a v5.2.0-provider off main.
  • At this point, the latest consumer version is still v5.0.0-consumer. We now merge a state breaking change for the consumer module to main, and consequently release v5.1.0-consumer. Note that v5.1.0-consumer is tagged off a LATER commit from main than v5.2.0-provider. This is fine, as the consumer module should not be affected by the provider module's state breaking changes.
  • Once either module sees a library API breaking change, we bump the major version for both modules. For example, we merge a library API breaking change to main for the provider module. We release v6.0.0-provider and v6.0.0-consumer off main. Note that most often, a library API breaking change will affect both modules simultaneously (example being bumping sdk version).

Consequences

Positive

  • Consumer repos have clear communication of what tagged versions are relevant to them. Consumer devs should know to never reference an ICS version that starts with provider, even if it'd technically build.
  • Consumer and provider modules do not deviate as long as we continually release off a shared main branch. Backporting remains relatively unchanged besides being explicit about what module(s) your changes should affect.
  • No code changes, just changes in process. Very simple.

Negative

  • Slightly more complexity.Considerably more complex to manage the ICS library. +This is because ICS needs to support multiple versions of SDK (e.g., 0.45, 0.47, 0.50). +In addition, ICS needs to support a special fork of SDK (with LSM included) for the Cosmos Hub. +This means that instead of focusing on main the development team needs to manage multiple release +branches with different dependency trees.
  • This solution does not allow having provider and consumer on separate versions of e.g. the Cosmos SDK.

Neutral

References

Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-012-separate-releasing.html.html b/legacy/v3.3.0/adrs/adr-012-separate-releasing.html.html new file mode 100644 index 0000000000..adef243b8b --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-012-separate-releasing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-013-equivocation-slashing.html b/legacy/v3.3.0/adrs/adr-013-equivocation-slashing.html new file mode 100644 index 0000000000..1b9032b388 --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-013-equivocation-slashing.html @@ -0,0 +1,39 @@ + + + + + +Slashing on the provider for consumer equivocation | Interchain Security + + + + +
+
Version: v3.3.0

ADR 013: Slashing on the provider for consumer equivocation

Changelog

  • 1st Sept. 2023: Initial draft

Status

Proposed

Context

This ADR presents some approaches on how to slash on the provider chain validators that performed equivocations on consumer chains. +Currently, the provider chain can receive and verify evidence of equivocation, but it cannot slash the misbehaving validator.

In the remainder of this section, we explain how slashing is performed on a single chain and show why slashing on the provider for equivocation on the consumer is challenging.

Note that future versions of the Cosmos SDK, CometBFT, and ibc-go could modify the way we slash, etc. Therefore, a future reader of this ADR, should note that when we refer to Cosmos SDK, CometBFT, and ibc-go we specifically refer to their v0.47, v0.37 and v7.3.0 versions respectively.

Single-chain slashing

Slashing is implemented across the slashing +and staking modules. +The slashing module's keeper calls the staking module's Slash() method, passing among others, the infractionHeight (i.e., the height when the equivocation occurred), the validator's power at the infraction height, and the slashFactor (currently set to 5% in case of equivocation on the Cosmos Hub).

Slashing undelegations and redelegations

To slash undelegations, Slash goes through all undelegations and checks whether they started before or after the infraction occurred. If an undelegation started before the infractionHeight, then it is not slashed, otherwise it is slashed by slashFactor.

The slashing of redelegations happens in a similar way, meaning that Slash goes through all redelegations and checks whether the redelegations started before or after the infractionHeight.

Slashing delegations

Besides undelegations and redelegations, the validator's delegations need to also be slashed. +This is performed by deducting the appropriate amount of tokens from the validator. Note that this deduction is computed based on the voting power the misbehaving validator had at the height of the equivocation. As a result of the tokens deduction, +the tokens per share +reduce and hence later on, when delegators undelegate or redelegate, the delegators retrieve back less +tokens, effectively having their tokens slashed. The rationale behind this slashing mechanism, as mentioned in the Cosmos SDK documentation

[...] is to simplify the accounting around slashing. Rather than iteratively slashing the tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, effectively reducing the value of each issued delegator share.

This approach of slashing delegations does not utilize the +infractionHeight in any way and hence the following scenario could occur:

  1. a validator V performs an equivocation at a height Hi
  2. a new delegator D delegates to V after height Hi
  3. evidence of the equivocation by validator V is received
  4. the tokens of delegator D are slashed

In the above scenario, delegator D is slashed, even though D's voting power did not contribute to the infraction.

Old evidence

In the single-chain case, old evidence (e.g., from 3 years ago) is ignored. This is achieved through +CometBFT that ignores old evidence based on the parameters MaxAgeNumBlocks and MaxAgeDuration (see here). +Additionally, note that when the evidence is sent by CometBFT to the application, the evidence is rechecked in the evidence module of Cosmos SDK and if it is old, the evidence is ignored. +In Cosmos Hub, the MaxAgeNumBlocks is set to 1000000 (i.e., ~70 days if we assume we need ~6 sec per block) and MaxAgeDuration is set to 172800000000000 ns (i.e., 2 days). Because of this check, we can easily exclude old evidence.

Slashing for equivocation on the consumer

In the single-chain case, slashing requires both the infractionHeight and the voting power. +In order to slash on the provider for an equivocation on a consumer, we need to have both the provider's infractionHeight and voting power. +Note that the infractionHeight on the consumer chain must be mapped to a height on the provider chain. +Unless we have a way to find the corresponding infractionHeight and power on the provider chain, we cannot slash for equivocation on the consumer in the same way as we would slash in the single-chain case.

The challenge of figuring out the corresponding infractionHeight and power values on the provider chain is due to the following trust assumption:

  • We trust the consensus layer and validator set of the consumer chains, but we do not trust the application layer.

As a result, we cannot trust anything that stems from the application state of a consumer chain.

Note that when a relayer or a user sends evidence through a MsgSubmitConsumerDoubleVoting message, the provider gets access to DuplicateVoteEvidence:

type DuplicateVoteEvidence struct {
VoteA *Vote `json:"vote_a"`
VoteB *Vote `json:"vote_b"`

// abci specific information
TotalVotingPower int64
ValidatorPower int64
Timestamp time.Time
}

The "abci specific information" fields cannot be trusted because they are not signed. Therefore, +we can use neither ValidatorPower for slashing on the provider chain, nor the Timestamp to check the evidence age. We can get the infractionHeight from the votes, but this infractionHeight corresponds to the infraction height on the consumer and not on the provider chain. +Similarly, when a relayer or a user sends evidence through a MsgSubmitConsumerMisbehaviour message, the provider gets access to Misbehaviour that we cannot use to extract the infraction height, power, or the time on the provider chain.

Proposed solution

As a first iteration, we propose the following approach. At the moment the provider receives evidence of equivocation on a consumer:

  1. slash all the undelegations and redelegations using slashFactor;
  2. slash all delegations using as voting power the sum of the voting power of the misbehaving validator and the power of all the ongoing undelegations and redelegations.

Evidence expiration: Additionally, because we cannot infer the actual time of the evidence (i.e., the timestamp of the evidence cannot be trusted), we do not consider evidence expiration and hence old evidence is never ignored (e.g., the provider would act on 3 year-old evidence of equivocation on a consumer). +Additionally, we do not need to store equivocation evidence to avoid slashing a validator more than once, because we do not slash tombstoned validators and we tombstone a validator when slashed.

We do not act on evidence that was signed by a validator consensus key that is pruned when we receive the evidence. We prune a validator's consensus key if the validator has assigned a new consumer key (using MsgAssignConsumerKey) and an unbonding period on the consumer chain has elapsed (see key assignment ADR). Note that the provider chain is informed that the unbonding period has elapsed on the consumer when the provider receives a VSCMaturedPacket and because of this, if the consumer delays the sending of a VSCMaturedPacket, we would delay the pruning of the key as well.

Implementation

The following logic needs to be added to the HandleConsumerDoubleVoting and HandleConsumerMisbehaviour methods:

undelegationsInTokens := sdk.NewInt(0)
for _, v := range k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validatorAddress) {
for _, entry := range v.Entries {
if entry.IsMature(now) && !entry.OnHold() {
// undelegation no longer eligible for slashing, skip it
continue
}
undelegationsInTokens = undelegationsInTokens.Add(entry.InitialBalance)
}
}

redelegationsInTokens := sdk.NewInt(0)
for _, v := range k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validatorAddress) {
for _, entry := range v.Entries {
if entry.IsMature(now) && !entry.OnHold() {
// redelegation no longer eligible for slashing, skip it
continue
}
redelegationsInTokens = redelegationsInTokens.Add(entry.InitialBalance)
}
}

infractionHeight := 0
undelegationsAndRedelegationsInPower = sdk.TokensToConsensusPower(undelegationsInTokens.Add(redelegationsInTokens))
totalPower := validator's voting power + undelegationsAndRedelegationsInPower
slashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)

k.stakingKeeper.Slash(ctx, validatorConsAddress, infractionHeight, totalPower, slashFraction, DoubleSign)

Infraction height: We provide a zero infractionHeight to the Slash method in order to slash all ongoing undelegations and redelegations (see checks in Slash, SlashUnbondingDelegation, and SlashRedelegation).

Power: We pass the sum of the voting power of the misbehaving validator when the evidence was received (i.e., at evidence height) and the power of all the ongoing undelegations and redelegations. +If we assume that the slashFactor is 5%, then the voting power we pass is power + totalPower(undelegations) + totalPower(redelegations). +Hence, when the Slash method slashes all the undelegations and redelegations it would end up with 0.05 * power + 0.05 * totalPower(undelegations) + 0.05 * totalPower(redelegations) - 0.05 * totalPower(undelegations) - 0.05 * totalPower(redelegations) = 0.05 * power and hence it would slash 5% of the validator's power when the evidence is received.

Positive

With the proposed approach we can quickly implement slashing functionality on the provider chain for consumer chain equivocations. +This approach does not need to change the staking module and therefore does not change in any way how slashing is performed today for a single chain.

Negative

  • We definitely slash more when it comes to undelegations and redelegations because we slash for all of them without considering an infractionHeight.
  • We potentially slash more than what we would have slashed if we knew the voting power at the corresponding infractionHeight in the provider chain.
  • We slash on old evidence of equivocation on a consumer.

References

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-013-equivocation-slashing.html.html b/legacy/v3.3.0/adrs/adr-013-equivocation-slashing.html.html new file mode 100644 index 0000000000..8cb4ccf8c5 --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-013-equivocation-slashing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-template.html b/legacy/v3.3.0/adrs/adr-template.html new file mode 100644 index 0000000000..a490b528f6 --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-template.html @@ -0,0 +1,22 @@ + + + + + +ADR Template | Interchain Security + + + + +
+
Version: v3.3.0

ADR {ADR-NUMBER}: {TITLE}

Changelog

  • {date}: {changelog}

Status

A decision may be "proposed" if it hasn't been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement.

{Deprecated|Proposed|Accepted}

Context

This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution.

Decision

This section explains all of the details of the proposed solution, including implementation details. +It should also describe affects / corollary items that may need to be changed as a part of this. +If the proposed change will be large, please also indicate a way to do the change to maximize ease of review. +(e.g. the optimal split of things to do between separate PR's)

Consequences

This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones.

Positive

Negative

Neutral

References

Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!

  • {reference link}
+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/adr-template.html.html b/legacy/v3.3.0/adrs/adr-template.html.html new file mode 100644 index 0000000000..4f74151f54 --- /dev/null +++ b/legacy/v3.3.0/adrs/adr-template.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/intro.html b/legacy/v3.3.0/adrs/intro.html new file mode 100644 index 0000000000..d560202756 --- /dev/null +++ b/legacy/v3.3.0/adrs/intro.html @@ -0,0 +1,22 @@ + + + + + +ADRs | Interchain Security + + + + +
+
Version: v3.3.0

Architecture Decision Records (ADR)

This is a location to record all high-level architecture decisions in the Interchain Security project.

You can read more about the ADR concept in this blog post.

An ADR should provide:

  • Context on the relevant goals and the current state
  • Proposed changes to achieve the goals
  • Summary of pros and cons
  • References
  • Changelog

Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and +justification for a change in architecture, or for the architecture of something +new. The spec is much more compressed and streamlined summary of everything as +it is or should be.

If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match.

Note the context/background should be written in the present tense.

To suggest an ADR, please make use of the ADR template provided.

Table of Contents

ADR #DescriptionStatus
001Consumer chain key assignmentAccepted, Implemented
002Jail ThrottlingAccepted, Implemented
003Equivocation governance proposalAccepted, Implemented
004Denom DOS fixesAccepted, Implemented
005Cryptographic verification of equivocation evidenceAccepted, In-progress
007Pause validator unbonding during equivocation proposalProposed
008Throttle with retriesAccepted, In-progress
009Soft Opt-outAccepted, Implemented
010Standalone to Consumer ChangeoverAccepted, Implemented
011Improving testing and increasing confidenceProposed
012Separate ReleasingProposed
013Slashing on the provider for consumer equivocationProposed
+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/adrs/intro.html.html b/legacy/v3.3.0/adrs/intro.html.html new file mode 100644 index 0000000000..28a1b8f382 --- /dev/null +++ b/legacy/v3.3.0/adrs/intro.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/consumer-development/app-integration.html b/legacy/v3.3.0/consumer-development/app-integration.html new file mode 100644 index 0000000000..27c1c6fa77 --- /dev/null +++ b/legacy/v3.3.0/consumer-development/app-integration.html @@ -0,0 +1,23 @@ + + + + + +Developing an ICS consumer chain | Interchain Security + + + + +
+
Version: v3.3.0

Developing an ICS consumer chain

When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol. +To help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications.

Basic consumer chain

The source code for the example app can be found here.

Please note that consumer chains do not implement the staking module - the validator set is replicated from the provider, meaning that the provider and the consumer use the same validator set and their stake on the provider directly determines their stake on the consumer. +At present there is no opt-in mechanism available, so all validators of the provider must also validate on the provider chain.

Your chain should import the consumer module from x/consumer and register it in the correct places in your app.go. +The x/consumer module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in. +You should not need to manage or override any code from the x/consumer module.

Democracy consumer chain

The source code for the example app can be found here.

This type of consumer chain wraps the basic CosmosSDK x/distribution, x/staking and x/governance modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system.

This allows the consumer chain to leverage those modules while also using the x/consumer module.

With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.

Standalone chain to consumer chain changeover

This feature is being actively worked on. Information will be provided at a later time.

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/consumer-development/app-integration.html.html b/legacy/v3.3.0/consumer-development/app-integration.html.html new file mode 100644 index 0000000000..fe3fc9a6e4 --- /dev/null +++ b/legacy/v3.3.0/consumer-development/app-integration.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/consumer-development/changeover-procedure.html b/legacy/v3.3.0/consumer-development/changeover-procedure.html new file mode 100644 index 0000000000..6dc026888c --- /dev/null +++ b/legacy/v3.3.0/consumer-development/changeover-procedure.html @@ -0,0 +1,19 @@ + + + + + +Changeover Procedure | Interchain Security + + + + +
+
Version: v3.3.0

Changeover Procedure

Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.

The relevant protocol specifications are available below:

Overview

Standalone to consumer changeover procedure can rougly be separated into 4 parts:

1. ConsumerAddition proposal submitted to the provider chain

The proposal is equivalent to the "normal" ConsumerAddition proposal submitted by new consumer chains.

However, here are the most important notes and differences between a new consumer chain and a standalone chain performing a changeover:

  • chain_id must be equal to the standalone chain id
  • initial_height field has additional rules to abide by:
caution
{
...
"initial_height" : {
// must correspond to current revision number of standalone chain
// e.g. stride-1 => "revision_number": 1
"revision_number": 1,

// must correspond to a height that is at least 1 block after the upgrade
// that will add the `consumer` module to the standalone chain
// e.g. "upgrade_height": 100 => "revision_height": 101
"revision_height": 1,
},
...
}

RevisionNumber: 0, RevisionHeight: 111

  • genesis_hash can be safely ignored because the chain is already running. A hash of the standalone chain's initial genesis may be used

  • binary_hash may not be available ahead of time. All chains performing the changeover go through rigorous testing - if bugs are caught and fixed the hash listed in the proposal may not be the most recent one.

  • spawn_time listed in the proposal MUST be before the upgrade_height listed in the the upgrade proposal on the standalone chain.

    caution

    spawn_time must occur before the upgrade_height on the standalone chain is reached because the provider chain must generate the ConsumerGenesis that contains the validator set that will be used after the changeover.

  • unbonding_period must correspond to the value used on the standalone chain. Otherwise, the clients used for the ccv protocol may be incorrectly initialized.

  • distribution_transmission_channel should be set.

note

Populating distribution_transmission_channel will enable the standalone chain to re-use one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ibc denom that may already be in use.

If the parameter is not set, a new channel will be created.

  • ccv_timeout_period has no important notes

  • transfer_timeout_period has no important notes

  • consumer_redistribution_fraction has no important notes

  • blocks_per_distribution_transmission has no important notes

  • historical_entries has no important notes

2. upgrade proposal on standalone chain

The standalone chain creates an upgrade proposal to include the interchain-security/x/ccv/consumer module.

caution

The upgrade height in the proposal should correspond to a height that is after the spawn_time in the consumer addition proposal submitted to the provider chain.

Otherwise, the upgrade is indistinguishable from a regular on-chain upgrade proposal.

3. spawn time is reached

When the spawn_time is reached on the provider it will generate a ConsumerGenesis that contains the validator set that will supercede the standalone validator set.

This ConsumerGenesis must be available on the standalone chain during the on-chain upgrade.

4. standalone chain upgrade

Performing the on-chain upgrade on the standalone chain will add the ccv/consumer module and allow the chain to become a consumer of replicated security.

caution

The ConsumerGenesis must be exported to a file and placed in the correct folder on the standalone chain before the upgade.

The file must be placed at the exact specified location, otherwise the upgrade will not be executed correctly.

Usually the file is placed in $NODE_HOME/config, but the file name and the exact directory is dictated by the upgrade code on the standalone chain.

  • please check exact instructions provided by the standalone chain team

After the genesis.json file has been made available, the process is equivalent to a normal on-chain upgrade. The standalone validator set will sign the next couple of blocks before transferring control to provider validator set.

The standalone validator set can still be slashed for any infractions if evidence is submitted within the unboding_period.

Notes

The changeover procedure may be updated in the future to create a seamless way of providing the validator set information to the standalone chain.

Onboarding Checklist

This onboarding checklist is slightly different from the one under Onboarding

Additionally, you can check the testnet repo for a comprehensive guide on preparing and launching consumer chains.

1. Complete testing & integration

  • test integration with gaia
  • test your protocol with supported relayer versions (minimum hermes 1.4.1)
  • test the changeover procedure
  • reach out to the ICS team if you are facing issues

2. Create an Onboarding Repository

To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain.

This should include (at minimum):

  • genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see Transform Consumer Genesis)
  • information about relevant seed/peer nodes you are running
  • relayer information (compatible versions)
  • copy of your governance proposal (as JSON)
  • a script showing how to start your chain and connect to peers (optional)
  • take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable

Example of such a repository can be found here.

3. Submit a ConsumerChainAddition Governance Proposal to the provider

Before you submit a ConsumerChainAddition proposal, please provide a spawn_time that is before the the upgrade_height of the upgrade that will introduce the ccv module to your chain.

danger

If the spawn_time happens after your upgrade_height the provider will not be able to communicate the new validator set to be used after the changeover.

Additionally, reach out to the community via the forum to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers.

  • determine your chain's spawn time
  • determine consumer chain parameters to be put in the proposal
  • take note to include a link to your onboarding repository

Example of a consumer chain addition proposal.

// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain or add a standalone chain.
// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.
// It is recommended that spawn time occurs after the proposal end time and that it is scheduled to happen before the standalone chain upgrade
// that sill introduce the ccv module.
{
// Title of the proposal
"title": "Changeover Standalone chain",
// Description of the proposal
// format the text as a .md file and include the file in your onboarding repository
"description": ".md description of your chain and all other relevant information",
// Proposed chain-id of the new consumer chain.
// Must be unique from all other consumer chain ids of the executing provider chain.
"chain_id": "standalone-1",
// Initial height of new consumer chain.
// For a completely new chain, this will be {0,1}.
"initial_height" : {
// must correspond to current revision number of standalone chain
// e.g. standalone-1 => "revision_number": 1
"revision_number": 1,

// must correspond to a height that is at least 1 block after the upgrade
// that will add the `consumer` module to the standalone chain
// e.g. "upgrade_height": 100 => "revision_height": 101
"revision_number": 1,
},
// Hash of the consumer chain genesis state without the consumer CCV module genesis params.
// => not relevant for changeover procedure
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
// Hash of the consumer chain binary that should be run by validators on standalone chain upgrade
// => not relevant for changeover procedure as it may become stale
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
// Unbonding period for the consumer chain.
// It should should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
// IBC transfer packets will timeout after this interval elapses.
"transfer_timeout_period": 1800000000000,
// The fraction of tokens allocated to the consumer redistribution address during distribution events.
// The fraction is a string representing a decimal number. For example "0.75" would represent 75%.
// The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.
"consumer_redistribution_fraction": "0.75",
// BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.
// eg. send rewards to the provider every 1000 blocks
"blocks_per_distribution_transmission": 1000,
// The number of historical info entries to persist in store.
// This param is a part of the cosmos sdk staking module. In the case of
// a ccv enabled consumer chain, the ccv module acts as the staking module.
"historical_entries": 10000,
// The ID of a token transfer channel used for the Reward Distribution
// sub-protocol. If DistributionTransmissionChannel == "", a new transfer
// channel is created on top of the same connection as the CCV channel.
// Note that transfer_channel_id is the ID of the channel end on the consumer chain.
// it is most relevant for chains performing a standalone to consumer changeover
// in order to maintan the existing ibc transfer channel
"distribution_transmission_channel": "channel-123" // NOTE: use existing transfer channel if available
}

3. Submit an Upgrade Proposal & Prepare for Changeover

This proposal should add the ccv consumer module to your chain.

  • proposal upgrade_height must happen after spawn_time in the ConsumerAdditionProposal
  • advise validators about the exact procedure for your chain and point them to your onboarding repository

4. Upgrade time 🚀

  • after spawn_time, request ConsumerGenesis from the provider and place it in <CURRENT_USER_HOME_DIR>/.sovereign/config/genesis.json
  • upgrade the binary to the one listed in your UpgradeProposal

The chain starts after at least 66.67% of standalone voting power comes online. The consumer chain is considered interchain secured once the "old" validator set signs a couple of blocks and transfers control to the provider validator set.

  • provide a repo with onboarding instructions for validators (it should already be listed in the proposal)
  • genesis.json after spawn_time obtained from provider (MUST contain the initial validator set)
  • maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)
+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/consumer-development/changeover-procedure.html.html b/legacy/v3.3.0/consumer-development/changeover-procedure.html.html new file mode 100644 index 0000000000..a1c9dbd064 --- /dev/null +++ b/legacy/v3.3.0/consumer-development/changeover-procedure.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/consumer-development/consumer-chain-governance.html b/legacy/v3.3.0/consumer-development/consumer-chain-governance.html new file mode 100644 index 0000000000..021867f65b --- /dev/null +++ b/legacy/v3.3.0/consumer-development/consumer-chain-governance.html @@ -0,0 +1,19 @@ + + + + + +Consumer Chain Governance | Interchain Security + + + + +
+
Version: v3.3.0

Consumer Chain Governance

Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We'll cover what these are in the "Whitelist" section below.

Democracy module

The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy.

Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus.

For an example, see the Democracy Consumer

CosmWasm

There are several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain.

For an example, see Neutron.

The Whitelist

Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see Neutron's whitelist.

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/consumer-development/consumer-chain-governance.html.html b/legacy/v3.3.0/consumer-development/consumer-chain-governance.html.html new file mode 100644 index 0000000000..5e1750ed45 --- /dev/null +++ b/legacy/v3.3.0/consumer-development/consumer-chain-governance.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/consumer-development/consumer-genesis-transformation.html b/legacy/v3.3.0/consumer-development/consumer-genesis-transformation.html new file mode 100644 index 0000000000..962e6be054 --- /dev/null +++ b/legacy/v3.3.0/consumer-development/consumer-genesis-transformation.html @@ -0,0 +1,22 @@ + + + + + +Consumer Genesis Transformation | Interchain Security + + + + +
+
Version: v3.3.0

Consumer Genesis Transformation

Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentaion on Onboarding and Changeover). +In case that the provider chain is running an older version of the InterChainSecurity (ICS) module than the consumer chain the exported CCV data might need to be transformed to the format supported by the ICS implementation run on the consumer chain. This is the case if the cosumer chain runs version 4 of ICS or later and the provider is running version 3 or older of the ICS module.

To transform such CCV data follow the instructions below

1. Prerequisite

  • Provider chain is running version 3 or older of the ICS provider module
  • Consumer is running version 4 or later of the ICS consumer module.
  • interchain-security-cd application complies to the version run on the consumer chain

2. Export the CCV data

Export the CCV data from the provider chain as descibed in the Onboarding and Changeover) your following. +As a result the CCV data will be stored in a file in JSON format.

3. Transform CCV data

To transform the CCV data to the newer format run the following command.

interchain-security-cd genesis transform [genesis-file]

where 'genesis-file' is the path to the file containing the CCV data exported in step 2. +As a result the CCV data in the new format will be written to standard output.

Use the new CCV data as described in the procedure you're following.

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/consumer-development/consumer-genesis-transformation.html.html b/legacy/v3.3.0/consumer-development/consumer-genesis-transformation.html.html new file mode 100644 index 0000000000..5f632da197 --- /dev/null +++ b/legacy/v3.3.0/consumer-development/consumer-genesis-transformation.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/consumer-development/offboarding.html b/legacy/v3.3.0/consumer-development/offboarding.html new file mode 100644 index 0000000000..4fb80a57e9 --- /dev/null +++ b/legacy/v3.3.0/consumer-development/offboarding.html @@ -0,0 +1,19 @@ + + + + + +Offboarding Checklist | Interchain Security + + + + +
+
Version: v3.3.0

Consumer Offboarding

To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).

// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.
// If it passes, all the consumer chain's state is removed from the provider chain. The outstanding unbonding
// operation funds are released.
{
// the title of the proposal
"title": "This was a great chain",
"description": "Here is a .md formatted string specifying removal details",
// the chain-id of the consumer chain to be stopped
"chain_id": "consumerchain-1",
// the time on the provider chain at which all validators are responsible to stop their consumer chain validator node
"stop_time": "2023-03-07T12:40:00.000000Z",
}

More information will be listed in a future version of this document.

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/consumer-development/offboarding.html.html b/legacy/v3.3.0/consumer-development/offboarding.html.html new file mode 100644 index 0000000000..6221022dab --- /dev/null +++ b/legacy/v3.3.0/consumer-development/offboarding.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/consumer-development/onboarding.html b/legacy/v3.3.0/consumer-development/onboarding.html new file mode 100644 index 0000000000..0f8d8b5d3b --- /dev/null +++ b/legacy/v3.3.0/consumer-development/onboarding.html @@ -0,0 +1,20 @@ + + + + + +Onboarding Checklist | Interchain Security + + + + +
+
Version: v3.3.0

Consumer Onboarding Checklist

The following checklists will aid in onboarding a new consumer chain to replicated security.

Additionally, you can check the testnet repo for a comprehensive guide on preparing and launching consumer chains.

1. Complete testing & integration

  • test integration with gaia
  • test your protocol with supported relayer versions (minimum hermes 1.4.1)
  • reach out to the ICS team if you are facing issues

2. Create an Onboarding Repository

To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain.

This should include (at minimum):

  • genesis.json without CCV data (before the proposal passes)
  • genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see Transform Consumer Genesis)
  • information about relevant seed/peer nodes you are running
  • relayer information (compatible versions)
  • copy of your governance proposal (as JSON)
  • a script showing how to start your chain and connect to peers (optional)
  • take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable

Example of such a repository can be found here.

3. Submit a Governance Proposal

Before you submit a ConsumerChainAddition proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch. +If possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues.

Additionally, reach out to the community via the forum to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers.

  • determine your chain's spawn time
  • determine consumer chain parameters to be put in the proposal
  • take note to include a link to your onboarding repository
  • describe the purpose and benefits of running your chain

Example of a consumer chain addition proposal.

// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.
// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.
// It is recommended that spawn time occurs after the proposal end time.
{
// Title of the proposal
"title": "Add consumer chain",
// Description of the proposal
// format the text as a .md file and include the file in your onboarding repository
"description": ".md description of your chain and all other relevant information",
// Proposed chain-id of the new consumer chain.
// Must be unique from all other consumer chain ids of the executing provider chain.
"chain_id": "newchain-1",
// Initial height of new consumer chain.
// For a completely new chain, this will be {0,1}.
"initial_height" : {
"revision_height": 0,
"revision_number": 1,
},
// Hash of the consumer chain genesis state without the consumer CCV module genesis params.
// It is used for off-chain confirmation of genesis.json validity by validators and other parties.
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
// Hash of the consumer chain binary that should be run by validators on chain initialization.
// It is used for off-chain confirmation of binary validity by validators and other parties.
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
// Unbonding period for the consumer chain.
// It should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
// IBC transfer packets will timeout after this interval elapses.
"transfer_timeout_period": 1800000000000,
// The fraction of tokens allocated to the consumer redistribution address during distribution events.
// The fraction is a string representing a decimal number. For example "0.75" would represent 75%.
// The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.
"consumer_redistribution_fraction": "0.75",
// BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.
// eg. send rewards to the provider every 1000 blocks
"blocks_per_distribution_transmission": 1000,
// The number of historical info entries to persist in store.
// This param is a part of the cosmos sdk staking module. In the case of
// a ccv enabled consumer chain, the ccv module acts as the staking module.
"historical_entries": 10000,
// The ID of a token transfer channel used for the Reward Distribution
// sub-protocol. If DistributionTransmissionChannel == "", a new transfer
// channel is created on top of the same connection as the CCV channel.
// Note that transfer_channel_id is the ID of the channel end on the consumer chain.
// it is most relevant for chains performing a sovereign to consumer changeover
// in order to maintain the existing ibc transfer channel
"distribution_transmission_channel": "channel-123"
}

4. Launch

The consumer chain starts after at least 66.67% of all provider's voting power comes online. The consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer

  • provide a repo with onboarding instructions for validators (it should already be listed in the proposal)
  • genesis.json with ccv data populated (MUST contain the initial validator set)
  • maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)
  • have a block explorer in place to track chain activity & health
+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/consumer-development/onboarding.html.html b/legacy/v3.3.0/consumer-development/onboarding.html.html new file mode 100644 index 0000000000..0e38c8be3e --- /dev/null +++ b/legacy/v3.3.0/consumer-development/onboarding.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/faq.html b/legacy/v3.3.0/faq.html new file mode 100644 index 0000000000..00a6bc3205 --- /dev/null +++ b/legacy/v3.3.0/faq.html @@ -0,0 +1,24 @@ + + + + + +Frequently Asked Questions | Interchain Security + + + + +
+
Version: v3.3.0

Frequently Asked Questions

What is the meaning of Validator Set Replication?

VSR simply means that the same validator set is used to secure both the provider and consumer chains. VSR is ensured through ICS protocol which keeps consumers up to date with the validator set of the provider.

What is a consumer chain?

Consumer chain is blockchain operated by the same validator operators as the provider chain. The ICS protocol ensures the validator set replication properties (informs consumer chain about the current state of the validator set on the provider)

Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements.

What happens to consumer if provider is down?

In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set.

The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness.

However, if the trusting_period (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain. +This means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about.

Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point. +At the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.

What happens to provider if consumer is down?

Consumer chains do not impact the provider chain. +The ICS protocol is concerned only with validator set replication and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events).

Can I run the provider and consumer chains on the same machine?

Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation.

Can the consumer chain have its own token?

As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees.

How are Tx fees paid on consumer?

The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations.

Are there any restrictions the consumer chains need to abide by?

No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way. +The only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain.

What's in it for the validators and stakers?

The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by consumer_redistribution_fraction. The rewards are distributed (sent to the provider) every blocks_per_distribution_transmission.

note

consumer_redistribution_fraction and blocks_per_distribution_transmission are parameters defined in the ConsumerAdditionProposal used to create the consumer chain. These parameters can be changed via consumer chain governance.

Can the consumer chain have its own governance?

Yes.

In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.

Validators can also be representatives but representatives are not required to run validator nodes.

This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance.

Can validators opt-out of replicated security?

At present, the validators cannot opt-out of validating consumer chains.

There are multiple opt-out mechanisms under active research.

How does Equivocation Governance Slashing work?

To avoid potential attacks directed at provider chain validators, a new mechanism was introduced:

When a validator double-signs on the consumer chain, a special type of slash packet is relayed to the provider chain. The provider will store information about the double signing validator and allow a governance proposal to be submitted. +If the double-signing proposal passes, the offending validator will be slashed on the provider chain and tombstoned. Tombstoning will permanently exclude the validator from the active set of the provider.

caution

An equivocation proposal cannot be submitted for a validator that did not double sign on any of the consumer chains.

Can Consumer Chains perform Software Upgrades?

Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM).

Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module.

How can I connect to the testnets?

Check out the Joining Replicated Security testnet section.

How do I start using ICS?

To become a consumer chain use this checklist and check the App integration section

Which relayers are supported?

Currently supported versions:

  • Hermes 1.4.1
  • Support for the CCV module was added to the Go relayer in v2.2.0 but v2.4.0 has significant performance fixes which makes it the earliest suggested version to use.

How does key delegation work in ICS?

You can check the Key Assignment Guide for specific instructions.

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/faq.html.html b/legacy/v3.3.0/faq.html.html new file mode 100644 index 0000000000..adb6ed223a --- /dev/null +++ b/legacy/v3.3.0/faq.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/features/key-assignment.html b/legacy/v3.3.0/features/key-assignment.html new file mode 100644 index 0000000000..bd186a9fc9 --- /dev/null +++ b/legacy/v3.3.0/features/key-assignment.html @@ -0,0 +1,20 @@ + + + + + +Key Assignment | Interchain Security + + + + +
+
Version: v3.3.0

Key Assignment

Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate. +There are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains.

The feature is outlined in this ADR-001

By sending an AssignConsumerKey transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator.

tip

Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity.

Rules

  • a key can be assigned before the consumer addition proposal passes on the provider
  • validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider
  • validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X
  • a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain
tip

Validators can use a different key for each consumer chain.

Adding a key

First, create a new node on the consumer chain using the equivalent:

consumerd init <moniker>

Then query your node for the consensus key.

consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}

Then, make an assign-consensus-key transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain.

gaiad tx provider assign-consensus-key <consumer-chain-id> '<pubkey>' --from <tx-signer> --home <home_dir> --gas 900000 -b sync -y -o json
  • consumer-chain-id is the string identifier of the consumer chain, as assigned on the provider chain
  • consumer-pub-key has the following format {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}

Check that the key was assigned correctly by querying the provider:

gaiad query provider validator-consumer-key <consumer-chain-id> cosmosvalcons1e....3xsj3ayzf4uv6

You must use a valcons address. You can obtain it by querying your node on the provider gaiad tendermint show-address

OR

gaiad query provider validator-provider-key <consumer-chain-id> consumervalcons1e....123asdnoaisdao

You must use a valcons address. You can obtain it by querying your node on the consumer consumerd tendermint show-address

OR

gaiad query provider all-pairs-valconsensus-address <consumer-chain-id>

You just need to use the chainId of consumer to query all pairs valconsensus address with consumer-pub-key for each of pair

Changing a key

To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied

Removing a key

To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the Adding a key section and using your provider consensus key.

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/features/key-assignment.html.html b/legacy/v3.3.0/features/key-assignment.html.html new file mode 100644 index 0000000000..9ca8bdbb6d --- /dev/null +++ b/legacy/v3.3.0/features/key-assignment.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/features/proposals.html b/legacy/v3.3.0/features/proposals.html new file mode 100644 index 0000000000..bea85e7974 --- /dev/null +++ b/legacy/v3.3.0/features/proposals.html @@ -0,0 +1,22 @@ + + + + + +ICS Provider Proposals | Interchain Security + + + + +
+
Version: v3.3.0

ICS Provider Proposals

Interchain security module introduces 3 new proposal types to the provider.

The proposals are used to propose upcoming interchain security events through governance.

ConsumerAdditionProposal

info

If you are preparing a ConsumerAdditionProposal you can find more information in the consumer onboarding checklist.

Proposal type used to suggest adding a new consumer chain.

When proposals of this type are passed and the spawn_time specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain.

Minimal example:

{
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
"title": "Add consumer chain",
"description": ".md description of your chain and all other relevant information",
"chain_id": "newchain-1",
"initial_height" : {
"revision_height": 0,
"revision_number": 1,
},
// Unbonding period for the consumer chain.
// It should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
"transfer_timeout_period": 1800000000000,
"consumer_redistribution_fraction": "0.75",
"blocks_per_distribution_transmission": 1000,
"historical_entries": 10000,
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1"
// relevant for chains performing a sovereign to consumer changeover
// in order to maintain the existing ibc transfer channel
"distribution_transmission_channel": "channel-123"
}

More examples can be found in the replicated security testnet repository here and here.

ConsumerRemovalProposal

Proposal type used to suggest removing an existing consumer chain.

When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain. +After the consumer chain removal, the chain in question will no longer be secured by the provider's validator set.

info

The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain. +Additional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set. +More information will be made available in the Consumer Offboarding Checklist.

Minimal example:

{
// the time on the provider chain at which all validators are responsible to stop their consumer chain validator node
"stop_time": "2023-03-07T12:40:00.000000Z",
// the chain-id of the consumer chain to be stopped
"chain_id": "consumerchain-1",
"title": "This was a great chain",
"description": "Here is a .md formatted string specifying removal details"
}

ChangeRewardDenomProposal

tip

ChangeRewardDenomProposal will only be accepted on the provider chain if at least one of the denomsToAdd or denomsToRemove fields is populated with at least one denom. Also, a denom cannot be repeated in both sets.

Proposal type used to mutate the set of denoms accepted by the provider as rewards.

Minimal example:

{
"title": "Add untrn as a reward denom",
"description": "Here is more information about the proposal",
"denomsToAdd": ["untrn"],
"denomsToRemove": []
}
+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/features/proposals.html.html b/legacy/v3.3.0/features/proposals.html.html new file mode 100644 index 0000000000..c2f15866b6 --- /dev/null +++ b/legacy/v3.3.0/features/proposals.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/features/reward-distribution.html b/legacy/v3.3.0/features/reward-distribution.html new file mode 100644 index 0000000000..840d0dbbd8 --- /dev/null +++ b/legacy/v3.3.0/features/reward-distribution.html @@ -0,0 +1,25 @@ + + + + + +Reward distribution | Interchain Security + + + + +
+
Version: v3.3.0

Reward distribution

Consumer chains have the option of sharing their block rewards (inflation tokens) and fees with provider chain validators and delegators. +In replicated security block rewards and fees are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel that gets created during consumer chain initialization.

Reward distribution on the provider is handled by the distribution module - validators and delegators receive a fraction of the consumer chain tokens as staking rewards. +The distributed reward tokens are IBC tokens and therefore cannot be staked on the provider chain.

Sending and distributing rewards from consumer chains to provider chain is handled by the Reward Distribution sub-protocol.

Note

The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the ConsumerRewardsPool. +There is a new transaction type called RegisterConsumerRewardDenom. This transaction allows consumer chains to register denoms to be used as consumer chain rewards on the provider. +The cost to register a denom is configurable (ConsumerRewardDenomRegistrationFee chain param) and the full amount of this fee is transferred to the community pool of the provider chain. Only denoms registered through this transaction are then transferred from the ConsumerRewardsPool to the FeePoolAddress, to be distributed out to delegators and validators.

Instructions for adding a denom

The transaction must be carried out on the provider chain. Please use the ibc/* denom trace format.

tip
# reward denoms must be registered on the provider chain (gaia in this example)
gaiad tx provider register-consumer-reward-denom ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9 --from mykey

Parameters

tip

The following chain parameters dictate consumer chain distribution amount and frequency. +They are set at consumer genesis and blocks_per_distribution_transmission, consumer_redistribution_fraction +transfer_timeout_period must be provided in every ConsumerChainAddition proposal.

consumer_redistribution_fraction

The fraction of tokens allocated to the consumer redistribution address during distribution events. The fraction is a string representing a decimal number. For example "0.75" would represent 75%.

tip

Example:

With consumer_redistribution_fraction set to 0.75 the consumer chain would send 75% of its block rewards and accumulated fees to the consumer redistribution address, and the remaining 25% to the provider chain every n blocks where n == blocks_per_distribution_transmission.

blocks_per_distribution_transmission

The number of blocks between IBC token transfers from the consumer chain to the provider chain.

transfer_timeout_period

Timeout period for consumer chain reward distribution IBC packets.

distribution_transmission_channel

Provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.

provider_fee_pool_addr_str

Provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/features/reward-distribution.html.html b/legacy/v3.3.0/features/reward-distribution.html.html new file mode 100644 index 0000000000..652d011a01 --- /dev/null +++ b/legacy/v3.3.0/features/reward-distribution.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/features/slashing.html b/legacy/v3.3.0/features/slashing.html new file mode 100644 index 0000000000..019d7b37e7 --- /dev/null +++ b/legacy/v3.3.0/features/slashing.html @@ -0,0 +1,22 @@ + + + + + +Consumer Initiated Slashing | Interchain Security + + + + +
+
Version: v3.3.0

Consumer Initiated Slashing

A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain. +In essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake).

To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized. +Any infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains.

In the current implementation there are 2 important changes brought by the interchain security module:

Downtime infractions

reported by consumer chains are acted upon on the provider as soon as the provider receives the infraction evidence.

Instead of slashing, the provider will only jail offending validator for the duration of time established in the chain parameters.

info

Slash throttling (sometimes called jail throttling) mechanism ensures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider.

Cryptographic verification of equivocation and slashing

The Cryptographic verification of equivocation allows external agents to submit evidences of light client and double signing attacks observed on a consumer chain. When valid evidence is received, the malicious validators will be slashed, jailed, and tombstoned on the provider.

The feature is outlined in ADR-005 and ADR-013.

By sending a MsgSubmitConsumerMisbehaviour or a MsgSubmitConsumerDoubleVoting transaction, the provider will +verify the reported equivocation and, if successful, slash, jail, and tombstone the malicious validator.

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/features/slashing.html.html b/legacy/v3.3.0/features/slashing.html.html new file mode 100644 index 0000000000..0c23fedf38 --- /dev/null +++ b/legacy/v3.3.0/features/slashing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/introduction/overview.html b/legacy/v3.3.0/introduction/overview.html new file mode 100644 index 0000000000..ede7648596 --- /dev/null +++ b/legacy/v3.3.0/introduction/overview.html @@ -0,0 +1,19 @@ + + + + + +Overview | Interchain Security + + + + +
+
Version: v3.3.0

Overview

info

Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.


Replicated security allows anyone to launch a "consumer" blockchain using the same validator set as the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit the full security and decentralization of the provider.

Why Replicated Security?

  • Full provider security. At launch, consumer chains are secured by the full validator set and market cap of the provider chain.
  • Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum.
  • Projects keep majority of gas fees. Depending on configuration, these fees either go to the project’s community DAO, or can be used in the protocol in other ways.
  • No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. A governance vote will take place for a chain to get adopted by the provider validators which will encourage participation and signal strong buy-in into the project's long-term success.
  • Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set.

Core protocol

info

Protocol specification is available as ICS-028 in the IBC repository.

Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer.

To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider.

Downtime Slashing

If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period.

Tokenomics and Rewards

Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance.

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/introduction/overview.html.html b/legacy/v3.3.0/introduction/overview.html.html new file mode 100644 index 0000000000..1cadc1b5f0 --- /dev/null +++ b/legacy/v3.3.0/introduction/overview.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/introduction/params.html b/legacy/v3.3.0/introduction/params.html new file mode 100644 index 0000000000..c4ed242dbb --- /dev/null +++ b/legacy/v3.3.0/introduction/params.html @@ -0,0 +1,21 @@ + + + + + +Interchain Security Parameters | Interchain Security + + + + +
+
Version: v3.3.0

Interchain Security Parameters

The parameters necessary for Interchain Security (ICS) are defined in

  • the Params structure in proto/interchain_security/ccv/provider/v1/provider.proto for the provider;
  • the Params structure in proto/interchain_security/ccv/consumer/v1/consumer.proto for the consumer.

Time-based parameters

ICS relies on the following time-based parameters.

ProviderUnbondingPeriod

ProviderUnbondingPeriod is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance.

ConsumerUnbondingPeriod

ConsumerUnbondingPeriod is the unbonding period on the consumer chain.

info

ConsumerUnbondingPeriod is set via the ConsumerAdditionProposal governance proposal to add a new consumer chain. +It is recommended that every consumer chain set and unbonding period shorter than ProviderUnbondingPeriod


Example:

ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day

Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer.

TrustingPeriodFraction

TrustingPeriodFraction is used to calculate the TrustingPeriod of created IBC clients on both provider and consumer chains.

Setting TrustingPeriodFraction to 0.5 would result in the following:

TrustingPeriodFraction = 0.5
ProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5
ConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5

Note that a light clients must be updated within the TrustingPeriod in order to avoid being frozen.

For more details, see the IBC specification of Tendermint clients.

CCVTimeoutPeriod

CCVTimeoutPeriod is the period used to compute the timeout timestamp when sending IBC packets.

For more details, see the IBC specification of Channel & Packet Semantics.

danger

If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed.

CCVTimeoutPeriod may have different values on the provider and consumer chains.

  • CCVTimeoutPeriod on the provider must be larger than ConsumerUnbondingPeriod
  • CCVTimeoutPeriod on the consumer is initial set via the ConsumerAdditionProposal

InitTimeoutPeriod

InitTimeoutPeriod is the maximum allowed duration for CCV channel initialization to execute.

For any consumer chain, if the CCV channel is not established within InitTimeoutPeriod then the consumer chain will be removed and therefore will not be secured by the provider chain.

The countdown starts when the spawn_time specified in the ConsumerAdditionProposal is reached.

VscTimeoutPeriod

VscTimeoutPeriod is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live. +If the VscTimeoutPeriod is ever reached for a consumer chain that chain will be considered not live and removed from interchain security.

tip

VscTimeoutPeriod MUST be larger than the ConsumerUnbondingPeriod.

BlocksPerDistributionTransmission

BlocksPerDistributionTransmission is the number of blocks between rewards transfers from the consumer to the provider.

TransferPeriodTimeout

TransferPeriodTimeout is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider.

If this timeout expires, then the transfer is attempted again after BlocksPerDistributionTransmission blocks.

  • TransferPeriodTimeout on the consumer is initial set via the ConsumerAdditionProposal gov proposal to add the consumer
  • TransferPeriodTimeout should be smaller than BlocksPerDistributionTransmission x avg_block_time

Slash Throttle Parameters

SlashMeterReplenishPeriod

SlashMeterReplenishPeriod exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed.

The meter is replenished to an amount equal to the slash meter allowance for that block, or SlashMeterReplenishFraction * CurrentTotalVotingPower.

SlashMeterReplenishFraction

SlashMeterReplenishFraction exists on the provider as the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs.

This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a sdk.Dec when used.

MaxThrottledPackets

MaxThrottledPackets exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value.

This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness.

info

MaxThrottledPackets was deprecated in ICS versions >= v3.2.0 due to the implementation of ADR-008.

RetryDelayPeriod

RetryDelayPeriod exists on the consumer for ICS versions >= v3.2.0 (introduced by the implementation of ADR-008) and is the period at which the consumer retries to send a SlashPacket that was rejected by the provider.

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/introduction/params.html.html b/legacy/v3.3.0/introduction/params.html.html new file mode 100644 index 0000000000..1ab5037dec --- /dev/null +++ b/legacy/v3.3.0/introduction/params.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/introduction/technical-specification.html b/legacy/v3.3.0/introduction/technical-specification.html new file mode 100644 index 0000000000..27892ce1bb --- /dev/null +++ b/legacy/v3.3.0/introduction/technical-specification.html @@ -0,0 +1,19 @@ + + + + + +Technical Specification | Interchain Security + + + + +
+
Version: v3.3.0

Technical Specification

For a technical deep dive into the replicated security protocol, see the specification.

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/introduction/technical-specification.html.html b/legacy/v3.3.0/introduction/technical-specification.html.html new file mode 100644 index 0000000000..7ae1ad8e35 --- /dev/null +++ b/legacy/v3.3.0/introduction/technical-specification.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/introduction/terminology.html b/legacy/v3.3.0/introduction/terminology.html new file mode 100644 index 0000000000..b847ccbcb4 --- /dev/null +++ b/legacy/v3.3.0/introduction/terminology.html @@ -0,0 +1,20 @@ + + + + + +Terminology | Interchain Security + + + + +
+
Version: v3.3.0

Terminology

You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.

Shared Security

Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share its proof-of-stake security with another blockchain or off-chain process.

Interchain Security

Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC.

Replicated Security

A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC. Note this documentation is focused on explaining the concepts from replicated security.

Mesh security

A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see Replicated vs. Mesh Security on the Informal Blog.

Consumer Chain

Chain that is secured by the validator set of the provider, instead of its own. +Replicated security allows the provider chain validator set to validate blocks on the consumer chain.

Standalone Chain

Chain that is secured by its own validator set. This chain does not participate in replicated security.

Standalone chains may sometimes be called "sovereign" - the terms are synonymous.

Changeover Procedure

Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/introduction/terminology.html.html b/legacy/v3.3.0/introduction/terminology.html.html new file mode 100644 index 0000000000..d3cb5cda86 --- /dev/null +++ b/legacy/v3.3.0/introduction/terminology.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/validators/changeover-procedure.html b/legacy/v3.3.0/validators/changeover-procedure.html new file mode 100644 index 0000000000..88e01a4e0b --- /dev/null +++ b/legacy/v3.3.0/validators/changeover-procedure.html @@ -0,0 +1,21 @@ + + + + + +Validator instructions for Changeover Procedure | Interchain Security + + + + +
+
Version: v3.3.0

Validator instructions for Changeover Procedure

More details available in Changeover Procedure documentation.

A major difference betwen launching a new consumer chain vs. onboarding a standalone chain to ICS is that there is no consumer genesis available for the standalone chain. Since a standalone chain already exists, its state must be preserved once it transitions to being a consumer chain.

Timeline

Upgrading standalone chains can be best visualised using a timeline, such as the one available Excalidraw graphic by Stride.

There is some flexibility with regards to how the changeover procedure is executed, so please make sure to follow the guides provided by the team doing the changeover.

Standalone to consumer transition timeline

1. ConsumerAdditionProposal on provider chain

This step will add the standalone chain to the list of consumer chains secured by the provider. +This step dictates the spawn_time. After spawn_time the CCV state (initial validator set of the provider) will be available to the consumer.

To obtain it from the provider use:

gaiad q provider consumer-genesis stride-1 -o json > ccv-state.json
jq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' genesis.json ccv-state.json > ccv.json

2. SoftwareUpgradeProposal on the standalone/consumer chain

This upgrade proposal will introduce ICS to the standalone chain, making it a consumer.

3. Assigning a consumer key

After spawn_time, make sure to assign a consumer key if you intend to use one.

Instructions are available here

4. Perform the software ugprade on standalone chain

Please use instructions provided by the standalone chain team and make sure to reach out if you are facing issues. +The upgrade preparation depends on your setup, so please make sure you prepare ahead of time.

danger

The ccv.json from step 1. must be made available on the machine running the standalone/consumer chain at standalone chain upgrade_height. This file contains the initial validator set and parameters required for normal ICS operation.

Usually, the file is placed in $NODE_HOME/config but this is not a strict requirement. The exact details are available in the upgrade code of the standalone/consumer chain.

Performing this upgrade will transition the standalone chain to be a consumer chain.

After 3 blocks, the standalone chain will stop using the "old" validator set and begin using the provider validator set.

FAQ

Can I reuse the same validator key for the consumer chain that I am already using on the standalone chain? Will I need to perform a AssignConsumerKey tx with this key before spawn time?

Validators must either assign a key or use the same key as on the provider.

If you are validating both the standalone and the provider, you can use your current standalone key with some caveats:

  • you must submit an AssignConsumerKey tx with your current standalone validator key
  • it is best to submit AssignConsumerKey tx before spawn_time
  • if you do not submit the Tx, it is assumed that you will be re-using your provider key to validate the standalone/consumer chain

Can I continue using the same node that was validating the standalone chain?

Yes.

Please assign your consensus key as stated aboce.

Can I set up a new node to validate the standalone/consumer chain after it transitions to replicated security?

Yes.

If you are planning to do this please make sure that the node is synced with standalone network and to submit AssignConsumerKey tx before spawn_time.

What happens to the standalone validator set after it after it transitions to replicated security?

The standalone chain validators will stop being validators after the first 3 blocks are created while using replicated security. The standalone validators will become governors and still can receive delegations if the consumer chain is using the consumer-democracy module.

Governors DO NOT VALIDATE BLOCKS.

Instead, they can participate in the governance process and take on other chain-specific roles.

Credits

Thank you Stride team for providing detailed instructions about the changeover procedure.

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/validators/changeover-procedure.html.html b/legacy/v3.3.0/validators/changeover-procedure.html.html new file mode 100644 index 0000000000..94e5bb0d45 --- /dev/null +++ b/legacy/v3.3.0/validators/changeover-procedure.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/validators/joining-neutron.html b/legacy/v3.3.0/validators/joining-neutron.html new file mode 100644 index 0000000000..0d66cce1fd --- /dev/null +++ b/legacy/v3.3.0/validators/joining-neutron.html @@ -0,0 +1,19 @@ + + + + + +Joining Neutron | Interchain Security + + + + +
+
Version: v3.3.0

Joining Neutron

Neutron is the first consumer chain to implement ICS.

You can find instructions on joining the mainnet here.

To join Neutron chain on the replicated security testnet check here

Resources

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/validators/joining-neutron.html.html b/legacy/v3.3.0/validators/joining-neutron.html.html new file mode 100644 index 0000000000..f30f7aba2b --- /dev/null +++ b/legacy/v3.3.0/validators/joining-neutron.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/validators/joining-stride.html b/legacy/v3.3.0/validators/joining-stride.html new file mode 100644 index 0000000000..f427b16887 --- /dev/null +++ b/legacy/v3.3.0/validators/joining-stride.html @@ -0,0 +1,19 @@ + + + + + +Joining Stride | Interchain Security + + + + +
+
Version: v3.3.0

Joining Stride

Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.

stride-1 network (mainnet) will perform a software upgrade and at height 4616678 that will transition the network to using the Cosmos Hub's (cosmoshub-4) validator set.

You can find instructions about the Stride consumer chain launch and joining the mainnet here.

This Excalidraw graphic explains the timeline of Stride's changeover procedure.

Note

Stride re-uses an existing transfer channel to send consumer rewards to the provider chain, in order to preserve existing transfer IBC denom between stride-1 and cosmoshub-4.

Resources

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/validators/joining-stride.html.html b/legacy/v3.3.0/validators/joining-stride.html.html new file mode 100644 index 0000000000..7e180d617b --- /dev/null +++ b/legacy/v3.3.0/validators/joining-stride.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/validators/joining-testnet.html b/legacy/v3.3.0/validators/joining-testnet.html new file mode 100644 index 0000000000..99f38b6231 --- /dev/null +++ b/legacy/v3.3.0/validators/joining-testnet.html @@ -0,0 +1,20 @@ + + + + + +Joining Replicated Security testnet | Interchain Security + + + + +
+
Version: v3.3.0

Joining Replicated Security testnet

Introduction

This short guide will teach you how to join the Replicated Security testnet.

The experience gained in the testnet will prepare you for validating interchain secured chains.

tip

Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set.

For general information about running cosmos-sdk based chains check out the validator basics and Running a Node section of Cosmos SDK docs

Joining the provider chain

info

At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain.

A comprehensive guide is available here.

Initialization

First, initialize your $NODE_HOME using the provider chain binary.

NODE_MONIKER=<your_node>
CHAIN_ID=provider
NODE_HOME=<path_to_your_home>

gaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME

Add your key to the keyring - more details available here.

In this example we will use the test keyring-backend. This option is not safe to use in production.

gaiad keys add <key_moniker> --keyring-backend test

# save the address as variable for later use
MY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)

Before issuing any transactions, use the provider testnet faucet to add funds to your address.

curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider

# example output:
{
"address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",
"amount": "10000000uatom",
"chain": "provider",
"hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",
"status": "success"
}

Then, use the account associated with the keyring to issue a create-validator transaction which will register your validator on chain.

gaiad tx staking create-validator \
--amount=1000000uatom \
--pubkey=$(gaiad tendermint show-validator) \
--moniker="choose a moniker" \
--chain-id=$CHAIN_ID" \
--commission-rate="0.10" \
--commission-max-rate="0.20" \
--commission-max-change-rate="0.01" \
--min-self-delegation="1000000" \
--gas="auto" \
--gas-prices="0.0025uatom" \
--from=<key_moniker>
tip

Check this guide to edit your validator.

After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use statesync to catch up to the rest of the network.

You can use this script to modify your config.toml with the required statesync parameters.

# create the statesync script
$: cd $NODE_HOME
$: touch statesync.sh
$ chmod 700 statesync.sh # make executable

Paste the following instructions into the statesync.sh:

#!/bin/bash

SNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"

LATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \
BLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \
TRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)

sed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\1true| ; \
s|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\1\"$SNAP_RPC,$SNAP_RPC\"| ; \
s|^(trust_height[[:space:]]+=[[:space:]]+).*$|\1$BLOCK_HEIGHT| ; \
s|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\1\"$TRUST_HASH\"|" $NODE_HOME/config/config.toml

Then, you can execute the script:

$: ./statesync.sh # setup config.toml for statesync

Finally, copy the provider genesis and start your node:

$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/replicated-security/provider/provider-genesis.json
$: wget $GENESIS_URL -O genesis.json
$: genesis.json $NODE_HOME/config/genesis.json
# start the service
$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"

Additional scripts to setup your nodes are available here and here. The scripts will configure your node and create the required services - the scripts only work in linux environments.

Joining consumer chains

tip

Once you reach the active set on the provider chain, you will be required to validate all available consumer chains.

You can use the same consensus key on all consumer chains, or opt to use a different key on each consumer chain. +Check out this guide to learn more about key assignment in replicated security.

To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries.

info

When running the provider chain and consumers on the same machine please update the PORT numbers for each of them and make sure they do not overlap (otherwise the binaries will not start).

Important ports to re-configure:

  • --rpc.laddr
  • --p2p.laddr
  • --api.address
  • --grpc.address
  • --grpc-web.address

Re-using consensus key

To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the priv_validator_key.json into the home directory of your consumer chain (<consumer_home>/config/priv_validator_key.json).

When you start the chain, the consensus key will be the same on the provider and the consumer chain.

Assigning consensus keys

Whenever you initialize a new node, it will be configured with a consensus key you can use.

# machine running consumer chain
consumerd init <node_moniker> --home <home_path> --chain-id consumer-1

# use the output of this command to get the consumer chain consensus key
consumerd tendermint show-validator
# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}

Then, let the provider know which key you will be using for the consumer chain:

# machine running the provider chain
gaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b sync -y -o json

After this step, you are ready to copy the consumer genesis into your nodes's /config folder, start your consumer chain node and catch up to the network.

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/validators/joining-testnet.html.html b/legacy/v3.3.0/validators/joining-testnet.html.html new file mode 100644 index 0000000000..e419dac49b --- /dev/null +++ b/legacy/v3.3.0/validators/joining-testnet.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/validators/overview.html b/legacy/v3.3.0/validators/overview.html new file mode 100644 index 0000000000..308a17c2de --- /dev/null +++ b/legacy/v3.3.0/validators/overview.html @@ -0,0 +1,24 @@ + + + + + +Overview | Interchain Security + + + + +
+
Version: v3.3.0

Overview

tip

We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.

At present, replicated security requires all validators of the provider chain (ie. Cosmos Hub) to run validator nodes for all governance-approved consumer chains.

Once a ConsumerAdditionProposal passes, validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains.

Provider chain and consumer chains represent standalone chains that only share the validator set ie. the same validator operators are tasked with running all chains.

info

To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 180 validators for Cosmos Hub).

Startup sequence overview

Consumer chains cannot start and be secured by the validator set of the provider unless a ConsumerAdditionProposal is passed. +Each proposal contains defines a spawn_time - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider.

tip

Validators are required to run consumer chain binaries only after spawn_time has passed.

Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains.

The image below illustrates the startup sequence +startup

1. Consumer Chain init + 2. Genesis generation

Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ConsumerAdditionProposal

3. Submit Proposal

Consumer chain team (or their advocates) submits a ConsumerAdditionProposal. +The most important parameters for validators are:

  • spawn_time - the time after which the consumer chain must be started
  • genesis_hash - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and spawn_time is reached
  • binary_hash - hash of the consumer chain binary used to validate the software builds

4. CCV Genesis state generation

After reaching spawn_time the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain genesis.json. The CCV validator set consists of the validator set on the provider at spawn_time.

The state can be queried on the provider chain (in this case the Cosmos Hub):

 gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json

This is used by the launch coordinator to create the final genesis.json that will be distributed to validators in step 5.

5. Updating the genesis file

Upon reaching the spawn_time the initial validator set state will become available on the provider chain. The initial validator set is included in the final genesis.json of the consumer chain.

6. Chain start

info

The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences.

The new genesis.json containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided genesis.json to start their consumer chain node.

tip

Please pay attention to any onboarding repositories provided by the consumer chain teams. +Recommendations are available in Consumer Onboarding Checklist. +Another comprehensive guide is available in the Replicated Security testnet repo.

7. Creating IBC connections

Finally, to fully establish replicated security an IBC relayer is used to establish connections and create the required channels.

danger

The relayer can establish the connection only after the consumer chain starts producing blocks.

hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> 
hermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1
hermes start

Downtime Infractions

At present, the consumer chain can report evidence about downtime infractions to the provider chain. The min_signed_per_window and signed_blocks_window can be different on each consumer chain and are subject to changes via consumer chain governance.

info

Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains.

To unjail, the validator must wait for the jailing period to elapse on the provider chain and submit an unjail transaction on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains.

More information is available in Downtime Slashing documentation

Double-signing Infractions

To learn more about equivocation handling in replicated security check out the Slashing documentation section.

Key assignment

Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use.

For more information check our the Key assignment overview and guide

References:

+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/validators/overview.html.html b/legacy/v3.3.0/validators/overview.html.html new file mode 100644 index 0000000000..636b99eed4 --- /dev/null +++ b/legacy/v3.3.0/validators/overview.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/v3.3.0/validators/withdraw_rewards.html b/legacy/v3.3.0/validators/withdraw_rewards.html new file mode 100644 index 0000000000..97105e57ce --- /dev/null +++ b/legacy/v3.3.0/validators/withdraw_rewards.html @@ -0,0 +1,20 @@ + + + + + +Withdrawing consumer chain validator rewards | Interchain Security + + + + +
+
Version: v3.3.0

Withdrawing consumer chain validator rewards

Here are example steps for withdrawing rewards from consumer chains in the provider chain

info

The examples used are from rs-testnet, the replicated security persistent testnet.

Validator operator address: cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 +Self-delegation address: cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

Prior to withdrawing rewards, query balances for self-delegation address:

gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

balances:
- amount: "1000000000000"
denom: uatom
pagination:
next_key: null
total: "0"

Querying validator rewards

Query rewards for the validator address:

gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6

rewards:
- amount: "158.069895000000000000"
denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD
- amount: "841842390516.072526500000000000"
denom: uatom

The ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD denom represents rewards from a consumer chain.

Withdrawing rewards and commission

1. Withdraw rewards

gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y

txhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A

2. Confirm withdrawal

After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:

gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

balances:
- amount: "216"
denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD
- amount: "2233766225342"
denom: uatom
pagination:
next_key: null
total: "0"
+ + + + \ No newline at end of file diff --git a/legacy/v3.3.0/validators/withdraw_rewards.html.html b/legacy/v3.3.0/validators/withdraw_rewards.html.html new file mode 100644 index 0000000000..91b3c438d8 --- /dev/null +++ b/legacy/v3.3.0/validators/withdraw_rewards.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/validators/changeover-procedure.html b/legacy/validators/changeover-procedure.html new file mode 100644 index 0000000000..afcbd37ae3 --- /dev/null +++ b/legacy/validators/changeover-procedure.html @@ -0,0 +1,21 @@ + + + + + +Validator instructions for Changeover Procedure | Interchain Security + + + + +
+
Version: Next

Validator instructions for Changeover Procedure

More details available in Changeover Procedure documentation.

A major difference betwen launching a new consumer chain vs. onboarding a standalone chain to ICS is that there is no consumer genesis available for the standalone chain. Since a standalone chain already exists, its state must be preserved once it transitions to being a consumer chain.

Timeline

Upgrading standalone chains can be best visualised using a timeline, such as the one available Excalidraw graphic by Stride.

There is some flexibility with regards to how the changeover procedure is executed, so please make sure to follow the guides provided by the team doing the changeover.

Standalone to consumer transition timeline

1. ConsumerAdditionProposal on provider chain

This step will add the standalone chain to the list of consumer chains secured by the provider. +This step dictates the spawn_time. After spawn_time the CCV state (initial validator set of the provider) will be available to the consumer.

To obtain it from the provider use:

gaiad q provider consumer-genesis stride-1 -o json > ccv-state.json
jq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' genesis.json ccv-state.json > ccv.json

2. SoftwareUpgradeProposal on the standalone/consumer chain

This upgrade proposal will introduce ICS to the standalone chain, making it a consumer.

3. Assigning a consumer key

After spawn_time, make sure to assign a consumer key if you intend to use one.

Instructions are available here

4. Perform the software ugprade on standalone chain

Please use instructions provided by the standalone chain team and make sure to reach out if you are facing issues. +The upgrade preparation depends on your setup, so please make sure you prepare ahead of time.

danger

The ccv.json from step 1. must be made available on the machine running the standalone/consumer chain at standalone chain upgrade_height. This file contains the initial validator set and parameters required for normal ICS operation.

Usually, the file is placed in $NODE_HOME/config but this is not a strict requirement. The exact details are available in the upgrade code of the standalone/consumer chain.

Performing this upgrade will transition the standalone chain to be a consumer chain.

After 3 blocks, the standalone chain will stop using the "old" validator set and begin using the provider validator set.

FAQ

Can I reuse the same validator key for the consumer chain that I am already using on the standalone chain? Will I need to perform a AssignConsumerKey tx with this key before spawn time?

Validators must either assign a key or use the same key as on the provider.

If you are validating both the standalone and the provider, you can use your current standalone key with some caveats:

  • you must submit an AssignConsumerKey tx with your current standalone validator key
  • it is best to submit AssignConsumerKey tx before spawn_time
  • if you do not submit the Tx, it is assumed that you will be re-using your provider key to validate the standalone/consumer chain

Can I continue using the same node that was validating the standalone chain?

Yes.

Please assign your consensus key as stated aboce.

Can I set up a new node to validate the standalone/consumer chain after it transitions to replicated security?

Yes.

If you are planning to do this please make sure that the node is synced with standalone network and to submit AssignConsumerKey tx before spawn_time.

What happens to the standalone validator set after it after it transitions to replicated security?

The standalone chain validators will stop being validators after the first 3 blocks are created while using replicated security. The standalone validators will become governors and still can receive delegations if the consumer chain is using the consumer-democracy module.

Governors DO NOT VALIDATE BLOCKS.

Instead, they can participate in the governance process and take on other chain-specific roles.

Credits

Thank you Stride team for providing detailed instructions about the changeover procedure.

+ + + + \ No newline at end of file diff --git a/legacy/validators/changeover-procedure.html.html b/legacy/validators/changeover-procedure.html.html new file mode 100644 index 0000000000..a2109d297c --- /dev/null +++ b/legacy/validators/changeover-procedure.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/validators/joining-neutron.html b/legacy/validators/joining-neutron.html new file mode 100644 index 0000000000..924800d3de --- /dev/null +++ b/legacy/validators/joining-neutron.html @@ -0,0 +1,19 @@ + + + + + +Joining Neutron | Interchain Security + + + + +
+
Version: Next

Joining Neutron

Neutron is the first consumer chain to implement ICS.

You can find instructions on joining the mainnet here.

To join Neutron chain on the replicated security testnet check here

Resources

+ + + + \ No newline at end of file diff --git a/legacy/validators/joining-neutron.html.html b/legacy/validators/joining-neutron.html.html new file mode 100644 index 0000000000..f68ae602e3 --- /dev/null +++ b/legacy/validators/joining-neutron.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/validators/joining-stride.html b/legacy/validators/joining-stride.html new file mode 100644 index 0000000000..af403c86e5 --- /dev/null +++ b/legacy/validators/joining-stride.html @@ -0,0 +1,19 @@ + + + + + +Joining Stride | Interchain Security + + + + +
+
Version: Next

Joining Stride

Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.

stride-1 network (mainnet) will perform a software upgrade and at height 4616678 that will transition the network to using the Cosmos Hub's (cosmoshub-4) validator set.

You can find instructions about the Stride consumer chain launch and joining the mainnet here.

This Excalidraw graphic explains the timeline of Stride's changeover procedure.

Note

Stride re-uses an existing transfer channel to send consumer rewards to the provider chain, in order to preserve existing transfer IBC denom between stride-1 and cosmoshub-4.

Resources

+ + + + \ No newline at end of file diff --git a/legacy/validators/joining-stride.html.html b/legacy/validators/joining-stride.html.html new file mode 100644 index 0000000000..a880eac8f9 --- /dev/null +++ b/legacy/validators/joining-stride.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/validators/joining-testnet.html b/legacy/validators/joining-testnet.html new file mode 100644 index 0000000000..e3a0ebeb8b --- /dev/null +++ b/legacy/validators/joining-testnet.html @@ -0,0 +1,20 @@ + + + + + +Joining Replicated Security testnet | Interchain Security + + + + +
+
Version: Next

Joining Replicated Security testnet

Introduction

This short guide will teach you how to join the Replicated Security testnet.

The experience gained in the testnet will prepare you for validating interchain secured chains.

tip

Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set.

For general information about running cosmos-sdk based chains check out the validator basics and Running a Node section of Cosmos SDK docs

Joining the provider chain

info

At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain.

A comprehensive guide is available here.

Initialization

First, initialize your $NODE_HOME using the provider chain binary.

NODE_MONIKER=<your_node>
CHAIN_ID=provider
NODE_HOME=<path_to_your_home>

gaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME

Add your key to the keyring - more details available here.

In this example we will use the test keyring-backend. This option is not safe to use in production.

gaiad keys add <key_moniker> --keyring-backend test

# save the address as variable for later use
MY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)

Before issuing any transactions, use the provider testnet faucet to add funds to your address.

curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider

# example output:
{
"address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",
"amount": "10000000uatom",
"chain": "provider",
"hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",
"status": "success"
}

Then, use the account associated with the keyring to issue a create-validator transaction which will register your validator on chain.

gaiad tx staking create-validator \
--amount=1000000uatom \
--pubkey=$(gaiad tendermint show-validator) \
--moniker="choose a moniker" \
--chain-id=$CHAIN_ID" \
--commission-rate="0.10" \
--commission-max-rate="0.20" \
--commission-max-change-rate="0.01" \
--min-self-delegation="1000000" \
--gas="auto" \
--gas-prices="0.0025uatom" \
--from=<key_moniker>
tip

Check this guide to edit your validator.

After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use statesync to catch up to the rest of the network.

You can use this script to modify your config.toml with the required statesync parameters.

# create the statesync script
$: cd $NODE_HOME
$: touch statesync.sh
$ chmod 700 statesync.sh # make executable

Paste the following instructions into the statesync.sh:

#!/bin/bash

SNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"

LATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \
BLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \
TRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)

sed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\1true| ; \
s|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\1\"$SNAP_RPC,$SNAP_RPC\"| ; \
s|^(trust_height[[:space:]]+=[[:space:]]+).*$|\1$BLOCK_HEIGHT| ; \
s|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\1\"$TRUST_HASH\"|" $NODE_HOME/config/config.toml

Then, you can execute the script:

$: ./statesync.sh # setup config.toml for statesync

Finally, copy the provider genesis and start your node:

$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/replicated-security/provider/provider-genesis.json
$: wget $GENESIS_URL -O genesis.json
$: genesis.json $NODE_HOME/config/genesis.json
# start the service
$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"

Additional scripts to setup your nodes are available here and here. The scripts will configure your node and create the required services - the scripts only work in linux environments.

Joining consumer chains

tip

Once you reach the active set on the provider chain, you will be required to validate all available consumer chains.

You can use the same consensus key on all consumer chains, or opt to use a different key on each consumer chain. +Check out this guide to learn more about key assignment in replicated security.

To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries.

info

When running the provider chain and consumers on the same machine please update the PORT numbers for each of them and make sure they do not overlap (otherwise the binaries will not start).

Important ports to re-configure:

  • --rpc.laddr
  • --p2p.laddr
  • --api.address
  • --grpc.address
  • --grpc-web.address

Re-using consensus key

To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the priv_validator_key.json into the home directory of your consumer chain (<consumer_home>/config/priv_validator_key.json).

When you start the chain, the consensus key will be the same on the provider and the consumer chain.

Assigning consensus keys

Whenever you initialize a new node, it will be configured with a consensus key you can use.

# machine running consumer chain
consumerd init <node_moniker> --home <home_path> --chain-id consumer-1

# use the output of this command to get the consumer chain consensus key
consumerd tendermint show-validator
# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}

Then, let the provider know which key you will be using for the consumer chain:

# machine running the provider chain
gaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b sync -y -o json

After this step, you are ready to copy the consumer genesis into your nodes's /config folder, start your consumer chain node and catch up to the network.

+ + + + \ No newline at end of file diff --git a/legacy/validators/joining-testnet.html.html b/legacy/validators/joining-testnet.html.html new file mode 100644 index 0000000000..ea899a9f58 --- /dev/null +++ b/legacy/validators/joining-testnet.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/validators/overview.html b/legacy/validators/overview.html new file mode 100644 index 0000000000..7e2b09e4cb --- /dev/null +++ b/legacy/validators/overview.html @@ -0,0 +1,24 @@ + + + + + +Overview | Interchain Security + + + + +
+
Version: Next

Overview

tip

We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.

At present, replicated security requires all validators of the provider chain (ie. Cosmos Hub) to run validator nodes for all governance-approved consumer chains.

Once a ConsumerAdditionProposal passes, validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains.

Provider chain and consumer chains represent standalone chains that only share the validator set ie. the same validator operators are tasked with running all chains.

info

To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 180 validators for Cosmos Hub).

Startup sequence overview

Consumer chains cannot start and be secured by the validator set of the provider unless a ConsumerAdditionProposal is passed. +Each proposal contains defines a spawn_time - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider.

tip

Validators are required to run consumer chain binaries only after spawn_time has passed.

Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains.

The image below illustrates the startup sequence +startup

1. Consumer Chain init + 2. Genesis generation

Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ConsumerAdditionProposal

3. Submit Proposal

Consumer chain team (or their advocates) submits a ConsumerAdditionProposal. +The most important parameters for validators are:

  • spawn_time - the time after which the consumer chain must be started
  • genesis_hash - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and spawn_time is reached
  • binary_hash - hash of the consumer chain binary used to validate the software builds

4. CCV Genesis state generation

After reaching spawn_time the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain genesis.json. The CCV validator set consists of the validator set on the provider at spawn_time.

The state can be queried on the provider chain (in this case the Cosmos Hub):

 gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json

This is used by the launch coordinator to create the final genesis.json that will be distributed to validators in step 5.

5. Updating the genesis file

Upon reaching the spawn_time the initial validator set state will become available on the provider chain. The initial validator set is included in the final genesis.json of the consumer chain.

6. Chain start

info

The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences.

The new genesis.json containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided genesis.json to start their consumer chain node.

tip

Please pay attention to any onboarding repositories provided by the consumer chain teams. +Recommendations are available in Consumer Onboarding Checklist. +Another comprehensive guide is available in the Replicated Security testnet repo.

7. Creating IBC connections

Finally, to fully establish replicated security an IBC relayer is used to establish connections and create the required channels.

danger

The relayer can establish the connection only after the consumer chain starts producing blocks.

hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> 
hermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1
hermes start

Downtime Infractions

At present, the consumer chain can report evidence about downtime infractions to the provider chain. The min_signed_per_window and signed_blocks_window can be different on each consumer chain and are subject to changes via consumer chain governance.

info

Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains.

To unjail, the validator must wait for the jailing period to elapse on the provider chain and submit an unjail transaction on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains.

More information is available in Downtime Slashing documentation

Double-signing Infractions

To learn more about equivocation handling in replicated security check out the Slashing and EquivocationProposal documentation sections

Key assignment

Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use.

For more information check our the Key assignment overview and guide

References:

+ + + + \ No newline at end of file diff --git a/legacy/validators/overview.html.html b/legacy/validators/overview.html.html new file mode 100644 index 0000000000..f9d237807a --- /dev/null +++ b/legacy/validators/overview.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/legacy/validators/withdraw_rewards.html b/legacy/validators/withdraw_rewards.html new file mode 100644 index 0000000000..969c1bf4cf --- /dev/null +++ b/legacy/validators/withdraw_rewards.html @@ -0,0 +1,20 @@ + + + + + +Withdrawing consumer chain validator rewards | Interchain Security + + + + +
+
Version: Next

Withdrawing consumer chain validator rewards

Here are example steps for withdrawing rewards from consumer chains in the provider chain

info

The examples used are from rs-testnet, the replicated security persistent testnet.

Validator operator address: cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 +Self-delegation address: cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

Prior to withdrawing rewards, query balances for self-delegation address:

gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

balances:
- amount: "1000000000000"
denom: uatom
pagination:
next_key: null
total: "0"

Querying validator rewards

Query rewards for the validator address:

gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6

rewards:
- amount: "158.069895000000000000"
denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD
- amount: "841842390516.072526500000000000"
denom: uatom

The ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD denom represents rewards from a consumer chain.

Withdrawing rewards and commission

1. Withdraw rewards

gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y

txhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A

2. Confirm withdrawal

After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:

gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

balances:
- amount: "216"
denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD
- amount: "2233766225342"
denom: uatom
pagination:
next_key: null
total: "0"
+ + + + \ No newline at end of file diff --git a/legacy/validators/withdraw_rewards.html.html b/legacy/validators/withdraw_rewards.html.html new file mode 100644 index 0000000000..9eaafb2d0a --- /dev/null +++ b/legacy/validators/withdraw_rewards.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/main/index.html b/main/index.html new file mode 100644 index 0000000000..b237719ca6 --- /dev/null +++ b/main/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000000..10ed1b9181 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1 @@ +https://cosmos.github.io/interchain-security/v4.2.0weekly0.5https://cosmos.github.io/interchain-security/v4.2.0/adrs/adr-001-key-assignmentweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/adrs/adr-002-throttleweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/adrs/adr-003-equivocation-gov-proposalweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/adrs/adr-004-denom-dos-fixesweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/adrs/adr-005-cryptographic-equivocation-verificationweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/adrs/adr-007-pause-unbonding-on-eqv-propweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/adrs/adr-008-throttle-retriesweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/adrs/adr-009-soft-opt-outweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/adrs/adr-010-standalone-changeoverweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/adrs/adr-011-improving-test-confidenceweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/adrs/adr-012-separate-releasingweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/adrs/adr-013-equivocation-slashingweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/adrs/adr-014-epochsweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/adrs/adr-015-partial-set-securityweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/adrs/adr-templateweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/adrs/introweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/consumer-development/app-integrationweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/consumer-development/changeover-procedureweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/consumer-development/consumer-chain-governanceweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/consumer-development/consumer-genesis-transformationweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/consumer-development/offboardingweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/consumer-development/onboardingweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/faqweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/features/key-assignmentweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/features/partial-set-securityweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/features/power-shapingweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/features/proposalsweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/features/reward-distributionweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/features/slashingweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/introduction/overviewweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/introduction/paramsweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/introduction/technical-specificationweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/introduction/terminologyweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/validators/changeover-procedureweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/validators/joining-neutronweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/validators/joining-strideweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/validators/joining-testnetweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/validators/overviewweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/validators/partial-set-security-for-validatorsweekly0.5https://cosmos.github.io/interchain-security/v4.2.0/validators/withdraw_rewardsweekly0.5https://cosmos.github.io/interchain-security/v5.0.0weekly0.5https://cosmos.github.io/interchain-security/v5.0.0/adrs/adr-001-key-assignmentweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/adrs/adr-002-throttleweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/adrs/adr-003-equivocation-gov-proposalweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/adrs/adr-004-denom-dos-fixesweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/adrs/adr-005-cryptographic-equivocation-verificationweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/adrs/adr-007-pause-unbonding-on-eqv-propweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/adrs/adr-008-throttle-retriesweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/adrs/adr-009-soft-opt-outweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/adrs/adr-010-standalone-changeoverweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/adrs/adr-011-improving-test-confidenceweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/adrs/adr-012-separate-releasingweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/adrs/adr-013-equivocation-slashingweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/adrs/adr-014-epochsweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/adrs/adr-015-partial-set-securityweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/adrs/adr-templateweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/adrs/introweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/consumer-development/app-integrationweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/consumer-development/changeover-procedureweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/consumer-development/consumer-chain-governanceweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/consumer-development/consumer-genesis-transformationweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/consumer-development/offboardingweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/consumer-development/onboardingweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/faqweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/features/key-assignmentweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/features/proposalsweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/features/reward-distributionweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/features/slashingweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/introduction/overviewweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/introduction/paramsweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/introduction/technical-specificationweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/introduction/terminologyweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/upgrading/migrate_v4_v5weekly0.5https://cosmos.github.io/interchain-security/v5.0.0/validators/changeover-procedureweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/validators/joining-neutronweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/validators/joining-strideweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/validators/joining-testnetweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/validators/overviewweekly0.5https://cosmos.github.io/interchain-security/v5.0.0/validators/withdraw_rewardsweekly0.5https://cosmos.github.io/interchain-security/adrs/adr-001-key-assignmentweekly0.5https://cosmos.github.io/interchain-security/adrs/adr-002-throttleweekly0.5https://cosmos.github.io/interchain-security/adrs/adr-003-equivocation-gov-proposalweekly0.5https://cosmos.github.io/interchain-security/adrs/adr-004-denom-dos-fixesweekly0.5https://cosmos.github.io/interchain-security/adrs/adr-005-cryptographic-equivocation-verificationweekly0.5https://cosmos.github.io/interchain-security/adrs/adr-007-pause-unbonding-on-eqv-propweekly0.5https://cosmos.github.io/interchain-security/adrs/adr-008-throttle-retriesweekly0.5https://cosmos.github.io/interchain-security/adrs/adr-009-soft-opt-outweekly0.5https://cosmos.github.io/interchain-security/adrs/adr-010-standalone-changeoverweekly0.5https://cosmos.github.io/interchain-security/adrs/adr-011-improving-test-confidenceweekly0.5https://cosmos.github.io/interchain-security/adrs/adr-012-separate-releasingweekly0.5https://cosmos.github.io/interchain-security/adrs/adr-013-equivocation-slashingweekly0.5https://cosmos.github.io/interchain-security/adrs/adr-014-epochsweekly0.5https://cosmos.github.io/interchain-security/adrs/adr-015-partial-set-securityweekly0.5https://cosmos.github.io/interchain-security/adrs/adr-016-securityaggregationweekly0.5https://cosmos.github.io/interchain-security/adrs/adr-017-allowing-inactive-validatorsweekly0.5https://cosmos.github.io/interchain-security/adrs/introweekly0.5https://cosmos.github.io/interchain-security/consumer-development/app-integrationweekly0.5https://cosmos.github.io/interchain-security/consumer-development/changeover-procedureweekly0.5https://cosmos.github.io/interchain-security/consumer-development/consumer-chain-governanceweekly0.5https://cosmos.github.io/interchain-security/consumer-development/consumer-genesis-transformationweekly0.5https://cosmos.github.io/interchain-security/consumer-development/offboardingweekly0.5https://cosmos.github.io/interchain-security/consumer-development/onboardingweekly0.5https://cosmos.github.io/interchain-security/faqweekly0.5https://cosmos.github.io/interchain-security/features/democracy-modulesweekly0.5https://cosmos.github.io/interchain-security/features/key-assignmentweekly0.5https://cosmos.github.io/interchain-security/features/partial-set-securityweekly0.5https://cosmos.github.io/interchain-security/features/power-shapingweekly0.5https://cosmos.github.io/interchain-security/features/proposalsweekly0.5https://cosmos.github.io/interchain-security/features/reward-distributionweekly0.5https://cosmos.github.io/interchain-security/features/slashingweekly0.5https://cosmos.github.io/interchain-security/introduction/overviewweekly0.5https://cosmos.github.io/interchain-security/introduction/paramsweekly0.5https://cosmos.github.io/interchain-security/introduction/technical-specificationweekly0.5https://cosmos.github.io/interchain-security/introduction/terminologyweekly0.5https://cosmos.github.io/interchain-security/upgrading/migrate_v4_v5weekly0.5https://cosmos.github.io/interchain-security/validators/changeover-procedureweekly0.5https://cosmos.github.io/interchain-security/validators/joining-neutronweekly0.5https://cosmos.github.io/interchain-security/validators/joining-strideweekly0.5https://cosmos.github.io/interchain-security/validators/joining-testnetweekly0.5https://cosmos.github.io/interchain-security/validators/overviewweekly0.5https://cosmos.github.io/interchain-security/validators/partial-set-security-for-validatorsweekly0.5https://cosmos.github.io/interchain-security/validators/withdraw_rewardsweekly0.5https://cosmos.github.io/interchain-security/weekly0.5 \ No newline at end of file diff --git a/upgrading/migrate_v4_v5.html b/upgrading/migrate_v4_v5.html new file mode 100644 index 0000000000..ee6351c553 --- /dev/null +++ b/upgrading/migrate_v4_v5.html @@ -0,0 +1,128 @@ + + + + + +Upgrading to ICS v5.0.0 | Interchain Security + + + + +
Version: main

Upgrading to ICS v5.0.0

+

This ICS version uses cosmos-sdk v0.50.x and ibc-go v8.x.

+

To migrate you application to cosmos-sdk v0.50.x please use this guide.

+

To migrate your application to ibc-go v8.x.y please use the following guides:

+ +

ICS specific changes are outlined below.

+

Pre-requisite version for this upgrade: v4.x.

+

Provider

+

Keeper initialization

+
// app.go

app.ProviderKeeper = ibcproviderkeeper.NewKeeper(
appCodec,
keys[providertypes.StoreKey],
app.GetSubspace(providertypes.ModuleName),
scopedIBCProviderKeeper,
app.IBCKeeper.ChannelKeeper,
- app.IBCKeeper.PortKeeper
+ app.IBCKeeper.PortKeeper,
app.IBCKeeper.ConnectionKeeper,
app.IBCKeeper.ClientKeeper,
app.StakingKeeper,
app.SlashingKeeper,
app.AccountKeeper,
app.DistrKeeper,
app.BankKeeper,
*app.GovKeeper,
+ authtypes.NewModuleAddress(govtypes.ModuleName).String(),
+ authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),
+ authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()),
authtypes.FeeCollectorName,
)
+
    +
  • +

    authority was added - requirement for executing MsgUpdateParams

    +
      +
    • uses x/gov module address by default
    • +
    +
  • +
  • +

    validatorAddressCodec & consensusAddressCodec were added - they must match the bech32 address codec used by x/auth, x/bank, x/staking

    +
  • +
+

Protocol changes

+

Revert AfterUnbondingInitiated

+

AfterUnbondingInitiated behavior was reverted to ICS@v1.2.0-multiden

+

The revert re-introduces an additional state check.

+

See this issue for more context and the actions taken.

+

Migration (v4 -> v5)

+

ConensusVersion was bumped to 5.

+

The migration allows storing the provider module params in the x/ccv/provider module store instead of relying on legacy x/param store.

+

There are no special requirements for executing this migration.

+

Additions

+

MsgUpdateParams transaction

+

x/gov module account is selected as the default authority.

+

It is available when using gov CLI commands:

+

Drafting a proposal:

+
interchain-security-pd tx gov draft-proposal
# select "other"
# find and select "/interchain_security.ccv.provider.v1.MsgUpdateParams"
+

Submitting a proposal:

+
interchain-security-pd tx gov submit-proposal <proposal-message.json>
+

Example proposal-message.json:

+
{
"messages": [
{
"@type": "/interchain_security.ccv.provider.v1.MsgUpdateParams",
"authority": "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn",
"params": {
"trusting_period_fraction": "0.66",
"ccv_timeout_period": "2419200s",
"init_timeout_period": "604800s",
"vsc_timeout_period": "3024000s",
"slash_meter_replenish_period": "3s",
"slash_meter_replenish_fraction": "1.0",
"consumer_reward_denom_registration_fee": {
"denom": "stake",
"amount": "10000000"
},
"blocks_per_epoch": "600"
}
}
],
"metadata": "ipfs://CID",
"deposit": "10000stake",
"title": "Update Provider params",
"summary": "Update Provider params",
"expedited": false
}
+

+

When updating parameters all parameters fields must be specified. Make sure you are only changing parameters that you are interested in.

+

To avoid accidentally changing parameters you can first check the current on-chain provider params using:

+
interchain-security-pd q provider params -o json

{
"template_client": {...},
"trusting_period_fraction": "0.66",
"ccv_timeout_period": "2419200s",
"init_timeout_period": "604800s",
"vsc_timeout_period": "3024000s",
"slash_meter_replenish_period": "3s",
"slash_meter_replenish_fraction": "1.0",
"consumer_reward_denom_registration_fee": {
"denom": "stake",
"amount": "10000000"
},
"blocks_per_epoch": "600"
}
+

Governance proposals

+

Submitting the following legacy proposals is still supported:

+

Consumer addition proposal

+
interchain-security-pd tx gov submit-legacy-proposal consumer-addition <proposal_file.json>
+

Consumer removal proposal

+
interchain-security-pd tx gov submit-legacy-proposal consumer-removal <proposal_file.json>
+

Consumer addition proposal

+
interchain-security-pd tx gov submit-legacy-proposal change-reward-denoms <proposal_file.json>
+

You may also submit proposal messages above using submit-proposal.

+

Consumer

+

Keeper initialization

+
// pre-initialize ConsumerKeeper to satsfy ibckeeper.NewKeeper
app.ConsumerKeeper = ibcconsumerkeeper.NewNonZeroKeeper(
appCodec,
keys[ibcconsumertypes.StoreKey],
app.GetSubspace(ibcconsumertypes.ModuleName),
)

app.IBCKeeper = ibckeeper.NewKeeper(
appCodec,
keys[ibchost.StoreKey],
app.GetSubspace(ibchost.ModuleName),
app.ConsumerKeeper,
app.UpgradeKeeper,
scopedIBCKeeper,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

// initialize the actual consumer keeper
app.ConsumerKeeper = ibcconsumerkeeper.NewKeeper(
appCodec,
keys[ibcconsumertypes.StoreKey],
app.GetSubspace(ibcconsumertypes.ModuleName),
scopedIBCConsumerKeeper,
app.IBCKeeper.ChannelKeeper,
- &app.IBCKeeper.PortKeeper,
+ app.IBCKeeper.PortKeeper,
app.IBCKeeper.ConnectionKeeper,
app.IBCKeeper.ClientKeeper,
app.SlashingKeeper,
app.BankKeeper,
app.AccountKeeper,
&app.TransferKeeper,
app.IBCKeeper,
authtypes.FeeCollectorName,

// make sure the authority address makes sense for your chain
// the exact module account may differ depending on your setup (x/gov, x/admin or custom module)
// for x/ccv/democracy using the x/gov module address is correct
// if you don't have a way of updating consumer params you may still use the line below as it will have no affect
+ authtypes.NewModuleAddress(govtypes.ModuleName).String(),

// add address codecs
+ authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),
+ authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()),
)
+
    +
  • +

    authority was added - requirement for executing MsgUpdateParams

    +
      +
    • make sure the authority address makes sense for your chain
    • +
    • the exact module account may differ depending on your setup (x/gov, x/admin or custom module)
    • +
    • for x/ccv/democracy using the x/gov module address is correct
    • +
    • if you don't have a way of updating consumer params you may use authtypes.NewModuleAddress(govtypes.ModuleName).String() (has no effect on functionality)
    • +
    +
  • +
  • +

    validatorAddressCodec & consensusAddressCodec were added - they must match the bech32 address codec used by x/auth, x/bank, x/staking

    +
  • +
+

Additions

+

MsgUpdateParams transaction

+

This functionality is not supported on x/ccv/consumer without additional configuration.

+
    +
  • if you are using x/ccv/democracy the feature is supported out of the box
  • +
  • if you are using custom logic for changing consumer params, please update your code by providing the appropriate authority module account during ConsumerKeeper initialization in app.go.
  • +
+

You must add "/interchain_security.ccv.consumer.v1.MsgUpdateParams" to your parameters whitelist to be able to change ccvconsumer parameters via governance.

+

It is available when using gov CLI commands:

+

Drafting a proposal:

+
interchain-security-cd tx gov draft-proposal
# select "other"
# find and select "/interchain_security.ccv.consumer.v1.MsgUpdateParams"
+

Submitting a proposal:

+
    +
  • this proposal cannot be executed on chains without access to x/gov or other modules for managing governance
  • +
+

interchain-security-cdd tx gov submit-proposal <proposal-message.json>

+

Example proposal-message.json.

+
{
"messages": [
{
"@type": "/interchain_security.ccv.consumer.v1.MsgUpdateParams",
"authority": "consumer10d07y265gmmuvt4z0w9aw880jnsr700jlh7295",
"params": {
"enabled": true,
"blocks_per_distribution_transmission": "20",
"distribution_transmission_channel": "channel-1",
"provider_fee_pool_addr_str": "",
"ccv_timeout_period": "2419200s",
"transfer_timeout_period": "3000s",
"consumer_redistribution_fraction": "0.75",
"historical_entries": "10000",
"unbonding_period": "1209600s",
"soft_opt_out_threshold": "0.05",
"reward_denoms": [],
"provider_reward_denoms": [],
"retry_delay_period": "3000s"
}
}
],
"metadata": "ipfs://CID",
"deposit": "1000uatom",
"title": "Update Consumer Params -- change transfer_timeout_period to 3000s",
"summary": "Test Update Consumer Params",
"expedited": false
}
+

When updating parameters all parameters fields must be specified. Make sure you are only changing parameters that you are interested in.

+

To avoid accidentally changing parameters you can first check the current on-chain consumer params using:

+
interchain-security-pd q ccvconsumer params -o json
+

Params Query

+

Consumer params query was added:

+
interchain-security-cd q ccvconsumer params -o json

{
"params": {
"enabled": true,
"blocks_per_distribution_transmission": "1000",
"distribution_transmission_channel": "",
"provider_fee_pool_addr_str": "",
"ccv_timeout_period": "2419200s",
"transfer_timeout_period": "3600s",
"consumer_redistribution_fraction": "0.75",
"historical_entries": "10000",
"unbonding_period": "1209600s",
"soft_opt_out_threshold": "0.05",
"reward_denoms": [],
"provider_reward_denoms": [],
"retry_delay_period": "3600s"
}
}
+

Migration (v2 -> v3)

+

ConensusVersion was bumped to 3.

+

The migration allows storing the consumer module params in the x/ccv/consumer module store instead of relying on legacy x/param store.

+

There are no special requirements for executing this migration.

+

Interface method changes

+

Consumer methods were changed to match the cosmos-sdk StakingKeeper interface. +You will not need to change your code, unless you are using the ConsumerKeeper inside custom tests or you have developed custom app functionality that relies on ConsumerKeeper.

+

Please check the list below if you are using any of the consumer methods:

+
type StakingKeeper interface {
UnbondingTime(ctx context.Context) (time.Duration, error)
GetValidatorByConsAddr(ctx context.Context, consAddr sdk.ConsAddress) (stakingtypes.Validator, error)
GetLastValidatorPower(ctx context.Context, operator sdk.ValAddress) (int64, error)
Jail(context.Context, sdk.ConsAddress) error // jail a validator
Slash(ctx context.Context, consAddr sdk.ConsAddress, infractionHeight, power int64, slashFactor math.LegacyDec) (math.Int, error)
SlashWithInfractionReason(ctx context.Context, consAddr sdk.ConsAddress, infractionHeight, power int64, slashFactor math.LegacyDec, infraction stakingtypes.Infraction) (math.Int, error)
Unjail(ctx context.Context, addr sdk.ConsAddress) error
GetValidator(ctx context.Context, addr sdk.ValAddress) (stakingtypes.Validator, error)
IterateLastValidatorPowers(ctx context.Context, cb func(addr sdk.ValAddress, power int64) (stop bool)) error
IterateValidators(ctx context.Context, f func(index int64, validator stakingtypes.ValidatorI) (stop bool)) error
Validator(ctx context.Context, addr sdk.ValAddress) (stakingtypes.ValidatorI, error)
IsValidatorJailed(ctx context.Context, addr sdk.ConsAddress) (bool, error)
ValidatorByConsAddr(ctx context.Context, consAddr sdk.ConsAddress) (stakingtypes.ValidatorI, error)
Delegation(ctx context.Context, addr sdk.AccAddress, valAddr sdk.ValAddress) (stakingtypes.DelegationI, error)
MaxValidators(ctx context.Context) (uint32, error)
}
+

The consumer implements the StakingKeeper interface shown above.

+

Democracy

+

Changes in Consumer also apply to Democracy.

+

Democracy x/staking, x/distribution and x/gov were updated to reflect changes in cosmos-sdk v0.50.x.

+

There were no notable changes arising to the module functionality aside from conforming to cosmos-sdk v0.50.x.

+

Note:

+

You must add "/interchain_security.ccv.consumer.v1.MsgUpdateParams" to your parameters whitelist to be able to change consumer parameters via governance.

+ + \ No newline at end of file diff --git a/upgrading/migrate_v4_v5.html.html b/upgrading/migrate_v4_v5.html.html new file mode 100644 index 0000000000..245208be26 --- /dev/null +++ b/upgrading/migrate_v4_v5.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0.html b/v4.2.0.html new file mode 100644 index 0000000000..84d90dd16a --- /dev/null +++ b/v4.2.0.html @@ -0,0 +1,19 @@ + + + + + +Interchain Security Docs | Interchain Security + + + + +
+ + \ No newline at end of file diff --git a/v4.2.0.html.html b/v4.2.0.html.html new file mode 100644 index 0000000000..1438b9aab7 --- /dev/null +++ b/v4.2.0.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-001-key-assignment.html b/v4.2.0/adrs/adr-001-key-assignment.html new file mode 100644 index 0000000000..b61ecf9e2a --- /dev/null +++ b/v4.2.0/adrs/adr-001-key-assignment.html @@ -0,0 +1,79 @@ + + + + + +Key Assignment | Interchain Security + + + + +
Version: v4.2.0

ADR 001: Key Assignment

+

Changelog

+
    +
  • 2022-12-01: Initial Draft
  • +
  • 2024-03-01: Updated to take into account they key-assigment-replacement deprecation.
  • +
+

Status

+

Accepted

+

Context

+

KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate.

+

Decision

+

It is possible to change the keys at any time by submitting a transaction (i.e., MsgAssignConsumerKey).

+

State required

+
    +
  • ValidatorConsumerPubKey - Stores the validator assigned keys for every consumer chain.
  • +
+
ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey
+
    +
  • ValidatorByConsumerAddr - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol.
  • +
+
ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress
+
    +
  • ConsumerAddrsToPrune - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ValidatorByConsumerAddr.
  • +
+
ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses
+

Protocol overview

+

On receiving a MsgAssignConsumerKey(chainID, providerAddr, consumerKey) message:

+
// get validator from staking module  
validator, found := stakingKeeper.GetValidator(providerAddr)
if !found {
return ErrNoValidatorFound
}
providerConsAddr := validator.GetConsAddr()

// make sure consumer key is not in use
consumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)
if _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {
return ErrInvalidConsumerConsensusPubKey
}

// check whether the consumer chain is already registered
// i.e., a client to the consumer was already created
if _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {
// get the previous key assigned for this validator on this consumer chain
oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)
if found {
// mark this old consumer key as prunable once the VSCMaturedPacket
// for the current VSC ID is received
oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)
vscID := GetValidatorSetUpdateId()
AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)
}
} else {
// if the consumer chain is not registered, then remove the previous reverse mapping
if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {
oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)
DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)
}
}


// set the mapping from this validator's provider address to the new consumer key
SetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)

// set the reverse mapping: from this validator's new consensus address
// on the consumer to its consensus address on the provider
SetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)
+

When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see MakeConsumerGenesis).

+
func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {
// ...
// get initial valset from the staking module
var updates []abci.ValidatorUpdate{}
stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {
validator := stakingKeeper.GetValidator(providerAddr)
providerKey := validator.TmConsPublicKey()
updates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})
return false
})

// applies the key assignment to the initial validator
for i, update := range updates {
providerAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)
if consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {
updates[i].PubKey = consumerKey
}
}
gen.InitialValSet = updates

// get a hash of the consumer validator set from the update
updatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)
hash := tendermint.NewValidatorSet(updatesAsValSet).Hash()

return gen, hash, nil
}
+

Note that key assignment works hand-in-hand with epochs. +For each consumer chain, we store the consumer validator set that is currently (i.e., in this epoch) validating the consumer chain. +Specifically, for each validator in the set we store among others, the public key that it is using on the consumer chain during the current (i.e., ongoing) epoch. +At the end of every epoch, if there were validator set changes on the provider, then for every consumer chain, we construct a VSCPacket +with all the validator updates and add it to the list of PendingVSCPackets. We compute the validator updates needed by a consumer chain by +comparing the stored list of consumer validators with the current bonded validators on the provider, with something similar to this:

+
// get the valset that has been validating the consumer chain during this epoch 
currentValidators := GetConsumerValSet(consumerChain)
// generate the validator updates needed to be sent through a `VSCPacket` by comparing the current validators
// in the epoch with the latest bonded validators
valUpdates := DiffValidators(currentValidators, stakingmodule.GetBondedValidators())
// update the current validators set for the upcoming epoch to be the latest bonded validators instead
SetConsumerValSet(stakingmodule.GetBondedValidators())
+

where DiffValidators internally checks if the consumer public key for a validator has changed since the last +epoch and if so generates a validator update. This way, a validator can change its consumer public key for a consumer +chain an arbitrary amount of times and only the last set consumer public key would be taken into account.

+

On receiving a SlashPacket from a consumer chain with id chainID for a infraction of a validator data.Validator:

+
func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {
// ...
// the slash packet validator address may be known only on the consumer chain;
// in this case, it must be mapped back to the consensus address on the provider chain
consumerAddr := sdk.ConsAddress(data.Validator.Address)
providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)
if !found {
// the validator has the same key on the consumer as on the provider
providerAddr = consumerAddr
}
// ...
}
+

On receiving a VSCMatured:

+
func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {
// ...
// prune previous consumer validator address that are no longer needed
consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)
for _, addr := range consumerAddrs {
DeleteValidatorByConsumerAddr(chainID, addr)
}
DeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)
// ...
}
+

On stopping a consumer chain:

+
func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {
// ...
// deletes all the state needed for key assignments on this consumer chain
// ...
}
+

Consequences

+

Positive

+
    +
  • Validators can use different consensus keys on the consumer chains.
  • +
+

Negative

+
    +
  • None
  • +
+

Neutral

+
    +
  • The consensus state necessary to create a client to the consumer chain must use the hash returned by the MakeConsumerGenesis method as the nextValsHash.
  • +
  • The consumer chain can no longer check the initial validator set against the consensus state on InitGenesis.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-001-key-assignment.html.html b/v4.2.0/adrs/adr-001-key-assignment.html.html new file mode 100644 index 0000000000..c0759795d5 --- /dev/null +++ b/v4.2.0/adrs/adr-001-key-assignment.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-002-throttle.html b/v4.2.0/adrs/adr-002-throttle.html new file mode 100644 index 0000000000..f4c81b66ac --- /dev/null +++ b/v4.2.0/adrs/adr-002-throttle.html @@ -0,0 +1,164 @@ + + + + + +Jail Throttling | Interchain Security + + + + +
Version: v4.2.0

ADR 002: Jail Throttling

+

Changelog

+
    +
  • 2023-01-26: Initial Draft
  • +
  • 2023-02-07: Property refined, ADR ready to review/merge
  • +
  • 2023-11-22: Refactor for better understanding
  • +
+

Status

+

Accepted

+

Context

+

The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols. +In practice, this assumption may not hold. +A malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider.

+

Before the throttling feature was implemented, the following attack was possible. +Attacker(s) would create provider validators just below the provider's active set. +Using a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once. +Control of the provider would then pass over to the attackers' validators. +This enables the attacker(s) to halt the provider. +Or even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC.

+

Decision

+

The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack, +i.e., this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time.

+

Required State

+

Slash meter: There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time. +This meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params.

+

Global entry queue: There exists a single queue which stores "global slash entries". +These entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering. +This queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.

+

Per-chain data queue: For each established consumer, there exists a queue which stores "throttled packet data", +i.e.,pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering. +Order is enforced by IBC sequence number. +These "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.

+

Note: The reason for a multiple-queue design is the VSC Maturity and Slashing Order property (see spec). +There are other ways to ensure such a property (like a queue of linked lists, etc.), but the proposed approach seemed to be the most understandable and easiest to implement with a KV store.

+

Params

+

SlashMeterReplenishPeriod -- the period after which the slash meter is replenished.

+

SlashMeterReplenishFraction -- the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs. This param also serves as a maximum fraction of total voting power that the slash meter can hold.

+

MaxThrottledPackets -- the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value. +This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness.

+

Protocol Overview

+

OnRecvSlashPacket

+

Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:

+
    +
  1. A global slash entry is queued.
  2. +
  3. The data of such a packet is added to the per-chain queue.
  4. +
+

OnRecvVSCMaturedPacket

+

Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue.

+

Endblocker

+

In the EndBlock of the provider CCV module, there are three actions performed:

+
    +
  • replenish the slash meter;
  • +
  • handle the leading VSCMaturedPackets;
  • +
  • and handle the throttle queues.
  • +
+
Slash Meter Replenishment
+

Once the slash meter becomes not full, it'll be replenished after SlashMeterReplenishPeriod by incrementing the meter with its allowance for the replenishment block, where allowance = SlashMeterReplenishFraction * currentTotalVotingPower. +The slash meter will never exceed its current allowance (function of the total voting power for the block) in value.

+

Note a few things:

+
    +
  1. The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power. +In such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods.
  2. +
  3. Total voting power of a chain changes over time, especially as validators are jailed. +As validators are jailed, total voting power decreases, and so does the jailing allowance. +See below for more detailed throttling property discussion.
  4. +
  5. The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1. +If the SlashMeterReplenishFraction is set too low, integer rounding will put this minimum value into effect. +That is, if SlashMeterReplenishFraction * currentTotalVotingPower < 1, then the effective allowance would be 1. +This min value of allowance ensures that there's some packets handled over time, even if that is a very long time. +It's a crude solution to an edge case caused by too small of a replenishment fraction.
  6. +
+

The behavior described above is achieved by executing CheckForSlashMeterReplenishment() every EndBlock, BEFORE HandleThrottleQueues() is executed.

+
Handle Leading VSCMaturedPackets
+

In every block, it is possible that VSCMaturedPacket data was queued before any slash packet data. +Since this "leading" VSCMatured packet data does not have to be throttled (see VSC Maturity and Slashing Order), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes.

+
Handle Throttle Queues
+

In every EndBlock, the following logic is executed to handle data from the throttle queues.

+
meter := getSlashMeter()

// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist
while meter.IsPositiveOrZero() && entriesExist() {
// Get next entry in queue
entry := getNextGlobalSlashEntry()
// Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet
valPower := entry.getValPower()
meter = meter - valPower
// Using the per-chain queue, handle the single slash packet using its queued data,
// then handle all trailing VSCMatured packets for this consumer
handleSlashPacketAndTrailingVSCMaturedPackets(entry)
// Delete entry in global queue, delete handled data
entry.Delete()
deleteThrottledSlashPacketData()
deleteTrailingVSCMaturedPacketData()
}
+

System Properties

+

All CCV system properties should be maintained by implementing this feature, see CCV spec - Consumer Initiated Slashing.

+

One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than MaxThrottledPackets, then the provider binary will panic, and the provider chain will halt. +Therefore this param should be set carefully. See SetThrottledPacketDataSize. +This behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators.

+

Main Throttling Property

+

Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions.

+

First, we introduce the following definitions:

+
    +
  • A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.
  • +
  • The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.
  • +
  • There is a list of honest validators such that if they are jailed, X% of the initial validator set will be jailed.
  • +
+

For the Throttling Property to hold, the following assumptions must be true:

+
    +
  1. We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack.
  2. +
  3. No validator has more than SlashMeterReplenishFraction of total voting power on the provider.
  4. +
  5. SlashMeterReplenishFraction is large enough that SlashMeterReplenishFraction * currentTotalVotingPower > 1, +i.e., the replenish fraction is set high enough that we can ignore the effects of rounding.
  6. +
  7. SlashMeterReplenishPeriod is sufficiently longer than the time it takes to produce a block.
  8. +
+

Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined.

+

Throttling Property: The time it takes to jail/tombstone X% of the initial validator set will be greater than or equal to +SlashMeterReplenishPeriodXSlashMeterReplenishFraction2SlashMeterReplenishPeriod\mathit{SlashMeterReplenishPeriod} \cdot \frac{X}{\mathit{SlashMeterReplenishFraction}} - 2 \cdot \mathit{SlashMeterReplenishPeriod}.

+
+

Intuition

+

Let's use the following notation:

+
    +
  • CC: Number of replenishment cycles
  • +
  • PP: SlashMeterReplenishPeriod\mathit{SlashMeterReplenishPeriod}
  • +
  • FF: SlashMeterReplenishFraction\mathit{SlashMeterReplenishFraction}
  • +
  • VmaxV_{\mathit{max}}: Max power of a validator as a fraction of total voting power
  • +
+

In CC number of replenishment cycles, the fraction of total voting power that can be removed, aa, is aFC+Vmaxa \leq F \cdot C + V_{\mathit{max}} (where VmaxV_{\mathit{max}} is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value).

+

So, we need at least CaVmaxFC \geq \frac{a - V_{\mathit{max}}}{F} cycles to remove aa fraction of the total voting power.

+

Since we defined the start of the attack to be the moment when the first slash request arrives, then FF fraction of the initial validator set can be jailed immediately. For the remaining XFX - F fraction of the initial validator set to be jailed, it takes at least C(XF)VmaxFC \geq \frac{(X - F) - V_{\mathit{max}}}{F} cycles. Using the assumption that VmaxFV_{\mathit{max}} \leq F (assumption 2), we get CX2FFC \geq \frac{X - 2F}{F} cycles.

+

In order to execute CC cycles, we need CPC \cdot P time.

+

Thus, jailing the remaining XFX - F fraction of the initial validator set corresponds to P(X2F)F\frac{P \cdot (X - 2F)}{F} time.

+

In other words, the attack must take at least PXF2P\frac{P \cdot X}{F} - 2P time (in the units of replenish period PP).

+
+

This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests. +For example, if SlashMeterReplenishFraction is set to 0.06, then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub. +Note that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power.

+

Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings.

+

How Unjailing Affects the Main Throttling Property

+

Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained.

+

If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider.

+

In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack.

+

Consequences

+

Positive

+
    +
  • The described attack is slowed down in seemingly all cases.
  • +
  • If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded.
  • +
+

Negative

+
    +
  • Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below. +However, this is sacrificing liveness in a edge case scenario for the sake of security. +As an improvement, using retries would fully prevent this attack vector.
  • +
+

Neutral

+
    +
  • Additional state is introduced to the provider chain.
  • +
  • VSCMatured and slash packet data is not always handled in the same block that it is received.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-002-throttle.html.html b/v4.2.0/adrs/adr-002-throttle.html.html new file mode 100644 index 0000000000..d4b75c0d8e --- /dev/null +++ b/v4.2.0/adrs/adr-002-throttle.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-003-equivocation-gov-proposal.html b/v4.2.0/adrs/adr-003-equivocation-gov-proposal.html new file mode 100644 index 0000000000..9fe52f288d --- /dev/null +++ b/v4.2.0/adrs/adr-003-equivocation-gov-proposal.html @@ -0,0 +1,60 @@ + + + + + +Equivocation governance proposal | Interchain Security + + + + +
Version: v4.2.0

ADR 003: Equivocation governance proposal

+

Changelog

+
    +
  • 2023-02-06: Initial draft
  • +
  • 2023-11-30: Change status to deprecated
  • +
+

Status

+

Deprecated

+

Context

+

Note: ADR deprecated as the equivocation proposal was removed by the +cryptographic verification of equivocation feature +(see ADR-005 and +ADR-013).

+

We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain.

+

For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence.

+

Decision

+

To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain.

+

A new kind of governance proposal is added to the provider module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain.

+

If such proposal passes, the proposal handler delegates to the evidence module to process the equivocation. This module ensures the evidence isn’t too old, or else ignores it (see code). Too old is determined by 2 consensus params :

+
    +
  • evidence.max_age_duration number of nanoseconds before an evidence is considered too old
  • +
  • evidence.max_age_numblocks number of blocks before an evidence is considered too old.
  • +
+

On the hub, those parameters are equals to

+
// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682
(...)
"evidence": {
"max_age_num_blocks": "1000000",
"max_age_duration": "172800000000000",
(...)
},
(...)
+

A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the evidence module when the proposal passes and is handled by the hub.

+

For max_age_num_blocks=1M, the parameter is big enough if we consider the hub produces 12k blocks per day (blocks_per_year/365 = 436,0000/365). The evidence can be up to 83 days old (1,000,000/12,000) and not be ignored.

+

For max_age_duration=172,800,000,000,000, the parameter is too low, because the value is in nanoseconds so it’s 2 days. Fortunately the condition that checks those 2 parameters uses a AND, so if max_age_num_blocks condition passes, the evidence won’t be ignored.

+

Consequences

+

Positive

+
    +
  • Remove the possibility from a malicious consumer chain to “attack” the provider chain by slashing/jailing validators.
  • +
  • Provide a more acceptable implementation for the validator community.
  • +
+

Negative

+
    +
  • Punishment action of double-signing isn’t “automated”, a governance proposal is required which takes more time.
  • +
  • You need to pay 250ATOM to submit an equivocation evidence.
  • +
+

Neutral

+

References

+
+ + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-003-equivocation-gov-proposal.html.html b/v4.2.0/adrs/adr-003-equivocation-gov-proposal.html.html new file mode 100644 index 0000000000..97fa76ec7c --- /dev/null +++ b/v4.2.0/adrs/adr-003-equivocation-gov-proposal.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-004-denom-dos-fixes.html b/v4.2.0/adrs/adr-004-denom-dos-fixes.html new file mode 100644 index 0000000000..187f4ce919 --- /dev/null +++ b/v4.2.0/adrs/adr-004-denom-dos-fixes.html @@ -0,0 +1,59 @@ + + + + + +ADR Template | Interchain Security + + + + +
Version: v4.2.0

ADR 004: Denom DOS fixes

+

Changelog

+
    +
  • 5/9/2023: ADR created
  • +
+

Status

+

Accepted

+

Context

+

The provider and consumer modules are vulnerable to similar issues involving an attacker sending millions of denoms to certain addresses and causing the chain to halt. This ADR outlines both fixes since they are similar. Both fixes involve processing only denoms that are on a whitelist to avoid iterating over millions of junk denoms but have different requirements and are implemented in different ways.

+

Decision

+

Provider

+
    +
  • Put the distribution module's FeePoolAddress back on the blocklist so that it cannot receive funds from users.
  • +
  • Create a new address called ConsumerRewardPool and unblock it, allowing funds to be sent to it.
  • +
  • Create a set of strings in the store for allowed ConsumerRewardDenoms.
  • +
  • Create an endpoint called RegisterConsumerRewardDenom which deducts a fee from the sender's account, sends it to the community pool and adds a string to the ConsumerRewardDenoms set.
  • +
  • Create a parameter called ConsumerRewardDenomRegistrationFee which determines the fee which is charged to register a consumer reward denom in the step above.
  • +
  • Create a function called TransferRewardsToFeeCollector which gets the entire ConsumerRewardDenoms set from the store, iterates over it, and for each entry: +
      +
    • Gets the balance of this denom for the ConsumerRewardPool account
    • +
    • Sends the entire balance out to the FeePoolAddress using SendCoinsFromModuleToModule which is not affected by the blocklist.
    • +
    +
  • +
  • Run TransferRewardsToFeeCollector in the endblock
  • +
+

Now, nobody can send millions of junk denoms to the FeePoolAddress because it is on the block list. If they send millions of junk denoms to the ConsumerRewardPool, this does not matter because all balances are not iterated over, only those which are in the ConsumerRewardDenoms set.

+

We also add a new tx: register-consumer-reward-denom, and a new query: registered-consumer-reward-denoms

+

Consumer

+
    +
  • Create a new param RewardDenoms with a list of strings
  • +
  • Create a new param ProviderRewardDenoms with a list of strings
  • +
  • Create a function AllowedRewardDenoms which iterates over ProviderRewardDenoms and converts each denom to its ibc-prefixed denom using the provider chain's ibc channel information, then concatenates the RewardDenoms list and returns the combined list of allowed denoms.
  • +
  • In SendRewardsToProvider, instead of iterating over the balances of all denoms in the ToSendToProvider address, iterate over AllowedRewardDenoms
  • +
+

Now, if somebody sends millions of junk denoms to ToSendToProvider, they will not be iterated over. Only the RewardDenoms and ProviderRewardDenoms will be iterated over. Since we do not require this feature to be permissionless on the consumer, the registration fee process is not needed.

+

Consequences

+

Positive

+
    +
  • Denom DOS is no longer possible on either provider or consumer.
  • +
+

Negative

+
    +
  • Consumer chain teams must pay a fee to register a denom for distribution on the provider, and add some extra parameters in their genesis file.
  • +
+ + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-004-denom-dos-fixes.html.html b/v4.2.0/adrs/adr-004-denom-dos-fixes.html.html new file mode 100644 index 0000000000..0486f5275b --- /dev/null +++ b/v4.2.0/adrs/adr-004-denom-dos-fixes.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-005-cryptographic-equivocation-verification.html b/v4.2.0/adrs/adr-005-cryptographic-equivocation-verification.html new file mode 100644 index 0000000000..328133bddd --- /dev/null +++ b/v4.2.0/adrs/adr-005-cryptographic-equivocation-verification.html @@ -0,0 +1,145 @@ + + + + + +Cryptographic verification of equivocation evidence | Interchain Security + + + + +
Version: v4.2.0

ADR 005: Cryptographic verification of equivocation evidence

+

Changelog

+
    +
  • 5/1/2023: First draft
  • +
  • 7/23/2023: Add light client attacks handling
  • +
  • 9/6/2023: Add double signing attacks handling
  • +
  • 11/3/2023: Update limitations to clarify amnesia attacks are ignored
  • +
+

Status

+

Accepted

+

Context

+

Currently, we use a governance proposal to slash validators for equivocation (double signing and light client attacks). +Every proposal needs to go through a (two weeks) voting period before it can be approved. +Given a three-week unbonding period, this means that an equivocation proposal needs to be submitted within one week since the infraction occurred.

+

This ADR proposes a system to slash validators automatically for equivocation, immediately upon the provider chain's receipt of the evidence. Another thing to note is that we intend to introduce this system in stages, since even the partial ability to slash and/or tombstone is a strict improvement in security. +The feature is implemented in two parts, each with its dedicated endpoint. One endpoint handles light client attacks, while the other handles double signing attacks.

+

Light Client Attack

+

In a nutshell, the light client is a process that solely verifies a specific state machine's +consensus without executing the transactions. The light clients get new headers by querying +multiple nodes, called primary and witness nodes.

+

Light clients download new headers committed on chain from a primary. Headers can be verified in two ways: sequentially, +where the block height of headers is serial, or using skipping. This second verification method allows light clients to download headers +with nonconsecutive block height, where some intermediate headers are skipped (see Tendermint Light Client, Figure 1 and Figure 3). +Additionally, light clients are cross-checking new headers obtained from a primary with witnesses to ensure all nodes share the same state.

+

A light client attack occurs when a Byzantine validator sends invalid headers to a light client. +As the light client doesn't execute transactions, it can be deceived into trusting corrupted application state transitions. +For instance, if a light client receives header A from the primary and header B from a witness for the same block height H, +and both headers are successfully verified, it indicates a light client attack. +Note that in this case, either the primary or the witness or both are malicious.

+

The types of light client attacks are defined by analyzing the differences between the conflicting headers. +There are three types of light client attacks: lunatic attack, equivocation attack, and amnesia attack. +For details, see the CometBFT specification.

+

When a light client agent detects two conflicting headers, it will initially verify their traces (see cometBFT detector) using its primary and witness nodes. +If these headers pass successful verification, the Byzantine validators will be identified based on the header's commit signatures +and the type of light client attack. The agent will then transmit this information to its nodes using a LightClientAttackEvidence evidence to be eventually voted on and added to a block. +Note that from a light client agent perspective, it is not possible to establish whether a primary or a witness node, or both, are malicious. +Therefore, it will create and send two evidences: one against the primary (sent to the witness), and one against the witness (sent to the primary). +Both nodes will then verify it before broadcasting it and adding it to the evidence pool. +If an evidence is finally committed to a block, the chain's evidence module will execute it, resulting in the jailing and the slashing of the validators responsible for the light client attack.

+

Light clients are a core component of IBC. In the event of a light client attack, IBC relayers notify the affected chains by submitting an IBC misbehavior message. +A misbehavior message includes the conflicting headers that constitute a light client attack evidence. Upon receiving such a message, +a chain will first verify whether these headers would have convinced its light client. This verification is achieved by checking +the header states against the light client consensus states (see IBC misbehaviour handler). If the misbehaviour is successfully verified, the chain will then "freeze" the +light client, halting any further trust in or updating of its states.

+

Double Signing Attack

+

A double signing attack, also known as equivocation, +occurs when a validator votes for two different blocks in the same round of the CometBFT consensus. +This consensus mechanism operates with multiple voting rounds at each block height, +and it strictly prohibits sending two votes of the same type during a round +(see CometBFT State Machine Overview).

+

When a node observes two votes from the same peer, it will use these two votes to create +a DuplicateVoteEvidence +evidence and gossip it to the other nodes in the network +(see CometBFT equivocation detection). +Each node will then verify the evidence according to the CometBFT rules that define a valid double signing infraction, and based on this verification, they will decide whether to add the evidence to a block. +During the evidence verification process, the signatures of the conflicting votes must be verified successfully. +Note that this is achieved using the public key of the misbehaving validator, along with the chain ID of the chain where the infraction occurred (see CometBFT equivocation verification).

+

Once a double signing evidence is committed to a block, the consensus layer will report the equivocation to the evidence module of the Cosmos SDK application layer. +The application will, in turn, punish the malicious validator through jailing, tombstoning and slashing +(see handleEquivocationEvidence).

+

Decision

+

Light Client Attack

+

In the first part of the feature, we introduce a new endpoint: HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour). +The main idea is to leverage the current IBC misbehaviour handling and update it to solely jail and slash the validators that +performed a light client attack. Note that in this context, we assume that chains connected via a light client +share the same validator set, as is the case with Replicated Security.

+

This endpoint reuses the IBC client libraries to verify that the misbehaviour headers would have fooled the light client. +Additionally, it’s crucial that the endpoint logic results in the slashing and jailing of validators under the same conditions +as a light client agent detector. Therefore, the endpoint ensures that the two conditions are met: +the headers in the misbehaviour message have the same block height, and +the light client isn’t expired.

+

After having successfully verified a misbehaviour, the endpoint executes the jailing and slashing of the malicious validators similarly as in the evidence module.

+

Double Signing Attack

+

In the second part of the feature, we introduce a new endpoint HandleConsumerDoubleVoting( ctx sdk.Context, evidence *tmtypes.DuplicateVoteEvidence, chainID string, pubkey cryptotypes.PubKey). +Simply put, the handling logic verifies a double signing evidence against a provided +public key and chain ID and, if successful, executes the jailing of the malicious validator who double voted.

+

We define a new +MsgSubmitConsumerDoubleVoting message to report a double voting evidence observed +on a consumer chain to the endpoint of the provider chain. This message contains two fields: +a double signing evidence +duplicate_vote_evidence and a light client header for the infraction block height, +referred to as infraction_block_header. +The latter provides the malicious validator's public key and the chain ID required to verify the signature of the votes contained in the evidence.

+

Note that double signing evidence is not verified using the same conditions as in the implementation CometBFT (see +verify(evidence types.Evidence) method). Specifically, we do not check that the evidence hasn't expired. +More details can be found in the "Current limitations" section below.

+

Upon a successful equivocation verification, the misbehaving validator is jailed for the maximum time +(see DoubleSignJailEndTime +in the SDK evidence module).

+

Current limitations:

+
    +
  • +

    We cannot derive an infraction height from the evidence, so it is only possible to jail validators, not actually slash them. +To explain the technical reasons behind this limitation, let's recap the initial consumer initiated slashing logic. +In a nutshell, consumer heights are mapped to provider heights through VSCPackets, namely through the so called vscIDs. +When an infraction occurs on the consumer, a SlashPacket containing the vscID obtained from mapping the consumer infraction height +is sent to the provider. Upon receiving the packet, the provider maps the consumer infraction height to a local infraction height, +which is used to slash the misbehaving validator. In the context of untrusted consumer chains, all their states, including vscIDs, +could be corrupted and therefore cannot be used for slashing purposes.

    +
  • +
  • +

    For the same reasons explained above, the age of a consumer double signing evidence can't be verified, +either using its infraction height or its unsigned timestamp. Note that changes the jailing behaviour, potentially leading to a validator's jailing based on some "old" evidence from a consumer, which wouldn't occur if the consumer were a standalone chain.

    +
  • +
  • +

    In the first stage of this feature, validators are jailed indefinitely without being tombstoned. +The underlying reason is that a malicious validator could take advantage of getting tombstoned +to avoid being slashed on the provider (see comment).

    +
  • +
  • +

    Currently, the endpoint can only handle equivocation light client attacks. This is because the lunatic attacks require the endpoint to possess the ability to dissociate which header is conflicted or trusted upon receiving a misbehavior message. Without this information, it's not possible to extract the Byzantine validators from the conflicting headers (see comment). In addition, "amnesia" attacks are ignored, similar to CometBFT (see ADR-056).

    +
  • +
+

Consequences

+

Positive

+
    +
  • It is now possible for the provider chain to jail validators who committed +light client or double signing attacks on a consumer chain.
  • +
+

Negative

+
    +
  • N/A
  • +
+

References

+
+ + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-005-cryptographic-equivocation-verification.html.html b/v4.2.0/adrs/adr-005-cryptographic-equivocation-verification.html.html new file mode 100644 index 0000000000..1de33611c7 --- /dev/null +++ b/v4.2.0/adrs/adr-005-cryptographic-equivocation-verification.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html b/v4.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html new file mode 100644 index 0000000000..b71660e139 --- /dev/null +++ b/v4.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html @@ -0,0 +1,98 @@ + + + + + +ADR Template | Interchain Security + + + + +
Version: v4.2.0

ADR 007: Pause validator unbonding during equivocation proposal

+

Changelog

+
    +
  • 2023-05-16: Initial Draft
  • +
  • 2023-11-30: Change the status to rejected
  • +
+

Status

+

Rejected

+

Context

+

Note: ADR rejected as the equivocation proposal was removed by the +cryptographic verification of equivocation feature +(see ADR-005 and +ADR-013).

+

Currently, if an equivocation slashing proposal is created after more than one +week has passed since the equivocation, it is possible that the validator in +question could unbond and get away without being slashed, since the unbonding +period is 3 weeks, and the voting period is 2 weeks. For this reason, it might +be good to pause unbondings for validators named in an equivocation slashing +proposal until the proposal's voting period is over.

+

Decision

+

How

+

Pausing the unbonding period is already possible thanks to the changes in the +staking module of the cosmos-sdk:

+
    +
  • stakingKeeper.PutUnbondingOnHold pauses an unbonding period
  • +
  • stakingKeeper.UnbondingCanComplete unpauses an unbonding period
  • +
+

These methods use a reference counter under the hood, that gets incremented +every time PutUnbondingOnHold is called, and decreased when +UnbondingCanComplete is called instead. A specific unbonding is considered +fully unpaused when its underlying reference counter reaches 0. Therefore, as +long as we safeguard consistency - i.e. we make sure we eventually decrement +the reference counter for each time we have incremented it - we can safely use +this existing mechanism without conflicts with the Completion of Unbonding +Operations system.

+

When pause

+

The unbonding period (if there is any unbonding) should be paused once an +equivocation proposal enters the voting period. For that, the gov module's +hook AfterProposalDeposit can be used.

+

If the hook is triggered with a an equivocation proposal in voting period, then +for each equivocation of the proposal, the unbonding operations of the related +validator that were initiated after the equivocation block time must be paused

+
    +
  • i.e. the underlying reference counter has to be increased.
  • +
+

Note that even after the voting period has started, a proposal can receive +additional deposits. The hook is triggered however at arrival of a deposit, so +a check to verify that the proposal is not already in voting period is +required.

+

When unpause

+

We can use a gov module's hook also here and it is +AfterProposalVotingPeriodEnded.

+

If the hook is triggered with an equivocation proposal, then for each +associated equivocation, the unbonding operations of the related validator that +were initiated between the equivocation block time and the start of the +proposal voting period must be unpaused - i.e. decrease the underlying +reference counter - regardless of the proposal outcome.

+

Consequences

+

Positive

+
    +
  • Validators subject to an equivocation proposal cannot finish unbonding +their tokens before the end of the voting period.
  • +
+

Negative

+
    +
  • A malicious consumer chain could forge slash packets enabling submission of +an equivocation proposal on the provider chain, resulting in the freezing of +validator's unbondings for an undeterminated amount of time.
  • +
  • Misbehavior on a consumer chain can potentially go unpunished, if no one +submits an equivocation proposal in time, or if the proposal doesn't pass.
  • +
+

Neutral

+
    +
  • This feature can't be used for social slashing, because an equivocation +proposal is only accepted if there's a slash log for the related +validator(s), meaning the consumer chain has reported the equivocation to +the provider chain.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html b/v4.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html new file mode 100644 index 0000000000..cb13e82a8e --- /dev/null +++ b/v4.2.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-008-throttle-retries.html b/v4.2.0/adrs/adr-008-throttle-retries.html new file mode 100644 index 0000000000..47ff3bc767 --- /dev/null +++ b/v4.2.0/adrs/adr-008-throttle-retries.html @@ -0,0 +1,133 @@ + + + + + +Throttle with retries | Interchain Security + + + + +
Version: v4.2.0

Throttle with retries

ADR 008: Throttle with retries

+

Changelog

+
    +
  • 6/9/23: Initial draft
  • +
  • 6/22/23: added note on consumer pending packets storage optimization
  • +
  • 7/14/23: Added note on upgrade order
  • +
+

Status

+

Accepted

+

Context

+

For context on why the throttling mechanism exists, see ADR 002.

+

Note the terms slash throttling and jail throttling are synonymous, since in replicated security a SlashPacket simply jails a validator for downtime infractions.

+

Currently the throttling mechanism is designed so that provider logic (slash meter, etc.) dictates how many SlashPackets can be handled over time. +Throttled SlashPackets are persisted on the provider, leading to multiple possible issues. Namely:

+
    +
  • If SlashPackets or VSCMaturedPackets are actually throttled/queued on the provider, state can grow and potentially lead to a DoS attack. +We have short term solutions around this, but overall they come with their own weaknesses. +See #594.
  • +
  • If a jailing attack described in ADR 002 were actually to be carried out with the current throttling design, we'd likely have to halt the provider, and perform an emergency upgrade and/or migration to clear the queues of SlashPackets that were deemed to be malicious. +Alternatively, validators would just have to tough it out and wait for the queues to clear, during which all/most validators would be jailed. +Right after being jailed, validators would have to unjail themselves promptly to ensure safety. +The coordination required to maintain safety in such a scenario is not ideal.
  • +
+

As a solution, we can improve the throttling mechanism to instead queue/persist relevant data on each consumer, and have consumers retry slash requests as needed.

+

Decision

+

Consumer changes

+

Note the consumer already queues up both SlashPackets and VSCMaturedPackets via AppendPendingPacket. +Those packets are dequeued in every EndBlock in SendPackets and sent to the provider.

+

Instead, we will now introduce the following logic on EndBlock:

+
    +
  • Slash packets will always be sent to the provider once they're at the head of the queue. +However, once sent, the consumer will not send any subsequent VSCMaturedPackets from the queue until the provider responds with an acknowledgement that the sent SlashPacket has been handled, i.e., validator was jailed. +That is, SlashPackets block the sending of subsequent VSCMaturedPackets in the consumer queue.
  • +
  • If two SlashPackets are at the head of the queue, the consumer will send the first SlashPacket, and then wait for a success acknowledgement from the provider before sending the second SlashPacket. +This seems like it'd simplify implementation.
  • +
  • VSCMaturedPackets at the head of the queue (i.e., NOT following a SlashPacket) can be sent immediately, and do not block any other packets in the queue, since the provider always handles them immediately.
  • +
+

To prevent the provider from having to keep track of what SlashPackets have been rejected, the consumer will have to retry the sending of SlashPackets over some period of time. +This can be achieved with an on-chain consumer param, i.e., RetryDelayPeriod. +To reduce the amount of redundant re-sends, we recommend setting RetryDelayPeriod ~ SlashMeterReplenishmentPeriod, i.e., waiting for the provider slash meter to be replenished before resending the rejected SlashPacket.

+

Note to prevent weird edge case behavior, a retry would not be attempted until either a success or failure acknowledgement has been received from the provider.

+

With the behavior described, we maintain very similar behavior to the previous throttling mechanism regarding the timing that SlashPackets and VSCMaturedPackets are handled on the provider. +Obviously the queueing and blocking logic is moved, and the two chains would have to send more messages between one another (only in the case the throttling mechanism is triggered).

+

In the normal case, when no or a few SlashPackets are being sent, the VSCMaturedPackets will not be delayed, and hence unbonding will not be delayed.

+

For the implementation of this design, see throttle_retry.go.

+

Consumer pending packets storage optimization

+

In addition to the mentioned consumer changes, an optimization will need to be made to the consumer's pending packets storage to properly implement the feature from this ADR.

+

The consumer ccv module previously queued "pending packets" to be sent in each EndBlock in SendPackets. +These packets are queued in state with a protobuf list of ConsumerPacketData. +For a single append operation, the entire list is deserialized, then a packet is appended to that list, and the list is serialized again. +See older version of AppendPendingPacket. +That is, a single append operation has O(N) complexity, where N is the size of the list.

+

This poor append performance isn't a problem when the pending packets list is small. +But with this ADR being implemented, the pending packets list could potentially grow to the order of thousands of entries when SlashPackets need to be resent.

+

We can improve the append time for this queue by converting it from a protobuf-esq list, to a queue implemented with sdk-esq code. +The idea is to persist a uint64 index that will be incremented each time you queue up a packet. +You can think of this as storing the tail of the queue. +Then, packet data will be keyed by that index, making the data naturally ordered byte-wise for sdk's iterator. +The index will also be stored in the packet data value bytes, so that the index can later be used to delete certain packets from the queue.

+

Two things are achieved with this approach:

+
    +
  • More efficient packet append/enqueue times
  • +
  • The ability to delete select packets from the queue (previously all packets were deleted at once)
  • +
+

Provider changes

+

The main change needed for the provider is the removal of queuing logic for SlashPackets and VSCMaturedPackets upon being received.

+

Instead, the provider will consult the slash meter to determine if a SlashPacket can be handled immediately. +If not, the provider will return an acknowledgement message to the consumer communicating that the SlashPacket could not be handled, and needs to be sent again in the future (retried).

+

VSCMaturedPackets will always be handled immediately upon being received by the provider.

+

Note spec. Specifically the section on VSC Maturity and Slashing Order. Previously the onus was on the provider to maintain this property via queuing packets and handling them FIFO.

+

Now this property will be maintained by the consumer sending packets in the correct order, and blocking the sending of VSCMaturedPackets as needed. Then, the ordered IBC channel will ensure that SlashPackets and VSCMaturedPackets are received in the correct order on the provider.

+

The provider's main responsibility regarding throttling will now be to determine if a received SlashPacket can be handled via slash meter etc., and appropriately acknowledge to the sending consumer.

+

Handling VSCMaturedPackets immediately

+

Why the provider can handle VSCMatured packets immediately

+

A VSCMaturedPacket communicates to the provider that sufficient time passed on the consumer since the corresponding VSCPacket has been applied (on the consumer) such that infractions committed on the consumer could have been submitted.

+

If the consumer is following the queuing/blocking protocol described, then no bad behavior occurs and the VSC Maturity and Slashing Order property is maintained.

+

If a consumer sends VSCMaturedPackets too leniently -- the consumer is malicious and sends duplicate VSCMaturedPackets, or sends the packets sooner than the CCV protocol specifies -- then the provider needs to handle VSCMaturedPackets immediately to prevent DOS, state bloat, or other issues. +The only possible negative outcome is that the malicious consumer may not be able to jail a validator who should have been jailed. +The malicious behavior only creates a negative outcome for the consumer chain that is being malicious.

+

If a consumer blocks the sending of VSCMaturedPackets, then unbonding operations on the provider will be delayed, but only until the VSC timeout period has elapsed. +At that time, the consumer is removed. +Again the malicious behavior only creates a negative outcome for the consumer chain that is being malicious.

+

Splitting of PRs and Upgrade Order

+

This feature will implement consumer changes in #1024.

+

These changes should be deployed to production for all consumers before the provider changes are deployed to production.

+

In other words, the consumer changes in #1024 are compatible with the current ("v1") provider implementation of throttling that's running on the Cosmos Hub as of July 2023.

+

Once all consumers have deployed the changes in #1024, the provider changes from #1321 can be deployed to production, fully enabling v2 throttling.

+

Consequences

+
    +
  • Consumers will now have to manage their own queues, and retry logic.
  • +
  • Consumers still aren't trustless, but the provider is now less susceptible to mismanaged or malicious consumers.
  • +
  • Recovering from the "jailing attack" is more elegant.
  • +
  • Some issues like #1001 will now be handled implicitly by the improved throttling mechanism.
  • +
  • SlashPackets and VSCMaturedPackets can be handled immediately once received by the provider if the slash meter allows.
  • +
  • In general, we reduce the amount of computation that happens in the provider EndBlock.
  • +
+

Positive

+
    +
  • We no longer have to reason about a "global queue" and a "chain specific queue", and keeping those all in-sync. +Now SlashPackets and VSCMaturedPackets queuing is handled on each consumer individually.
  • +
  • Due to the above, the throttling protocol becomes less complex overall.
  • +
  • We no longer have to worry about throttle related DoS attack on the provider, since no queuing exists on the provider.
  • +
+

Negative

+
    +
  • Increased number of IBC packets being relayed anytime throttling logic is triggered.
  • +
  • Consumer complexity increases, since consumers now have manage queuing themselves, and implement packet retry logic.
  • +
+

Neutral

+
    +
  • Core throttling logic on the provider remains unchanged, i.e., slash meter, replenishment cycles, etc.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-008-throttle-retries.html.html b/v4.2.0/adrs/adr-008-throttle-retries.html.html new file mode 100644 index 0000000000..6bc8a1a0f1 --- /dev/null +++ b/v4.2.0/adrs/adr-008-throttle-retries.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-009-soft-opt-out.html b/v4.2.0/adrs/adr-009-soft-opt-out.html new file mode 100644 index 0000000000..8cb396d090 --- /dev/null +++ b/v4.2.0/adrs/adr-009-soft-opt-out.html @@ -0,0 +1,49 @@ + + + + + +Soft Opt-Out | Interchain Security + + + + +
Version: v4.2.0

Soft Opt-Out

ADR 009: Soft Opt-Out

+

Changelog

+
    +
  • 6/13/23: Initial draft of ADR. Feature already implemented and in production.
  • +
+

Status

+

Accepted

+

Context

+

Some small validators may not have the resources needed to validate all consumer chains. Therefore a need exists to allow the bottom x% of validators to opt-out of validating a consumer chain. Meaning downtime infractions for these validators are dropped without ever reaching the provider.

+

This document specifies a modification to the ccv protocol which allows the bottom x% of the validator set by power to opt out of validating consumer chains without being jailed or otherwise punished for it. The feature is implemented with entirely consumer-side code.

+

Decision

+

A consumer param exists, known as SoftOptOutThreshold, which is a string decimal in the range of [0, 0.2], that determines the portion of validators which are allowed to opt out of validating that specific consumer.

+

In every consumer beginblocker, a function is ran which determines the so called smallest non opt-out voting power. Validators with voting power greater than or equal to this value must validate the consumer chain, while validators below this value may opt out of validating the consumer chain.

+

The smallest non opt-out voting power is recomputed every beginblocker in UpdateSmallestNonOptOutPower(). In a nutshell, the method obtains the total voting power of the consumer, iterates through the full valset (ordered power ascending) keeping track of a power sum, and when powerSum / totalPower > SoftOptOutThreshold, the SmallestNonOptOutPower is found and persisted.

+

Then, whenever the Slash() interface is executed on the consumer, if the voting power of the relevant validator being slashed is less than SmallestNonOptOutPower for that block, the slash request is dropped and never sent to the provider.

+

Consequences

+

Positive

+
    +
  • Small validators can opt out of validating specific consumers without being punished for it.
  • +
+

Negative

+
    +
  • The bottom x% is still part of the total voting power of the consumer chain. This means that if the soft opt-out threshold is set to 10% for example, and every validator in the bottom 10% opts out from validating the consumer, then a 24% downtime of the remaining voting power would halt the chain. This may be especially problematic during consumer upgrades.
  • +
  • In nominal scenarios, consumers with soft opt out enabled will be constructing slash packets for small vals, which may be dropped. This is wasted computation, but necessary to keep implementation simple. Note that the sdk's full downtime logic is always executed on the consumer, which can be computationally expensive and slow down certain blocks.
  • +
  • In a consumer chain, when a validator that has opted out becomes the proposer, there will naturally be no proposal made and validators would need to move to the next consensus round for the same height to reach a decision. As a result, we would need more time to finalize blocks on a consumer chain.
  • +
+

Neutral

+
    +
  • Validators in the bottom of the valset who don't have to validate, may receive large delegation(s) which suddenly boost the validator to the subset that has to validate. This may catch the validator off guard.
  • +
+

References

+
    +
  • Original issue with some napkin math #784
  • +
+ + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-009-soft-opt-out.html.html b/v4.2.0/adrs/adr-009-soft-opt-out.html.html new file mode 100644 index 0000000000..ea6166fb02 --- /dev/null +++ b/v4.2.0/adrs/adr-009-soft-opt-out.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-010-standalone-changeover.html b/v4.2.0/adrs/adr-010-standalone-changeover.html new file mode 100644 index 0000000000..83c5ff5cb5 --- /dev/null +++ b/v4.2.0/adrs/adr-010-standalone-changeover.html @@ -0,0 +1,53 @@ + + + + + +Standalone to Consumer Changeover | Interchain Security + + + + +
Version: v4.2.0

Standalone to Consumer Changeover

ADR 010: Standalone to Consumer Changeover

+

Changelog

+
    +
  • 6/30/23: Feature completed, first draft of ADR.
  • +
+

Status

+

Implemented

+

Context

+

Stride will be the first consumer to "changeover" from a standalone cosmos blockchain, to a consumer chain secured by the Cosmos Hub. This document will outline the changes made to the replicated security protocol to support this changeover process.

+

Decision

+

Process

+

Prior to the changeover, the consumer chain will have an existing staking keeper and validator set, these may be referred to as the "standalone staking keeper" and "standalone validator set" respectively.

+

The first step in the changeover process is to submit a ConsumerAdditionProposal. If the proposal passes, the provider will create a new IBC client for the consumer at spawn time, with the provider's validator set. A consumer genesis will also be constructed by the provider for validators to query. Within this consumer genesis contains the initial validator set for the consumer to apply after the changeover.

+

Next, the standalone consumer chain runs an upgrade which adds the CCV module, and is properly setup to execute changeover logic.

+

The consumer upgrade height must be reached after the provider has created the new IBC client. Any replicated security validators who will run the consumer, but are not a part of the sovereign validator set, must sync up a full node before the consumer upgrade height is reached. The disk state of said full node will be used to run the consumer chain after the changeover has completed.

+

The meat of the changeover logic is that the consumer chain validator set is updated to that which was specified by the provider via the queried consumer genesis. Validators which were a part of the old set, but not the new set, are given zero voting power. Once these validator updates are given to Comet, the set is committed, and in effect 2 blocks later (see FirstConsumerHeight).

+

A relayer then establishes the new IBC connection between the provider and consumer. The CCV channel handshake is started on top of this connection. Once the CCV channel is established and VSC packets are being relayed, the consumer chain is secured by the provider.

+

Changes to CCV Protocol

+
    +
  • Consumer Genesis state is updated to include a PreCCV boolean. When this boolean is set true in the consumer genesis JSON, special logic is executed on InitGenesis to trigger the changeover process on the consumer's first endblocker after the upgrade which adds the CCV module. Note that InitGenesis is not automatically called during chain upgrades, so the consumer must manually call the consumer's InitGenesis method in an upgrade handler.
  • +
  • The ConsumerAdditionProposal type is updated to include a DistributionTransmissionChannel field. This field allows the consumer to use an existing IBC transfer channel to send rewards as a part of the CCV protocol. Consumers that're not changing over from a standalone chain will leave this field blank, indicating that a new transfer channel should be created on top of the same connection as the CCV channel.
  • +
  • The CCV consumer keeper is updated to contain an optional reference to the standalone staking keeper. The standalone staking keeper is used to slash for infractions that happened before the changeover was completed. Ie. any infraction from a block height before the changeover, that is submitted after the changeover, will call the standalone staking keeper's slash method. Note that a changeover consumer's standalone staking keeper becomes a democracy module keeper, so it is possible for a governance token to be slashed.
  • +
+

Consequences

+

Positive

+
    +
  • Existing cosmos chains are now able to onboard over to a consumer chain secured by a provider.
  • +
  • The previous staking keepers for such chains can be transitioned to democracy staking module keepers.
  • +
+

Negative

+
    +
  • The delineation between different types of consumers in this repo becomes less clear. Ie. there is code in the democracy consumer's app.go that only applies to a previously standalone chain, but that file also serves as the base for a normal democracy consumer launched with RS from genesis.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-010-standalone-changeover.html.html b/v4.2.0/adrs/adr-010-standalone-changeover.html.html new file mode 100644 index 0000000000..69ace4bc36 --- /dev/null +++ b/v4.2.0/adrs/adr-010-standalone-changeover.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-011-improving-test-confidence.html b/v4.2.0/adrs/adr-011-improving-test-confidence.html new file mode 100644 index 0000000000..79373314c2 --- /dev/null +++ b/v4.2.0/adrs/adr-011-improving-test-confidence.html @@ -0,0 +1,158 @@ + + + + + +Improving testing and increasing confidence | Interchain Security + + + + +
Version: v4.2.0

ADR 011: Improving testing and increasing confidence

+

Changelog

+
    +
  • 2023-08-11: Proposed, first draft of ADR.
  • +
+

Status

+

Proposed

+

Context

+

Testing, QA, and maintenance of interchain-security libraries is an ever-evolving area of software engineering we have to keep incrementally improving. The purpose of the QA process is to catch bugs as early as possible. In an ideal development workflow a bug should never reach production. A bug found in the specification stage is a lot cheaper to resolve than a bug discovered in production (or even in testnet). Ideally, all bugs should be found during the CI execution, and we hope that no bugs will ever even reach the testnet (although nothing can replace actual system stress test under load interacting with users).

+

During development and testnet operation the following types of bugs were the most commonly found:

+
    +
  • improper iterator usage
  • +
  • unbounded array access/iteration
  • +
  • improper input handling and validation
  • +
  • improper cached context usage
  • +
  • non-determinism check (improper use of maps in go, relying on random values)
  • +
  • KV store management and/or how keys are defined
  • +
  • deserialization issues arising from consumer/provider versioning mismatch
  • +
+

Such bugs can be discovered earlier with better tooling. Some of these bugs can induce increases in block times, chain halts, state corruption, or introduce an attack surface which is difficult to remove if other systems have started depending on that behavior.

+

Current state of testing

+

Our testing suites consist of multiple parts, each with their own trade-offs and benefits with regards to code coverage, complexity and confidence they provide.

+

Unit testing

+

Unit testing is employed mostly for testing single-module functionality. It is the first step in testing and often the most practical. While highly important, unit tests often test a single piece of code and don't test relationships between different moving parts, this makes them less valuable when dealing with multi-module interactions.

+

Unit tests often employ mocks to abstract parts of the system that are not under test. Mocks are not equivalent to actual models and should not be treated as such.

+

Out of all the approaches used, unit testing has the most tools available and the coverage can simply be displayed as % of code lines tested. Although this is a very nice and very easy to understand metric, it does not speak about the quality of the test coverage.

+

Since distributed systems testing is a lot more involved, unit tests are oftentimes not sufficient to cover complex interactions. Unit tests are still necessary and helpful, but in cases where unit tests are not helpful e2e or integration tests should be favored.

+

Integration testing

+

With integration testing we test the multi-module interactions while isolating them from the remainder of the system. +Integration tests can uncover bugs that are often missed by unit tests.

+

It is very difficult to gauge the actual test coverage imparted by integration tests and the available tooling is limited. +In interchain-security we employ the ibc-go/testing framework to test interactions in-memory.

+

At present, integration testing does not involve the consensus layer - it is only concerned with application level state and logic.

+

End-to-end testing

+

In our context end-to-end testing comprises of tests that use the actual application binaries in an isolated environment (e.g. docker container). During test execution the inputs are meant to simulate actual user interaction, either by submitting transactions/queries using the command line or using gRPC/REST APIs and checking for state changes after an action has been performed. With this testing strategy we also include the consensus layer in all of our runs. This is the closest we can get to testing user interactions without starting a full testnet.

+

End-to-end testing strategies vary between different teams and projects and we strive to unify our approach to the best of our ability (at least for ICS and gaia).

+

The available tooling does not give us significant (or relevant) line of code coverage information since most of the tools are geared towards analyzing unit tests and simple code branch evaluation.

+

We aim to adapt our best practices by learning from other similar systems and projects such as cosmos-sdk, ibc-go and CometBFT.

+

Decision

+

1. Connect specifications to code and tooling

+

Oftentimes, specifications are disconnected from the development and QA processes. This gives rise to problems where the specification does not reflect the actual state of the system and vice-versa. +Usually specifications are just text files that are rarely used and go unmaintained after a while, resulting in consistency issues and misleading instructions/expectations about system behavior.

+

Decision context and hypothesis

+

Specifications written in a dedicated and executable specification language are easier to maintain than the ones written entirely in text. +Additionally, we can create models based on the specification OR make the model equivalent to a specification.

+

Models do not care about the intricacies of implementation and neither do specifications. Since both models and specifications care about concisely and accurately describing a system (such as a finite state machine), we see a benefit of adding model based tools (such as quint) to our testing and development workflows.

+

Main benefit

+

MBT tooling can be used to generate test traces that can be executed by multiple different testing setups.

+

2. Improve e2e tooling

+

Matrix tests

+

Instead of only running tests against current main branch we should adopt an approach where we also:

+
    +
  • run regression tests against different released software versions (ICS v1 vs v2 vs v3)
  • +
  • run non-determinism tests to uncover issues quickly
  • +
+

Matrix tests can be implemented using CometMock and refactoring our current e2e CI setup.

+

Introducing e2e regression testing

+

This e2e test suite would execute using a cronjob in our CI (nightly, multiple times a day etc.)

+

Briefly, the same set of traces is run against different maintained versions of the software and the main branch. +This would allow us to discover potential issues during development instead of in a testnet scenarios.

+

The most valuable issues that can be discovered in this way are state breaking changes, regressions and version incompatibilities.

+

The setup is illustrated by the image below. +e2e matrix tests

+

This table explains which versions are tested against each other for the same set of test traces:

+
    +
  • ✅ marks a passing test
  • +
  • ❌ marks a failing test
  • +
+
USES: ICS v1 PROVIDERstart chainadd keydelegateundelegateredelegatedowntimeequivocationstop chain
v1 consumer (sdk45,ibc4.3)
v2 consumer (sdk45, ibc4.4)
v3 consumer (sdk47, ibc7)
main consumer
neutron
stride
+

Introducing e2e CometMock tests

+

CometMock is a mock implementation of the CometBFT consensus engine. It supports most operations performed by CometBFT while also being lightweight and relatively easy to use.

+

CometMock tests allow more nuanced control of test scenarios because CometMock can "fool" the blockchain app into thinking that a certain number of blocks had passed. +This allows us to test very nuanced scenarios, difficult edge cases and long-running operations (such as unbonding operations).

+

Examples of tests made easier with CometMock are listed below:

+
    +
  • regression tests
  • +
  • non-determinism tests
  • +
  • upgrade tests
  • +
  • state-breaking changes
  • +
+

With CometMock, the matrix test approach can also be used. The image below illustrates a CometMock setup that can be used to discover non-deterministic behavior and state-breaking changes. +e2e matrix tests

+

This table explains which versions are tested against each other for the same set of test traces:

+
    +
  • ✅ marks a passing test
  • +
  • ❌ marks a failing test
  • +
+
SCENARIOstart chainadd keydelegateundelegateredelegatedowntimeequivocationstop chain
v3 provi + v3 consu
main provi + main consu
commit provi + commit consu
+

Briefly; multiple versions of the application are run against the same CometMock instance and any deviations in app behavior would result in app hash errors (the apps would be in different states after performing the same set of actions).

+

3. Introduce innovative testing approaches

+

When discussing e2e testing, some very important patterns emerge - especially if test traces are used instead of ad-hoc tests written by hand.

+

We see a unique opportunity to clearly identify concerns and modularize the testing architecture.

+

The e2e testing frameworks can be split into a pipeline consisting of 3 parts: model, driver and harness.

+

Model

+

Model is the part of the system that can emulate the behavior of the system under test. +Ideally, it is very close to the specification and is written in a specification language such as quint, TLA+ or similar. +One of the purposes of the model is that it can be used to generate test traces.

+

Driver

+

The purpose of the driver is to accept test traces (generated by the model or written by hand), process them and provide inputs to the next part of the pipeline.

+

Basically, the driver sits between the model and the actual infrastructure on which the test traces are being executed on.

+

Harness

+

Harness is the infrastructure layer of the pipeline that accepts inputs from the driver.

+

There can be multiple harnesses as long as they can perform four things:

+
    +
  • bootstrap a test execution environment (local, docker, k8s…)
  • +
  • accept inputs from drivers
  • +
  • perform the action specified by the driver
  • +
  • report results after performing actions
  • +
+

Consequences

+

The procedure outlined in this ADR is not an all-or-nothing approach. Concepts introduced here do not rely on each other, so this ADR may only be applied partially without negative impact on test coverage and code confidence.

+

Positive

+
    +
  1. introduction of maintainable MBT solutions
  2. +
+
    +
  • improvement over the current "difftest" setup that relies on an opinionated typescript model and go driver
  • +
+
    +
  1. increased code coverage and confidence
  2. +
+
    +
  • using CometMock allows us to run more tests in less time
  • +
  • adding matrix e2e tests allows us to quickly pinpoint differences between code versions
  • +
+

Negative

+

It might be easier to forgo the MBT tooling and instead focus on pure property based testing

+ +

The solutions are potentially expensive if we increase usage of the CI pipeline - this is fixed by running "expensive" tests using a cronjob, instead of running them on every commit.

+

Neutral

+

The process of changing development and testing process is not something that can be thought of and delivered quickly. Luckily, the changes can be rolled out incrementally without impacting existing workflows.

+

References

+
+

Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!

+
+
+ + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-011-improving-test-confidence.html.html b/v4.2.0/adrs/adr-011-improving-test-confidence.html.html new file mode 100644 index 0000000000..cf58822cc6 --- /dev/null +++ b/v4.2.0/adrs/adr-011-improving-test-confidence.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-012-separate-releasing.html b/v4.2.0/adrs/adr-012-separate-releasing.html new file mode 100644 index 0000000000..686df5a1c2 --- /dev/null +++ b/v4.2.0/adrs/adr-012-separate-releasing.html @@ -0,0 +1,79 @@ + + + + + +Separate Releasing | Interchain Security + + + + +
Version: v4.2.0

ADR 012: Separate Releasing

+

Changelog

+
    +
  • 0.0202020202020202: Initial draft of idea in #801
  • +
  • 0.01652892561983471: Put idea in this ADR
  • +
  • 0.05: Reject this ADR
  • +
+

Status

+

Rejected

+

Context

+

Spike results

+

I explored the idea of #801 with this spike branch. Here's my conclusions:

+

Splitting this repo to have multiple go.mods is possible. However there are various intricacies involved in decoupling the package hierarchy to have x/ccv/types as the lowest level dep, with x/ccv/consumer and x/ccv/provider being one dep layer above, with high-level tests depending on all three of the mentioned packages. I'd estimate this decoupling would take 2-5 workdays to finish, and require significant review effort.

+

Why go.mod split is not the way to go

+

Let's take a step back and remember the issue we're trying to solve - We need a clean way to decouple semver/releasing for the consumer and provider modules. After more consideration, splitting up go.mods gives us little benefit in achieving this. Reasons:

+
    +
  • The go.mod dependency system is tied to git tags for the entire repo (ex: require github.com/cometbft/cometbft v0.37.2 refers to a historical tag for the entire cometbft repo).
  • +
  • It'd be an odd dev experience to allow modules to reference past releases of other modules in the same repo. When would we ever want the consumer module to reference a past release of the types module for example?
  • +
  • If we allow for go.mod replace statements to build from local source code, why split up the package deps at all?
  • +
  • Splitting go.mods adds a bunch of complexity with go.work files and all that shiz. VSCode does not play well with multiple module repos either.
  • +
+

Why separate repos is cool but also not the way to go

+

All this considered, the cleanest solution to decoupling semver/releasing for the consumer and provider modules would be to have multiple repos, each with their own go.mod (3-4 repos total including high level tests). With this scheme we could separately tag each repo as changes are merged, they could share some code from types being an external dep, etc.

+

I don't think any of us want to split up the monorepo, that's a lot of work and seems like bikeshedding. There's another solution that's very simple..

+

Decision

+

Slightly adapting the current semver ruleset:

+
    +
  • A library API breaking change to EITHER the provider or consumer module will result in an increase of the MAJOR version number for BOTH modules (X.y.z-provider AND X.y.z-consumer).
  • +
  • A state breaking change (change requiring coordinated upgrade and/or state migration) will result in an increase of the MINOR version number for the AFFECTED module(s) (x.Y.z-provider AND/OR x.Y.z-consumer).
  • +
  • Any other changes (including node API breaking changes) will result in an increase of the PATCH version number for the AFFECTED module(s) (x.y.Z-provider AND/OR x.y.Z-consumer).
  • +
+

Example release flow

+

We upgrade main to use a new version of SDK. This is a major version bump, triggering a new release for both the provider and consumer modules, v5.0.0-provider and v5.0.0-consumer.

+
    +
  • A state breaking change is merged to main for the provider module. We release only a v5.1.0-provider off main.
  • +
  • Another state breaking change is merged to main for the provider module. We release only a v5.2.0-provider off main.
  • +
  • At this point, the latest consumer version is still v5.0.0-consumer. We now merge a state breaking change for the consumer module to main, and consequently release v5.1.0-consumer. Note that v5.1.0-consumer is tagged off a LATER commit from main than v5.2.0-provider. This is fine, as the consumer module should not be affected by the provider module's state breaking changes.
  • +
  • Once either module sees a library API breaking change, we bump the major version for both modules. For example, we merge a library API breaking change to main for the provider module. We release v6.0.0-provider and v6.0.0-consumer off main. Note that most often, a library API breaking change will affect both modules simultaneously (example being bumping sdk version).
  • +
+

Consequences

+

Positive

+
    +
  • Consumer repos have clear communication of what tagged versions are relevant to them. Consumer devs should know to never reference an ICS version that starts with provider, even if it'd technically build.
  • +
  • Consumer and provider modules do not deviate as long as we continually release off a shared main branch. Backporting remains relatively unchanged besides being explicit about what module(s) your changes should affect.
  • +
  • No code changes, just changes in process. Very simple.
  • +
+

Negative

+
    +
  • ~~Slightly more complexity.~~Considerably more complex to manage the ICS library. +This is because ICS needs to support multiple versions of SDK (e.g., 0.45, 0.47, 0.50). +In addition, ICS needs to support a special fork of SDK (with LSM included) for the Cosmos Hub. +This means that instead of focusing on main the development team needs to manage multiple release +branches with different dependency trees.
  • +
  • This solution does not allow having provider and consumer on separate versions of e.g. the Cosmos SDK.
  • +
+

Neutral

+

References

+
+

Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!

+
+
+ + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-012-separate-releasing.html.html b/v4.2.0/adrs/adr-012-separate-releasing.html.html new file mode 100644 index 0000000000..3c336ed756 --- /dev/null +++ b/v4.2.0/adrs/adr-012-separate-releasing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-013-equivocation-slashing.html b/v4.2.0/adrs/adr-013-equivocation-slashing.html new file mode 100644 index 0000000000..f32f9d2b07 --- /dev/null +++ b/v4.2.0/adrs/adr-013-equivocation-slashing.html @@ -0,0 +1,103 @@ + + + + + +Slashing on the provider for consumer equivocation | Interchain Security + + + + +
Version: v4.2.0

ADR 013: Slashing on the provider for consumer equivocation

+

Changelog

+
    +
  • 1st Sept. 2023: Initial draft
  • +
+

Status

+

Accepted

+

Context

+

This ADR presents some approaches on how to slash on the provider chain validators that performed equivocations on consumer chains. +Currently, the provider chain can receive and verify evidence of equivocation, but it cannot slash the misbehaving validator.

+

In the remainder of this section, we explain how slashing is performed on a single chain and show why slashing on the provider for equivocation on the consumer is challenging.

+

Note that future versions of the Cosmos SDK, CometBFT, and ibc-go could modify the way we slash, etc. Therefore, a future reader of this ADR, should note that when we refer to Cosmos SDK, CometBFT, and ibc-go we specifically refer to their v0.47, v0.37 and v7.3.0 versions respectively.

+

Single-chain slashing

+

Slashing is implemented across the slashing +and staking modules. +The slashing module's keeper calls the staking module's Slash() method, passing among others, the infractionHeight (i.e., the height when the equivocation occurred), the validator's power at the infraction height, and the slashFactor (currently set to 5% in case of equivocation on the Cosmos Hub).

+

Slashing undelegations and redelegations

+

To slash undelegations, Slash goes through all undelegations and checks whether they started before or after the infraction occurred. If an undelegation started before the infractionHeight, then it is not slashed, otherwise it is slashed by slashFactor.

+

The slashing of redelegations happens in a similar way, meaning that Slash goes through all redelegations and checks whether the redelegations started before or after the infractionHeight.

+

Slashing delegations

+

Besides undelegations and redelegations, the validator's delegations need to also be slashed. +This is performed by deducting the appropriate amount of tokens from the validator. Note that this deduction is computed based on the voting power the misbehaving validator had at the height of the equivocation. As a result of the tokens deduction, +the tokens per share +reduce and hence later on, when delegators undelegate or redelegate, the delegators retrieve back less +tokens, effectively having their tokens slashed. The rationale behind this slashing mechanism, as mentioned in the Cosmos SDK documentation

+
+

[...] is to simplify the accounting around slashing. Rather than iteratively slashing the tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, effectively reducing the value of each issued delegator share.

+
+

This approach of slashing delegations does not utilize the +infractionHeight in any way and hence the following scenario could occur:

+
    +
  1. a validator V performs an equivocation at a height Hi
  2. +
  3. a new delegator D delegates to V after height Hi
  4. +
  5. evidence of the equivocation by validator V is received
  6. +
  7. the tokens of delegator D are slashed
  8. +
+

In the above scenario, delegator D is slashed, even though D's voting power did not contribute to the infraction.

+

Old evidence

+

In the single-chain case, old evidence (e.g., from 3 years ago) is ignored. This is achieved through +CometBFT that ignores old evidence based on the parameters MaxAgeNumBlocks and MaxAgeDuration (see here). +Additionally, note that when the evidence is sent by CometBFT to the application, the evidence is rechecked in the evidence module of Cosmos SDK and if it is old, the evidence is ignored. +In Cosmos Hub, the MaxAgeNumBlocks is set to 1000000 (i.e., ~70 days if we assume we need ~6 sec per block) and MaxAgeDuration is set to 172800000000000 ns (i.e., 2 days). Because of this check, we can easily exclude old evidence.

+

Slashing for equivocation on the consumer

+

In the single-chain case, slashing requires both the infractionHeight and the voting power. +In order to slash on the provider for an equivocation on a consumer, we need to have both the provider's infractionHeight and voting power. +Note that the infractionHeight on the consumer chain must be mapped to a height on the provider chain. +Unless we have a way to find the corresponding infractionHeight and power on the provider chain, we cannot slash for equivocation on the consumer in the same way as we would slash in the single-chain case.

+

The challenge of figuring out the corresponding infractionHeight and power values on the provider chain is due to the following trust assumption:

+
    +
  • We trust the consensus layer and validator set of the consumer chains, but we do not trust the application layer.
  • +
+

As a result, we cannot trust anything that stems from the application state of a consumer chain.

+

Note that when a relayer or a user sends evidence through a MsgSubmitConsumerDoubleVoting message, the provider gets access to DuplicateVoteEvidence:

+
type DuplicateVoteEvidence struct {
VoteA *Vote `json:"vote_a"`
VoteB *Vote `json:"vote_b"`

// abci specific information
TotalVotingPower int64
ValidatorPower int64
Timestamp time.Time
}
+

The "abci specific information" fields cannot be trusted because they are not signed. Therefore, +we can use neither ValidatorPower for slashing on the provider chain, nor the Timestamp to check the evidence age. We can get the infractionHeight from the votes, but this infractionHeight corresponds to the infraction height on the consumer and not on the provider chain. +Similarly, when a relayer or a user sends evidence through a MsgSubmitConsumerMisbehaviour message, the provider gets access to Misbehaviour that we cannot use to extract the infraction height, power, or the time on the provider chain.

+

Proposed solution

+

As a first iteration, we propose the following approach. At the moment the provider receives evidence of equivocation on a consumer:

+
    +
  1. slash all the undelegations and redelegations using slashFactor;
  2. +
  3. slash all delegations using as voting power the sum of the voting power of the misbehaving validator and the power of all the ongoing undelegations and redelegations.
  4. +
+

Evidence expiration: Additionally, because we cannot infer the actual time of the evidence (i.e., the timestamp of the evidence cannot be trusted), we do not consider evidence expiration and hence old evidence is never ignored (e.g., the provider would act on 3 year-old evidence of equivocation on a consumer). +Additionally, we do not need to store equivocation evidence to avoid slashing a validator more than once, because we do not slash tombstoned validators and we tombstone a validator when slashed.

+

We do not act on evidence that was signed by a validator consensus key that is pruned when we receive the evidence. We prune a validator's consensus key if the validator has assigned a new consumer key (using MsgAssignConsumerKey) and an unbonding period on the consumer chain has elapsed (see key assignment ADR). Note that the provider chain is informed that the unbonding period has elapsed on the consumer when the provider receives a VSCMaturedPacket and because of this, if the consumer delays the sending of a VSCMaturedPacket, we would delay the pruning of the key as well.

+

Implementation

+

The following logic needs to be added to the HandleConsumerDoubleVoting and HandleConsumerMisbehaviour methods:

+
undelegationsInTokens := sdk.NewInt(0)
for _, v := range k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validatorAddress) {
for _, entry := range v.Entries {
if entry.IsMature(now) && !entry.OnHold() {
// undelegation no longer eligible for slashing, skip it
continue
}
undelegationsInTokens = undelegationsInTokens.Add(entry.InitialBalance)
}
}

redelegationsInTokens := sdk.NewInt(0)
for _, v := range k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validatorAddress) {
for _, entry := range v.Entries {
if entry.IsMature(now) && !entry.OnHold() {
// redelegation no longer eligible for slashing, skip it
continue
}
redelegationsInTokens = redelegationsInTokens.Add(entry.InitialBalance)
}
}

infractionHeight := 0
undelegationsAndRedelegationsInPower = sdk.TokensToConsensusPower(undelegationsInTokens.Add(redelegationsInTokens))
totalPower := validator's voting power + undelegationsAndRedelegationsInPower
slashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)

k.stakingKeeper.Slash(ctx, validatorConsAddress, infractionHeight, totalPower, slashFraction, DoubleSign)
+

Infraction height: We provide a zero infractionHeight to the Slash method in order to slash all ongoing undelegations and redelegations (see checks in Slash, SlashUnbondingDelegation, and SlashRedelegation).

+

Power: We pass the sum of the voting power of the misbehaving validator when the evidence was received (i.e., at evidence height) and the power of all the ongoing undelegations and redelegations. +If we assume that the slashFactor is 5%, then the voting power we pass is power + totalPower(undelegations) + totalPower(redelegations). +Hence, when the Slash method slashes all the undelegations and redelegations it would end up with 0.05 * power + 0.05 * totalPower(undelegations) + 0.05 * totalPower(redelegations) - 0.05 * totalPower(undelegations) - 0.05 * totalPower(redelegations) = 0.05 * power and hence it would slash 5% of the validator's power when the evidence is received.

+

Positive

+

With the proposed approach we can quickly implement slashing functionality on the provider chain for consumer chain equivocations. +This approach does not need to change the staking module and therefore does not change in any way how slashing is performed today for a single chain.

+

Negative

+
    +
  • We definitely slash more when it comes to undelegations and redelegations because we slash for all of them without considering an infractionHeight.
  • +
  • We potentially slash more than what we would have slashed if we knew the voting power at the corresponding infractionHeight in the provider chain.
  • +
  • We slash on old evidence of equivocation on a consumer.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-013-equivocation-slashing.html.html b/v4.2.0/adrs/adr-013-equivocation-slashing.html.html new file mode 100644 index 0000000000..159bb314fb --- /dev/null +++ b/v4.2.0/adrs/adr-013-equivocation-slashing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-014-epochs.html b/v4.2.0/adrs/adr-014-epochs.html new file mode 100644 index 0000000000..e3b10f476b --- /dev/null +++ b/v4.2.0/adrs/adr-014-epochs.html @@ -0,0 +1,72 @@ + + + + + +Epochs | Interchain Security + + + + +
Version: v4.2.0

ADR 014: Epochs

+

Changelog

+
    +
  • 2024-01-05: Proposed, first draft of ADR.
  • +
  • 2024-02-29: Updated so that it describes the implementation where we store the whole consumer validator set.
  • +
+

Status

+

Proposed

+

Context

+

In every block that the provider valset changes, a VSCPacket must be sent to every consumer and a corresponding VSCMaturedPacket sent back. +Given that the validator powers may change very often on the provider chain (e.g., the Cosmos Hub), this approach results in a large workload for the relayers. +Although the validator powers may change very often, these changes are usually small and have an insignificant impact on the chain's security. +In other words, the valset on the consumers can be slightly outdated without affecting security. +As a matter of fact, this already happens due to relaying delays.

+

As a solution, this ADR introduces the concept of epochs. +An epoch consists of multiple blocks. +The provider sends VSCPackets once per epoch. +A VSCPacket contains all the validator updates that are needed by a consumer chain.

+

Decision

+

The implementation of epochs requires the following changes:

+
    +
  • For each consumer chain, we store the consumer validator set that is currently (i.e., in this epoch) validating the +consumer chain. For each validator in the set we store i) its voting power, and ii) the public key that it is +using on the consumer chain during the current (i.e., ongoing) epoch. +The initial consumer validator set for a chain is set during the creation of the consumer genesis.
  • +
  • We introduce the BlocksPerEpoch param that sets the number of blocks in an epoch. By default, BlocksPerEpoch is +set to be 600 which corresponds to 1 hour, assuming 6 seconds per block. This param can be changed through +a governance proposal. In the provider EndBlock we check BlockHeight() % BlocksPerEpoch() == 0 +to decide when an epoch has ended.
  • +
  • At the end of every epoch, if there were validator set changes on the provider, then for every consumer chain, we +construct a VSCPacket with all the validator updates and add it to the list of PendingVSCPackets. We compute the +validator updates needed by a consumer chain by comparing the stored list of consumer validators with the current +bonded validators on the provider, with something similar to this:
  • +
+
// get the valset that has been validating the consumer chain during this epoch 
currentValidators := GetConsumerValSet(consumerChain)
// generate the validator updates needed to be sent through a `VSCPacket` by comparing the current validators
// in the epoch with the latest bonded validators
valUpdates := DiffValidators(currentValidators, stakingmodule.GetBondedValidators())
// update the current validators set for the upcoming epoch to be the latest bonded validators instead
SetConsumerValSet(stakingmodule.GetBondedValidators())
+

Note that a validator can change its consumer public key for a specific consumer chain an arbitrary amount of times during +a block and during an epoch. Then, when we generate the validator updates in DiffValidators, we have to check whether +the current consumer public key (retrieved by calling GetValidatorConsumerPubKey) is different from the consumer public +key the validator was using in the current epoch.

+

Consequences

+

Positive

+
    +
  • Reduce the cost of relaying.
  • +
  • Reduce the amount of IBC packets needed for ICS.
  • +
  • Simplifies key-assignment code because +we only need to check if the consumer_public_key has been modified since the last epoch to generate an update.
  • +
+

Negative

+
    +
  • Increase the delay in the propagation of validator set changes (but for reasonable epoch lengths on the order of ~hours or less, this is unlikely to be significant).
  • +
+

Neutral

+

N/A

+

References

+
+ + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-014-epochs.html.html b/v4.2.0/adrs/adr-014-epochs.html.html new file mode 100644 index 0000000000..e09b1e4f41 --- /dev/null +++ b/v4.2.0/adrs/adr-014-epochs.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-015-partial-set-security.html b/v4.2.0/adrs/adr-015-partial-set-security.html new file mode 100644 index 0000000000..315a802635 --- /dev/null +++ b/v4.2.0/adrs/adr-015-partial-set-security.html @@ -0,0 +1,154 @@ + + + + + +Partial Set Security | Interchain Security + + + + +
Version: v4.2.0

ADR 015: Partial Set Security

+

Changelog

+
    +
  • 2024-01-22: Proposed, first draft of ADR.
  • +
+

Status

+

Proposed

+

Context

+

Currently, in Replicated Security, the entire validator set of the provider chain is used to secure consumer chains. There are at least three concerns with this approach. +First, a large number of validators might be forced to validate consumer chains they are not interested in securing. +Second, it is costly for small validators to secure additional chains. This concern is only partially addressed through soft opt-out that allows small validators to opt out from validating consumer chains. +Third and for the above reasons, it is challenging for a new consumer chain to join Replicated Security.

+

As a solution, we present Partial Set Security (PSS). As the name suggests, PSS allows for every consumer chain to be secured by only a subset of the provider validator set. +In what follows we propose the exact steps we need to take to implement PSS. This is a first iteration of PSS, and therefore we present the most minimal solution that make PSS possible.

+

Decision

+

In Replicated Security, all the provider validators have to secure every consumer chain (with the exception of those validators allowed to opt out through the soft opt-out feature).

+

In PSS, we allow validators to opt in and out of validating any given consumer chain. +This has one exception: we introduce a parameter N for each consumer chain and require that the validators in top N% of the provider's voting power have to secure the consumer chain. +Validators outside of the top N% can dynamically opt in if they want to validate on the consumer chain.

+

For example, if a consumer chain has N = 95%, then it ultimately receives the same security it receives today with Replicated Security (with a default SoftOptOutThreshold of 5%). +On the other hand, if a consumer chain has N = 0%, then no validator is forced to validate the chain, but validators can opt in to do so instead.

+

For the remainder of this ADR, we call a consumer chain Top N if it has joined as a Top N chain with N > 0 and Opt In chain otherwise. An Opt In consumer chain is secured only by the validators that have opted in to secure that chain.

+

We intend to implement PSS using a feature branch off v4.0.0 interchain security.

+

How do consumer chains join?

+

As a simplification and to avoid chain id squatting, a consumer chain can only join PSS through a governance proposal and not in a permissionless way.

+

However, this proposal type will be modified so that it requires a lower quorum percentage than normal proposal, and every validator who voted "YES" on the proposal will form the consumer chain's initial validator set.

+

Consumer chains join PSS the same way chains now join Replicated Security, namely through a ConsumerAdditionProposal proposal. +We extend ConsumerAdditionProposal with one optional field:

+

uint32 top_N: Corresponds to the percentage of validators that join under the Top N case. +For example, 53 corresponds to a Top 53% chain, meaning that the top 53% provider validators have to validate the proposed consumer chain. +top_N can be 0 or include any value in [50, 100]. A chain can join with top_N == 0 as an Opt In, or with top_N ∈ [50, 100] as a Top N chain.

+

In case of a Top N chain, we restrict the possible values of top_N from (0, 100] to [50, 100]. +By having top_N >= 50 we can guarantee that we cannot have a successful attack, assuming that at most 1/3 of provider validators can be malicious. +This is because, a Top N chain with N >= 50% would have at least 1/3 honest validators, which is sufficient to stop attacks. +Additionally, by having N >= 50% (and hence N > (VetoThreshold = 33.4%)) we enable the top N validators to Veto any ConsumerAdditionProposal for consumer chains they do not want to validate.

+

If a proposal has the top_N argument wrongly set, it should get rejected in [ValidateBasic] (https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/types/proposal.go#L86).

+

In the code, we distinguish whether a chain is Top N or Opt In by checking whether top_N is zero or not.

+

In a future version of PSS, we intend to introduce a ConsumerModificationProposal so that we can modify the parameters of a consumer chain, e.g, a chain that is Opt In to become Top N, etc.

+

State & Query

+

We augment the provider module’s state to keep track of the top_N value for each consumer chain. The key to store this information would be:

+
topNBytePrefix | len(chainID) | chainID
+

To create the above key, we can use ChainIdWithLenKey.

+

Then in the keeper we introduce methods as follows:

+
func (k Keeper) SetTopN(ctx sdk.Context, chainID string, topN uint32)
func (k Keeper) IsTopN(ctx sdk.Context, chainID string) bool
func (k Keeper) IsOptIn(ctx sdk.Context, chainID string) bool

// returns the N if Top N chain, otherwise an error
func (k Keeper) GetTopN(ctx sdk.Context, chainID string) (uint32, error)
+

We also extend the interchain-security-pd query provider list-consumer-chains query to return information on whether a consumer chain is an Opt In or a Top N chain and with what N. +This way, block explorers can present informative messages such as "This chain is secured by N% of the provider chain" for consumer chains.

+

How do validators opt in?

+

A validator can opt in by sending a new type of message that we introduce in tx.proto.

+
message MsgOptIn {
// the chain id of the consumer chain to opt in to
string chainID = 1;
// the provider address of the validator
string providerAddr = 2;
// (optional) the consensus public key to use on the consumer
optional string consumerKey = 3;
}
+

Note that in a Top N consumer chain, the top N% provider validators have to validate the consumer chain. +Nevertheless, validators in the bottom (100 - N)% can opt in to validate as well. +Provider validators that belong or enter the top N% validators are automatically opted in to validate a Top N consumer chain. +This means that if a validator V belongs to the top N% validators but later falls (e.g., due to undelegations) to the bottom (100 - N)%, V is still considered opted in and has to validate unless V sends a MsgOptOut message (see below). +By automatically opting in validators when they enter the top N% validators and by forcing top N% validators to explicitly opt out in case they fall to the (100 - N)% bottom validators we simplify the design of PSS.

+

Note that a validator can send a MsgOptIn message even if the consumer chain is not yet running. To do this we reuse the IsConsumerProposedOrRegistered. If the chainID does not exist, the MsgOptIn should fail, as well as if the provider address does not exist.

+

Optionally, a validator that opts in can provide a consumerKey so that it assigns a different consumer key (from the provider) to the consumer chain. +Naturally, a validator can always change the consumer key on a consumer chain by sending a MsgAssignConsumerKey message at a later point in time, as is done in Replicated Security.

+

State & Query

+

For each validator, we store a pair (blockHeight, isOptedIn) that contains the block height the validator opted in and whether the validator is currently opted in or not, under the key:

+
optedInBytePrefix | len(chainID) | chainID | addr
+

By using a prefix iterator on optedInBytePrefix | len(chainID) | chainID we retrieve all the opted in validators.

+

We introduce the following Keeper methods.

+
// returns all the validators that have opted in on chain `chainID`
func (k Keeper) GetOptedInValidators(ctx sdk.Context, chainID string) []Validators

func (k Keeper) IsValidatorOptedIn(ctx sdk.Context, chainID string, val Validator) bool
+

We introduce the following two queries:

+
interchain-security-pd query provider optedInValidators $chainID
interchain-security-pd query provider hasToValidate $providerAddr
+

One query to retrieve the validators that are opted in and hence the validators that need to validate the consumer chain and one query that given a validator's address returns all the chains this validator has to validate.

+

When do validators opt in?

+

As described earlier, validators can manually opt in by sending a MsgOptIn message. +Additionally, in a Top N chain, a validator is automatically opted in when it moves from the bottom (100 - N)% to the top N% validators.

+

Lastly, validators can also opt in if they vote Yes during the ConsumerAdditionProposal that introduces a consumer chain. +This simplifies validators operations because they do not have to send an additional message to opt in.

+

Because the Tally method deletes the votes after reading them, we cannot check the votes of the validators after the votes have been tallied. +To circumvent this, we introduce a hook for AfterProposalVote and keep track of all the votes cast by a validator. +If a validator casts more than one vote, we only consider the latest vote. +Finally, we only consider a validator has opted in if it casts a 100% Yes vote in case of a weighted vote.

+

How do validators opt out?

+

Validators that have opted in on a chain can opt out by sending the following message:

+
message MsgOptOut {
// the chain id of the consumer chain to opt out from
string chainID = 1;
// the provider address of the validator
string providerAddr = 2;
}
+

Validators can only opt out after a consumer chain has started and hence the above message returns an error if the chain with chainID is not running. +Additionally, a validator that belongs to the top N% validators cannot opt out from a Top N chain and hence a MsgOptOut would error in such a case.

+

State & Query

+

We also update the state of the opted-in validators when a validator has opted out by removing the opted-out validator.

+

Note that only opted-in validators can be punished for downtime on a consumer chain. +For this, we use historical info of all the validators that have opted in; We can examine the blockHeight stored under the key optedInBytePrefix | len(chainID) | chainID | addr to see if a validator was opted in. +This way we can jail validators for downtime knowing that indeed the validators have opted in at some point in the past. +Otherwise, we can think of a scenario where a validator V is down for a period of time, but before V gets punished for downtime, validator V opts out, and then we do not know whether V should be punished or not.

+

When does a consumer chain start?

+

A Top N consumer chain always starts at the specified date (spawn_time) if the ConsumerAdditionProposal has passed. +An Opt In consumer chain only starts if at least one validator has opted in. We check this in BeginBlockInit:

+
func (k Keeper) BeginBlockInit(ctx sdk.Context) {
propsToExecute := k.GetConsumerAdditionPropsToExecute(ctx)

for _, prop := range propsToExecute {
chainID := prop.ChainId
if !k.IsTopN(ctx, chainID) && len(k.GetOptedInValidators(ctx, chainID)) == 0 {
// drop the proposal
ctx.Logger().Info("could not start chain because no validator has opted in")
continue
}
...
+

How do we send the partial validator sets to the consumer chains?

+

A consumer chain should only be validated by opted in validators. +We introduce logic to do this when we queue the VSCPackets. +The logic behind this, is not as straightforward as it seems because CometBFT does not receive the validator set that has to validate a chain, but rather a delta of validator updates. +For example, to remove an opted-out validator from a consumer chain, we have to send a validator update with a power of 0, similarly to what is done in the assignment of consumer keys. +We intend to update this ADR at a later stage on how exactly we intend to implement this logic.

+

How do we distribute rewards?

+

Currently, rewards are distributed as follows: The consumer periodically sends rewards on the provider ConsumerRewardsPool address. +The provider then transfers those rewards to the fee collector address and those transferred rewards are distributed to validators and delegators.

+

In PSS, we distribute rewards only to validators that actually validate the consumer chain. +To do this, we have a pool associated with each consumer chain and consumers IBC transfer the rewards to this pool. +We then extract the rewards from each consumer pool and distribute them to the opted in validators.

+

Note that we only distribute rewards to validators that have been opted in for some time (e.g., 10000 blocks) to avoid cases where validators opt in just to receive rewards and then opt out immediately afterward.

+

Misbehaviour

+

Fraud votes

+

In an Opt In chain, a set of validators might attempt to perform an attack. To deter such potential attacks, PSS allows for the use of fraud votes. +A fraud vote is a governance proposal that enables the slashing of validators that performed an attack. +Due to their inherent complexity, we intend to introduce fraud votes in a different ADR and at a future iteration of PSS.

+

Double signing

+

We do not change the way slashing for double signing and light client attacks functions. +If a validator misbehaves on a consumer, then we slash that validator on the provider.

+

Downtime

+

We do not change the way downtime jailing functions. +If a validator is down on a consumer chain for an adequate amount of time, we jail this validator on the provider but only if the validator was opted in on this consumer chain in the recent past.

+

Consequences

+

Positive

+
    +
  • +

    Easier for new consumer chains to consume the provider's chain economic security because proposals are more likely to pass if not everyone is forced to validate.

    +
  • +
  • +

    Smaller validators are not forced to validate chains anymore if they do not want to.

    +
  • +
  • +

    We can deprecate the soft opt-out implementation.

    +
  • +
+

Negative

+
    +
  • A consumer chain does not receive the same economic security as with Replicated Security (assuming the value of SoftOptOutThreshold is 5%), unless it is a Top N chain with N >= 95%.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-015-partial-set-security.html.html b/v4.2.0/adrs/adr-015-partial-set-security.html.html new file mode 100644 index 0000000000..3db5a07b9a --- /dev/null +++ b/v4.2.0/adrs/adr-015-partial-set-security.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-template.html b/v4.2.0/adrs/adr-template.html new file mode 100644 index 0000000000..b5759f2f98 --- /dev/null +++ b/v4.2.0/adrs/adr-template.html @@ -0,0 +1,50 @@ + + + + + +ADR Template | Interchain Security + + + + +
Version: v4.2.0

ADR [ADR-NUMBER]: [TITLE]

+

Changelog

+
    +
  • +
+

Status

+
+

A decision may be "proposed" if it hasn't been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement.

+
+

[Deprecated|Proposed|Accepted]

+

Context

+
+

This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution.

+
+

Decision

+
+

This section explains all of the details of the proposed solution, including implementation details. +It should also describe affects / corollary items that may need to be changed as a part of this. +If the proposed change will be large, please also indicate a way to do the change to maximize ease of review. +(e.g. the optimal split of things to do between separate PR's)

+
+

Consequences

+
+

This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones.

+
+

Positive

+

Negative

+

Neutral

+

References

+
+

Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!

+
+
    +
  • [references]
  • +
+ + \ No newline at end of file diff --git a/v4.2.0/adrs/adr-template.html.html b/v4.2.0/adrs/adr-template.html.html new file mode 100644 index 0000000000..871a14db33 --- /dev/null +++ b/v4.2.0/adrs/adr-template.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/adrs/intro.html b/v4.2.0/adrs/intro.html new file mode 100644 index 0000000000..759c7cfafa --- /dev/null +++ b/v4.2.0/adrs/intro.html @@ -0,0 +1,60 @@ + + + + + +ADRs | Interchain Security + + + + +
Version: v4.2.0

Architecture Decision Records (ADR)

+

This is a location to record all high-level architecture decisions in the Interchain Security project.

+

You can read more about the ADR concept in this blog post.

+

An ADR should provide:

+
    +
  • Context on the relevant goals and the current state
  • +
  • Proposed changes to achieve the goals
  • +
  • Summary of pros and cons
  • +
  • References
  • +
  • Changelog
  • +
+

Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and +justification for a change in architecture, or for the architecture of something +new. The spec is much more compressed and streamlined summary of everything as +it is or should be.

+

If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match.

+

Note the context/background should be written in the present tense.

+

To suggest an ADR, please make use of the ADR template provided.

+

Table of Contents

+

Accepted

+ +

Proposed

+ +

Rejected

+ +

Deprecated

+
+ + \ No newline at end of file diff --git a/v4.2.0/adrs/intro.html.html b/v4.2.0/adrs/intro.html.html new file mode 100644 index 0000000000..b63acea386 --- /dev/null +++ b/v4.2.0/adrs/intro.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/consumer-development/app-integration.html b/v4.2.0/consumer-development/app-integration.html new file mode 100644 index 0000000000..8e8481e8fb --- /dev/null +++ b/v4.2.0/consumer-development/app-integration.html @@ -0,0 +1,32 @@ + + + + + +Developing an ICS consumer chain | Interchain Security + + + + +
Version: v4.2.0

Developing an ICS consumer chain

+

When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol. +To help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications.

+

Basic consumer chain

+

The source code for the example app can be found here.

+

Please note that consumer chains do not implement the staking module - the validator set is replicated from the provider, meaning that the provider and the consumer use the same validator set and their stake on the provider directly determines their stake on the consumer. +At present there is no opt-in mechanism available, so all validators of the provider must also validate on the provider chain.

+

Your chain should import the consumer module from x/consumer and register it in the correct places in your app.go. +The x/consumer module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in. +You should not need to manage or override any code from the x/consumer module.

+

Democracy consumer chain

+

The source code for the example app can be found here.

+

This type of consumer chain wraps the basic CosmosSDK x/distribution, x/staking and x/governance modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system.

+

This allows the consumer chain to leverage those modules while also using the x/consumer module.

+

With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.

+

Standalone chain to consumer chain changeover

+

See the standalone chain to consumer chain changeover guide for more information on how to transition your standalone chain to a consumer chain.

+ + \ No newline at end of file diff --git a/v4.2.0/consumer-development/app-integration.html.html b/v4.2.0/consumer-development/app-integration.html.html new file mode 100644 index 0000000000..f6dba50d75 --- /dev/null +++ b/v4.2.0/consumer-development/app-integration.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/consumer-development/changeover-procedure.html b/v4.2.0/consumer-development/changeover-procedure.html new file mode 100644 index 0000000000..19dd766918 --- /dev/null +++ b/v4.2.0/consumer-development/changeover-procedure.html @@ -0,0 +1,136 @@ + + + + + +Changeover Procedure | Interchain Security + + + + +
Version: v4.2.0

Changeover Procedure

+

Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.

+

The relevant protocol specifications are available below:

+ +

Overview

+

Standalone to consumer changeover procedure can roughly be separated into 4 parts:

+

1. ConsumerAddition proposal submitted to the provider chain

+

The proposal is equivalent to the "normal" ConsumerAddition proposal submitted by new consumer chains.

+

However, here are the most important notes and differences between a new consumer chain and a standalone chain performing a changeover:

+
    +
  • chain_id must be equal to the standalone chain id
  • +
  • initial_height field has additional rules to abide by:
  • +
+
caution
{
...
"initial_height" : {
// must correspond to current revision number of standalone chain
// e.g. stride-1 => "revision_number": 1
"revision_number": 1,

// must correspond to a height that is at least 1 block after the upgrade
// that will add the `consumer` module to the standalone chain
// e.g. "upgrade_height": 100 => "revision_height": 101
"revision_height": 1,
},
...
}

RevisionNumber: 0, RevisionHeight: 111

+
    +
  • +

    genesis_hash can be safely ignored because the chain is already running. A hash of the standalone chain's initial genesis may be used

    +
  • +
  • +

    binary_hash may not be available ahead of time. All chains performing the changeover go through rigorous testing - if bugs are caught and fixed the hash listed in the proposal may not be the most recent one.

    +
  • +
  • +

    spawn_time listed in the proposal MUST be before the upgrade_height listed in the upgrade proposal on the standalone chain.

    +
  • +
+
caution

spawn_time must occur before the upgrade_height on the standalone chain is reached because the provider chain must generate the ConsumerGenesis that contains the validator set that will be used after the changeover.

+
    +
  • +

    unbonding_period must correspond to the value used on the standalone chain. Otherwise, the clients used for the ccv protocol may be incorrectly initialized.

    +
  • +
  • +

    distribution_transmission_channel should be set.

    +
  • +
+
note

Populating distribution_transmission_channel will enable the standalone chain to reuse one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ibc denom that may already be in use.

If the parameter is not set, a new channel will be created.

+
    +
  • +

    ccv_timeout_period has no important notes

    +
  • +
  • +

    transfer_timeout_period has no important notes

    +
  • +
  • +

    consumer_redistribution_fraction has no important notes

    +
  • +
  • +

    blocks_per_distribution_transmission has no important notes

    +
  • +
  • +

    historical_entries has no important notes

    +
  • +
+

2. upgrade proposal on standalone chain

+

The standalone chain creates an upgrade proposal to include the interchain-security/x/ccv/consumer module.

+
caution

The upgrade height in the proposal should correspond to a height that is after the spawn_time in the consumer addition proposal submitted to the provider chain.

+

Otherwise, the upgrade is indistinguishable from a regular on-chain upgrade proposal.

+

3. spawn time is reached

+

When the spawn_time is reached on the provider it will generate a ConsumerGenesis that contains the validator set that will supersede the standalone validator set.

+

This ConsumerGenesis must be available on the standalone chain during the on-chain upgrade.

+

4. standalone chain upgrade

+

Performing the on-chain upgrade on the standalone chain will add the ccv/consumer module and allow the chain to become a consumer of replicated security.

+
caution

The ConsumerGenesis must be exported to a file and placed in the correct folder on the standalone chain before the upgrade.

The file must be placed at the exact specified location, otherwise the upgrade will not be executed correctly.

Usually the file is placed in $NODE_HOME/config, but the file name and the exact directory is dictated by the upgrade code on the standalone chain.

    +
  • please check exact instructions provided by the standalone chain team
  • +
+

After the genesis.json file has been made available, the process is equivalent to a normal on-chain upgrade. The standalone validator set will sign the next couple of blocks before transferring control to provider validator set.

+

The standalone validator set can still be slashed for any infractions if evidence is submitted within the unboding_period.

+

Notes

+

The changeover procedure may be updated in the future to create a seamless way of providing the validator set information to the standalone chain.

+

Onboarding Checklist

+

This onboarding checklist is slightly different from the one under Onboarding

+

Additionally, you can check the testnet repo for a comprehensive guide on preparing and launching consumer chains.

+

1. Complete testing & integration

+
    +
  • test integration with gaia
  • +
  • test your protocol with supported relayer versions (minimum hermes 1.4.1)
  • +
  • test the changeover procedure
  • +
  • reach out to the ICS team if you are facing issues
  • +
+

2. Create an Onboarding Repository

+

To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain.

+

This should include (at minimum):

+
    +
  • genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see Transform Consumer Genesis)
  • +
  • information about relevant seed/peer nodes you are running
  • +
  • relayer information (compatible versions)
  • +
  • copy of your governance proposal (as JSON)
  • +
  • a script showing how to start your chain and connect to peers (optional)
  • +
  • take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable
  • +
+

Example of such a repository can be found here.

+

3. Submit a ConsumerChainAddition Governance Proposal to the provider

+

Before you submit a ConsumerChainAddition proposal, please provide a spawn_time that is before the upgrade_height of the upgrade that will introduce the ccv module to your chain.

+
danger

If the spawn_time happens after your upgrade_height the provider will not be able to communicate the new validator set to be used after the changeover.

+

Additionally, reach out to the community via the forum to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers.

+
    +
  • determine your chain's spawn time
  • +
  • determine consumer chain parameters to be put in the proposal
  • +
  • take note to include a link to your onboarding repository
  • +
+

Example of a consumer chain addition proposal (compare with the ConsumerAdditionProposal in the ICS Provider Proposals section for chains that launch as consumers):

+
// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain or add a standalone chain.
// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.
// It is recommended that spawn time occurs after the proposal end time and that it is scheduled to happen before the standalone chain upgrade
// that sill introduce the ccv module.
{
// Title of the proposal
"title": "Changeover Standalone chain",
// Description of the proposal
// format the text as a .md file and include the file in your onboarding repository
"description": ".md description of your chain and all other relevant information",
// Proposed chain-id of the new consumer chain.
// Must be unique from all other consumer chain ids of the executing provider chain.
"chain_id": "standalone-1",
// Initial height of new consumer chain.
"initial_height" : {
// must correspond to current revision number of standalone chain
// e.g. standalone-1 => "revision_number": 1
"revision_number": 1,

// must correspond to a height that is at least 1 block after the upgrade
// that will add the `consumer` module to the standalone chain
// e.g. "upgrade_height": 100 => "revision_height": 101
"revision_number": 1,
},
// Hash of the consumer chain genesis state without the consumer CCV module genesis params.
// => not relevant for changeover procedure
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
// Hash of the consumer chain binary that should be run by validators on standalone chain upgrade
// => not relevant for changeover procedure as it may become stale
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
// Unbonding period for the consumer chain.
// It should should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
// IBC transfer packets will timeout after this interval elapses.
"transfer_timeout_period": 1800000000000,
// The fraction of tokens allocated to the consumer redistribution address during distribution events.
// The fraction is a string representing a decimal number. For example "0.75" would represent 75%.
// The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.
"consumer_redistribution_fraction": "0.75",
// BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.
// eg. send rewards to the provider every 1000 blocks
"blocks_per_distribution_transmission": 1000,
// The number of historical info entries to persist in store.
// This param is a part of the cosmos sdk staking module. In the case of
// a ccv enabled consumer chain, the ccv module acts as the staking module.
"historical_entries": 10000,
// The ID of a token transfer channel used for the Reward Distribution
// sub-protocol. If DistributionTransmissionChannel == "", a new transfer
// channel is created on top of the same connection as the CCV channel.
// Note that transfer_channel_id is the ID of the channel end on the consumer chain.
// it is most relevant for chains performing a standalone to consumer changeover
// in order to maintain the existing ibc transfer channel
"distribution_transmission_channel": "channel-123" // NOTE: use existing transfer channel if available
}
+

3. Submit an Upgrade Proposal & Prepare for Changeover

+

This proposal should add the ccv consumer module to your chain.

+
    +
  • proposal upgrade_height must happen after spawn_time in the ConsumerAdditionProposal
  • +
  • advise validators about the exact procedure for your chain and point them to your onboarding repository
  • +
+

4. Upgrade time 🚀

+
    +
  • after spawn_time, request ConsumerGenesis from the provider and place it in <CURRENT_USER_HOME_DIR>/.sovereign/config/genesis.json
  • +
  • upgrade the binary to the one listed in your UpgradeProposal
  • +
+

The chain starts after at least 66.67% of standalone voting power comes online. The consumer chain is considered interchain secured once the "old" validator set signs a couple of blocks and transfers control to the provider validator set.

+
    +
  • provide a repo with onboarding instructions for validators (it should already be listed in the proposal)
  • +
  • genesis.json after spawn_time obtained from provider (MUST contain the initial validator set)
  • +
  • maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)
  • +
+ + \ No newline at end of file diff --git a/v4.2.0/consumer-development/changeover-procedure.html.html b/v4.2.0/consumer-development/changeover-procedure.html.html new file mode 100644 index 0000000000..36825d3974 --- /dev/null +++ b/v4.2.0/consumer-development/changeover-procedure.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/consumer-development/consumer-chain-governance.html b/v4.2.0/consumer-development/consumer-chain-governance.html new file mode 100644 index 0000000000..16801ba98d --- /dev/null +++ b/v4.2.0/consumer-development/consumer-chain-governance.html @@ -0,0 +1,26 @@ + + + + + +Consumer Chain Governance | Interchain Security + + + + +
Version: v4.2.0

Consumer Chain Governance

+

Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We'll cover what these are in the "Whitelist" section below.

+

Democracy module

+

The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy.

+

Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus.

+

For an example, see the Democracy Consumer

+

CosmWasm

+

There are several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain.

+

For an example, see Neutron.

+

The Whitelist

+

Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see Neutron's whitelist.

+ + \ No newline at end of file diff --git a/v4.2.0/consumer-development/consumer-chain-governance.html.html b/v4.2.0/consumer-development/consumer-chain-governance.html.html new file mode 100644 index 0000000000..7d645a07aa --- /dev/null +++ b/v4.2.0/consumer-development/consumer-chain-governance.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/consumer-development/consumer-genesis-transformation.html b/v4.2.0/consumer-development/consumer-genesis-transformation.html new file mode 100644 index 0000000000..b04f77ac9c --- /dev/null +++ b/v4.2.0/consumer-development/consumer-genesis-transformation.html @@ -0,0 +1,41 @@ + + + + + +Consumer Genesis Transformation | Interchain Security + + + + +
Version: v4.2.0

Consumer Genesis Transformation

+

Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentation on Onboarding and Changeover). +In case that the provider chain is running an older version of the InterChainSecurity (ICS) module than the consumer chain - or vice versa - the exported CCV data might need to be transformed to the format supported by the ICS implementation run on the consumer chain. This is the case if the consumer chain runs version 4 of ICS or later and the provider is running version 3 or older of the ICS module.

+

Check the compatibility notes for known incompatibilities between provider and consumer versions and indications if a consumer genesis transformation is required.

+

To transform such CCV data follow the instructions below

+

1. Prerequisite

+
    +
  • used provider and consumer versions require transformation step as indicated in in the compatibility notes
  • +
  • interchain-security-cd application supports the versions used by the consumer and provider
  • +
+

2. Export the CCV data

+

Export the CCV data from the provider chain as described in the Onboarding and Changeover your following. +As a result the CCV data will be stored in a file in JSON format.

+

3. Transform CCV data

+

To transform the CCV data

+
    +
  • to the format supported by the current version of the consumer run the following command: +
    interchain-security-cd genesis transform [genesis-file]
    +where 'genesis-file' is the path to the file containing the CCV data exported in step 2. +As a result the CCV data in the new format will be written to standard output.
  • +
  • a specific target version of a consumer run the following command: +
    interchain-security-cd genesis transform --to <target_version> [genesis-file]

    +where <target_version is the ICS version the consumer chain is running. +Use interchain-security-cd genesis transform --help to get more details about supported target versions and more.
  • +
+

Use the new CCV data as described in the procedure you're following.

+ + \ No newline at end of file diff --git a/v4.2.0/consumer-development/consumer-genesis-transformation.html.html b/v4.2.0/consumer-development/consumer-genesis-transformation.html.html new file mode 100644 index 0000000000..60218de768 --- /dev/null +++ b/v4.2.0/consumer-development/consumer-genesis-transformation.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/consumer-development/offboarding.html b/v4.2.0/consumer-development/offboarding.html new file mode 100644 index 0000000000..d58d0959f3 --- /dev/null +++ b/v4.2.0/consumer-development/offboarding.html @@ -0,0 +1,19 @@ + + + + + +Offboarding Checklist | Interchain Security + + + + +
Version: v4.2.0

Consumer Offboarding

+

To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).

+
// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.
// If it passes, all the consumer chain's state is removed from the provider chain. The outstanding unbonding
// operation funds are released.
{
// the title of the proposal
"title": "This was a great chain",
"description": "Here is a .md formatted string specifying removal details",
// the chain-id of the consumer chain to be stopped
"chain_id": "consumerchain-1",
// the time on the provider chain at which all validators are responsible to stop their consumer chain validator node
"stop_time": "2023-03-07T12:40:00.000000Z",
}
+

More information will be listed in a future version of this document.

+ + \ No newline at end of file diff --git a/v4.2.0/consumer-development/offboarding.html.html b/v4.2.0/consumer-development/offboarding.html.html new file mode 100644 index 0000000000..32d320516a --- /dev/null +++ b/v4.2.0/consumer-development/offboarding.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/consumer-development/onboarding.html b/v4.2.0/consumer-development/onboarding.html new file mode 100644 index 0000000000..e16d241ba1 --- /dev/null +++ b/v4.2.0/consumer-development/onboarding.html @@ -0,0 +1,61 @@ + + + + + +Onboarding Checklist | Interchain Security + + + + +
Version: v4.2.0

Consumer Onboarding Checklist

+

The following checklists will aid in onboarding a new consumer chain to interchain security.

+

Additionally, you can check the testnet repo for a comprehensive guide on preparing and launching consumer chains.

+

1. Complete testing & integration

+
    +
  • test integration with gaia
  • +
  • test your protocol with supported relayer versions (minimum hermes 1.4.1)
  • +
  • reach out to the ICS team if you are facing issues
  • +
+

2. Create an Onboarding Repository

+

To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain.

+

This should include (at minimum):

+
    +
  • genesis.json without CCV data (before the proposal passes)
  • +
  • genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see Transform Consumer Genesis)
  • +
  • information about relevant seed/peer nodes you are running
  • +
  • relayer information (compatible versions)
  • +
  • copy of your governance proposal (as JSON)
  • +
  • a script showing how to start your chain and connect to peers (optional)
  • +
  • take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable
  • +
+

Example of such a repository can be found here.

+

3. Submit a Governance Proposal

+

Before you submit a ConsumerChainAddition proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch. +If possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues.

+

Additionally, reach out to the community via the forum to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers.

+
    +
  • determine your chain's spawn time
  • +
  • determine consumer chain parameters to be put in the proposal
  • +
  • take note to include a link to your onboarding repository
  • +
  • describe the purpose and benefits of running your chain
  • +
  • determine whether your chain should be an Opt-In chain or a Top N chain (see Partial Set Security)
  • +
  • if desired, decide on power-shaping parameters (see Power Shaping)
  • +
+

Example of a consumer chain addition proposal.

+
// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.
// If it passes, if the top_N parameter is not equal to 0, the top N% of validators by voting power on the provider chain are expected to validate the consumer chain at spawn time.
// Otherwise, only validators that opted in during the proposal period are expected to validate the consumer chain at spawn time.
// It is recommended that spawn time occurs after the proposal end time.
{
// Title of the proposal
"title": "Add consumer chain",
// Description of the proposal
// format the text as a .md file and include the file in your onboarding repository
"description": ".md description of your chain and all other relevant information",
// Proposed chain-id of the new consumer chain.
// Must be unique from all other consumer chain ids of the executing provider chain.
"chain_id": "newchain-1",
// Initial height of new consumer chain.
// For a completely new chain, this will be {0,1}.
"initial_height" : {
"revision_height": 0,
"revision_number": 1,
},
// Hash of the consumer chain genesis state without the consumer CCV module genesis params.
// It is used for off-chain confirmation of genesis.json validity by validators and other parties.
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
// Hash of the consumer chain binary that should be run by validators on chain initialization.
// It is used for off-chain confirmation of binary validity by validators and other parties.
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",
// Time on the provider chain at which the consumer chain genesis is finalized and validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
// Unbonding period for the consumer chain.
// It should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
// IBC transfer packets will timeout after this interval elapses.
"transfer_timeout_period": 1800000000000,
// The fraction of tokens allocated to the consumer redistribution address during distribution events.
// The fraction is a string representing a decimal number. For example "0.75" would represent 75%.
// The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.
"consumer_redistribution_fraction": "0.75",
// BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.
// eg. send rewards to the provider every 1000 blocks
"blocks_per_distribution_transmission": 1000,
// The number of historical info entries to persist in store.
// This param is a part of the cosmos sdk staking module. In the case of
// a ccv enabled consumer chain, the ccv module acts as the staking module.
"historical_entries": 10000,
// The ID of a token transfer channel used for the Reward Distribution
// sub-protocol. If DistributionTransmissionChannel == "", a new transfer
// channel is created on top of the same connection as the CCV channel.
// Note that transfer_channel_id is the ID of the channel end on the consumer chain.
// it is most relevant for chains performing a standalone to consumer changeover
// in order to maintain the existing ibc transfer channel
"distribution_transmission_channel": "channel-123",
// Corresponds to the percentage of validators that have to validate the chain under the Top N case.
// For example, 53 corresponds to a Top 53% chain, meaning that the top 53% provider validators by voting power
// have to validate the proposed consumer chain. top_N can either be 0 or any value in [50, 100].
// A chain can join with top_N == 0 as an Opt In chain, or with top_N ∈ [50, 100] as a Top N chain.
"top_N": 95,
// Corresponds to the maximum power (percentage-wise) a validator can have on the consumer chain. For instance, if
// `validators_power_cap` is set to 32, it means that no validator can have more than 32% of the voting power on the
// consumer chain. Note that this might not be feasible. For example, think of a consumer chain with only
// 5 validators and with `validators_power_cap` set to 10%. In such a scenario, at least one validator would need
// to have more than 20% of the total voting power. Therefore, `validators_power_cap` operates on a best-effort basis.
"validators_power_cap": 0,
// Corresponds to the maximum number of validators that can validate a consumer chain.
// Only applicable to Opt In chains. Setting `validator_set_cap` on a Top N chain is a no-op.
"validator_set_cap": 0,
// Corresponds to a list of provider consensus addresses of validators that are the ONLY ones that can validate
// the consumer chain.
"allowlist": [],
// Corresponds to a list of provider consensus addresses of validators that CANNOT validate the consumer chain.
"denylist": []
}
+

4. Launch

+

The consumer chain starts after at least 66.67% of its voting power comes online. +Note that this means 66.67% of the voting power in the consumer validator set, which will be comprised of all validators that either opted in to the chain or are part of the top N% of the provider chain (and are thus automatically opted in). +The consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer

+
    +
  • provide a repo with onboarding instructions for validators (it should already be listed in the proposal)
  • +
  • genesis.json with ccv data populated (MUST contain the initial validator set)
  • +
  • maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)
  • +
  • have a block explorer in place to track chain activity & health
  • +
+ + \ No newline at end of file diff --git a/v4.2.0/consumer-development/onboarding.html.html b/v4.2.0/consumer-development/onboarding.html.html new file mode 100644 index 0000000000..f79ba9bd2a --- /dev/null +++ b/v4.2.0/consumer-development/onboarding.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/faq.html b/v4.2.0/faq.html new file mode 100644 index 0000000000..6a63eaf720 --- /dev/null +++ b/v4.2.0/faq.html @@ -0,0 +1,86 @@ + + + + + +Frequently Asked Questions | Interchain Security + + + + +
Version: v4.2.0

Frequently Asked Questions

What is a consumer chain?

+

Consumer chain is a blockchain operated by (a subset of) the validators of the provider chain. The ICS protocol ensures that the consumer chain gets information about which validators should run it (informs consumer chain about the current state of the validator set and the opted in validators for this consumer chain on the provider).

+

Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements.

+

What happens to consumer if provider is down?

+

In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set.

+

The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness.

+

However, if the trusting_period (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain. +This means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about.

+

Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point. +At the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.

+

What happens to provider if consumer is down?

+

Consumer chains do not impact the provider chain. +The ICS protocol is concerned only with validator set management, and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events).

+

Can I run the provider and consumer chains on the same machine?

+

Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation.

+

Can the consumer chain have its own token?

+

As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees.

+

How are Tx fees paid on consumer?

+

The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations.

+

Are there any restrictions the consumer chains need to abide by?

+

No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way. +The only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain.

+

What's in it for the validators and stakers?

+

The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by ConsumerRedistributionFraction. The rewards are distributed (sent to the provider) every BlocksPerDistributionTransmission.

+
note

ConsumerRedistributionFraction and BlocksPerDistributionTransmission are parameters defined in the ConsumerAdditionProposal used to create the consumer chain. These parameters can be changed via consumer chain governance.

+

Can the consumer chain have its own governance?

+

Yes.

+

In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.

+

Validators can also be representatives but representatives are not required to run validator nodes.

+

This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance.

+

Can validators opt out of validating a consumer chain?

+

A validator can always opt out from an Opt-In consumer chain. +A validator can only opt out from a Top N chain if the validator does not belong to the top N% validators.

+

How does Slashing work?

+

Validators that perform an equivocation or a light-client attack on a consumer chain are slashed on the provider chain. +We achieve this by submitting the proof of the equivocation or the light-client attack to the provider chain (see slashing).

+

Can Consumer Chains perform Software Upgrades?

+

Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM).

+

Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module.

+

How can I connect to the testnets?

+

Check out the Joining Replicated Security testnet section.

+

How do I start using ICS?

+

To become a consumer chain use this checklist and check the App integration section

+

Which relayers are supported?

+

Currently supported versions:

+
    +
  • Hermes 1.8.0
  • +
+

How does key delegation work in ICS?

+

You can check the Key Assignment Guide for specific instructions.

+

How does Partial Set Security work?

+

Partial Set Security allows a provider chain to share only a subset of its validator set with a consumer chain. This subset can be determined by the top N% validators by voting power, or by validators opting in to validate the consumer chain. Partial Set Security allows for flexible tradeoffs between security, decentralization, and the budget a consumer chain spends on rewards to validators.

+

See the Partial Set Security section for more information.

+

How does a validator know which consumers chains it has to validate?

+

In order for a validator to keep track of all the chains it has to validate, the validator can use the +has-to-validate query.

+

How many chains can a validator opt in to?

+

There is no limit in the number of consumers chains a validator can choose to opt in to.

+

Can validators assign a consensus keys while a consumer-addition proposal is in voting period?

+

Yes, see the Key Assignment Guide for more information.

+

Can validators assign a consensus key during the voting period for a consumer-addition proposal if they are not in the top N?

+

Yes.

+

Can validators opt in to an Opt-in or Top N chain after its consumer-addition proposal voting period is over but before the spawn time?

+

Yes.

+

Can validators opt in to an Opt-in chain after the spawn time if nobody else opted in?

+

No, the consumer chain will not be added if nobody opted in by the spawn time. At least one validator, regardless of its voting power, must opt in before the spawn time arrives in order for the chain can start.

+

Can all validators opt out of an Opt-in chain?

+

Yes, the consumer chain will halt with an ERR CONSENSUS FAILURE error after the opt-out message for the last validator is received.

+

Can validators set a commission rate for chains they have not opted in to?

+

Yes, and this is useful for validators that are not in the top N% of the provider chain, but might move into the top N% in the future. +By setting the commission rate ahead of time, they can make sure that they immediately have a commission rate of their choosing as soon as they are in the top N%.

+ + \ No newline at end of file diff --git a/v4.2.0/faq.html.html b/v4.2.0/faq.html.html new file mode 100644 index 0000000000..ab504ca026 --- /dev/null +++ b/v4.2.0/faq.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/features/key-assignment.html b/v4.2.0/features/key-assignment.html new file mode 100644 index 0000000000..88b1333265 --- /dev/null +++ b/v4.2.0/features/key-assignment.html @@ -0,0 +1,59 @@ + + + + + +Key Assignment | Interchain Security + + + + +
Version: v4.2.0

Key Assignment

+

Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate. +There are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains.

+

The feature is outlined in this ADR-001

+

By sending an AssignConsumerKey transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator.

+
tip

Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity.

+

Rules

+
    +
  • a key can be assigned as soon as the consumer addition proposal is submitted to the provider
  • +
  • validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider
  • +
  • validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X
  • +
  • a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain
  • +
+
tip

Validators can use a different key for each consumer chain.

+

Adding a key

+

First, create a new node on the consumer chain using the equivalent:

+
consumerd init <moniker>
+

Then query your node for the consensus key.

+
consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}
+

Then, make an assign-consensus-key transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain.

+
gaiad tx provider assign-consensus-key <consumer-chain-id> '<pubkey>' --from <tx-signer> --home <home_dir> --gas 900000 -b sync -y -o json
+
    +
  • consumer-chain-id is the string identifier of the consumer chain, as assigned on the provider chain
  • +
  • consumer-pub-key has the following format {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}
  • +
+

Check that the key was assigned correctly by querying the provider:

+
gaiad query provider validator-consumer-key <consumer-chain-id> cosmosvalcons1e....3xsj3ayzf4uv6
+

You must use a valcons address. You can obtain it by querying your node on the provider gaiad tendermint show-address

+

OR

+
gaiad query provider validator-provider-key <consumer-chain-id> consumervalcons1e....123asdnoaisdao
+

You must use a valcons address. You can obtain it by querying your node on the consumer consumerd tendermint show-address

+

OR

+
gaiad query provider all-pairs-valconsensus-address <consumer-chain-id>
+

You just need to use the chainId of consumer to query all pairs valconsensus address with consumer-pub-key for each of pair

+

Changing a key

+

To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied

+

Removing a key

+

To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the Adding a key section and using your provider consensus key.

+
warning

Validators are strongly recommended to assign a separate key for each consumer chain +and not reuse the provider key across consumer chains for security reasons.

+

Querying proposed consumer chains

+

To query the consumer addition proposals that are in the voting period, you can use the following command on the provider:

+
gaiad query provider list-proposed-consumer-chains
+

This query is valuable for staying informed about when keys can be assigned to newly proposed consumer chains.

+ + \ No newline at end of file diff --git a/v4.2.0/features/key-assignment.html.html b/v4.2.0/features/key-assignment.html.html new file mode 100644 index 0000000000..ff2b86792a --- /dev/null +++ b/v4.2.0/features/key-assignment.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/features/partial-set-security.html b/v4.2.0/features/partial-set-security.html new file mode 100644 index 0000000000..6a2a603f34 --- /dev/null +++ b/v4.2.0/features/partial-set-security.html @@ -0,0 +1,30 @@ + + + + + +Partial Set Security | Interchain Security + + + + +
Version: v4.2.0

Partial Set Security

+

Partial Set Security (PSS) allows consumer chains to leverage only a subset of validators from the provider chain, which offers more flexibility than the traditional Replicated Security model. By introducing the top_N parameter, each consumer chain can choose the extent of security needed:

+
    +
  • +

    Top N: Requires the top N% validators from the provider chain to secure the consumer chain. This guarantees that the validators with the most power on the provider will validate the consumer chain, while others can voluntarily opt in.

    +
  • +
  • +

    Opt-In: If the top_N parameter is set to zero, no validator is mandated to secure the consumer chain. Instead, any validator from the provider chain can opt in using a dedicated transaction.

    +
  • +
+

An advantage of a Top N chain is that the consumer chain is guaranteed to receive at least a certain fraction of the market cap of the provider chain in security. In turn, this chain needs to be approved by governance, since validators will be forced to run the chain. Thus, Top N chains should typically expect to need to provide a strong case for why they should be added to the provider chain, and they should make sure they offer enough rewards to incentivize validators and delegators to vote for their proposal.

+

Opt-In chains, on the other hand, are more flexible. While for technical reasons, they are also currently added via governance proposals, since validators are never forced to validate these chains and simply opt in if they want to, they should typically expect to get their proposals approved much more easily compared to Top N chains, since validators that do not want to validate the chain can simply choose not to opt in. +However, opt in chains do not get a fixed amount of security as a relation of the market cap of the provider as top N chains do, so opt in chains might want to keep an eye on how many validators have opted in to validate their chain and adjust their reward emissions accordingly to incentivize validators.

+
tip

Partial Set Security is handled only by the provider chain - the consumer chains are simply sent validator sets, and they are not aware that this represents only a subset of the provider chain's validator set.

+
caution

Both Opt In and Top N chains currently require a governance proposal to be added to the provider chain.

For Top N chains, this is also the long term vision for how they are launched.

For Opt In chains, this is a temporary measure to prevent issues around chain ID squatting, i.e. someone could spuriously register many desirable chain IDs of upcoming consumer chain and simply deny legitimate consumer chains from using them. Eventually, the plan is to allow launching Opt In chains permissionlessly without going through governance, with quality control being handled by the market of validators deciding which chains they would like to validate on.

+ + \ No newline at end of file diff --git a/v4.2.0/features/partial-set-security.html.html b/v4.2.0/features/partial-set-security.html.html new file mode 100644 index 0000000000..fa47109f7a --- /dev/null +++ b/v4.2.0/features/partial-set-security.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/features/power-shaping.html b/v4.2.0/features/power-shaping.html new file mode 100644 index 0000000000..e717a47fef --- /dev/null +++ b/v4.2.0/features/power-shaping.html @@ -0,0 +1,64 @@ + + + + + +Power Shaping | Interchain Security + + + + +
Version: v4.2.0

Power Shaping

+

To give consumer chains more flexibility in choosing their validator set, Interchain Security offers +several "power shaping" mechanisms for consumer chains.

+

These are:

+
    +
  1. Capping the size of the validator set: The consumer chain can specify a maximum number of validators it +wants to have in its validator set. This can be used to limit the number of validators in the set, which can +be useful for chains that want to have a smaller validator set for faster blocks or lower overhead.
  2. +
+
info

This is only applicable to Opt In chains (chains with Top N = 0).

+
    +
  1. Capping the fraction of power any single validator can have: The consumer chain can specify a maximum fraction +of the total voting power that any single validator in its validator set should have. +This is a security measure with the intention of making it harder for a single large validator to take over a consumer chain. This mitigates the risk of an Opt In chain with only a few validators being dominated by a validator with a large amount of stake opting in. +For example, setting this fraction to e.g. 33% would mean that no single validator can have more than 33% of the total voting power, +and thus there is no single validator who would stop the chain by going offline.
  2. +
+
info

This is a soft cap, and the actual power of a validator can exceed this fraction if the validator set is small (e.g. there are only 3 validators and the cap is 20%).

+
info

Rewards are distributed proportionally to validators with respect to their capped voting power on the consumer, +not their total voting power on the provider.

+
    +
  1. Allowlist and denylist: The consumer chain can specify a list of validators that are allowed or disallowed from participating in the validator set. If an allowlist is set, all validators not on the allowlist cannot validate the consumer chain. If a validator is on both lists, the denylist takes precedence, that is, they cannot validate the consumer chain. If neither list is set, all validators are able to validate the consumer chain.
  2. +
+
warning

Note that if denylisting is used in a Top N consumer chain, then the chain might not be secured by N% of the total provider's +power. For example, consider that the top validator V on the provider chain has 10% of the voting power, and we have a Top 50% consumer chain, +then if V is denylisted, the consumer chain would only be secured by at least 40% of the provider's power.

+

All these mechanisms are set by the consumer chain in the ConsumerAdditionProposal. They operate solely on the provider chain, meaning the consumer chain simply receives the validator set after these rules have been applied and does not have any knowledge about whether they are applied.

+

Each of these mechanisms is set during the consumer addition proposal (see Onboarding), and is currently immutable after the chain has been added.

+

The values can be seen by querying the list of consumer chains:

+
interchain-security-pd query provider list-consumer-chains
+

Guidelines for setting power shaping parameters

+

When setting power shaping parameters, please consider the following guidelines:

+
    +
  • Do not cap the validator set size too low: Notice that this number is the *maximum number of validators that will ever validate the consumer chain. If this number is too low, the chain will be very limited in the +amount of stake that secures it. The validator set size cap should only be used if there are strong reasons to prefer fewer validators. Consider that setting the cap will mean that +even if the whole validator set of the provider wants to validate on the chain, some validators will simply not be able to.
  • +
  • Capping the fraction of power any single validator can have is a decent security measure, but it's good to be aware of the interactions with the size of the validator set. +For example, if there are only 3 validators, and the cap is 20%, this will not be possible (since even splitting the power fairly would mean that each validator has 33% of the power, so is above the cap). +However, the cap can be a good measure to prevent a single large validator from essentially taking over the chain. +In general, values under 33% make sense (since a validator that has 33% of the chains power would halt the chain if they go offline). +Notice that the smaller this value is, the more the original voting power gets distorted, which could discourage large validators from deciding to opt in to the chain.
  • +
  • If the allowlist is empty, all validators can validate the chain. If it is non empty, then only validators on the allowlist can validate the chain. +Thus, an allowlist containing too few validators is a security risk. In particular, consider that if the validators on the allowlist lose a lot of stake or stop being validators, +an allowlist that is too short can very quickly become outdated and leave too few validators, or validators with too little stake, to secure the chain in a decentralized way.
  • +
  • If the denylist is too full, this can likewise be problematic. If too many large validators are denylisted, the chain might not be secured by a large enough fraction of the provider's power, in particular when +the power distribution on the provider shifts and the denylisted validators gain more power.
  • +
+

In general, when setting these parameters, consider that the voting power distribution in the future might be very different from the one right now, +and that the chain should be secure even if the power distribution changes significantly.

+ + \ No newline at end of file diff --git a/v4.2.0/features/power-shaping.html.html b/v4.2.0/features/power-shaping.html.html new file mode 100644 index 0000000000..92d59bfa0f --- /dev/null +++ b/v4.2.0/features/power-shaping.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/features/proposals.html b/v4.2.0/features/proposals.html new file mode 100644 index 0000000000..7e1fcd1620 --- /dev/null +++ b/v4.2.0/features/proposals.html @@ -0,0 +1,46 @@ + + + + + +ICS Provider Proposals | Interchain Security + + + + +
Version: v4.2.0

ICS Provider Proposals

+

Interchain security module introduces 3 new proposal types to the provider.

+

The proposals are used to propose upcoming interchain security events through governance.

+

ConsumerAdditionProposal

+
info

If you are preparing a ConsumerAdditionProposal you can find more information in the consumer onboarding checklist.

+

Proposal type used to suggest adding a new consumer chain.

+

When proposals of this type are passed and the spawn_time specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain.

+

Minimal example:

+
{
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
"title": "Add consumer chain",
"description": ".md description of your chain and all other relevant information",
"chain_id": "newchain-1",
"initial_height" : {
"revision_height": 0,
"revision_number": 1,
},
// Unbonding period for the consumer chain.
// It should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
"transfer_timeout_period": 1800000000000,
"consumer_redistribution_fraction": "0.75",
"blocks_per_distribution_transmission": 1000,
"historical_entries": 10000,
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",
"distribution_transmission_channel": "channel-123",
"top_N": 95,
"validators_power_cap": 0,
"validator_set_cap": 0,
"allowlist": [],
"denylist": []
}
+

More examples can be found in the interchain security testnet repository here and here.

+

ConsumerRemovalProposal

+

Proposal type used to suggest removing an existing consumer chain.

+

When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain. +After the consumer chain removal, the chain in question will no longer be secured by the provider's validator set.

+
info

The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain. +Additional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set. +More information will be made available in the Consumer Offboarding Checklist.

+

Minimal example:

+
{
// the time on the provider chain at which all validators are responsible to stop their consumer chain validator node
"stop_time": "2023-03-07T12:40:00.000000Z",
// the chain-id of the consumer chain to be stopped
"chain_id": "consumerchain-1",
"title": "This was a great chain",
"description": "Here is a .md formatted string specifying removal details"
}
+
warning

Before the introduction of Partial Set Security, consumer chains typically included a "soft opt-out mechanism" +which allows the bottom N% of the provider's validators to not validate the consumer chain, without being jailed for downtime on the provider. +After the introduction of Partial Set Security, the use of the soft opt-out mechanism is discouraged, and consumer chains are +encouraged to use the topN parameter to not force validators with little stake to validate the chain.

+

ChangeRewardDenomProposal

+

Proposal type used to mutate the set of denoms accepted by the provider as rewards.

+
tip

A ChangeRewardDenomProposal will only be accepted on the provider chain if at least one of the denomsToAdd or denomsToRemove fields is populated with at least one denom. Also, a denom cannot be repeated in both sets.

+

Minimal example:

+
{
"title": "Add uatom as a reward denom",
"description": "Here is more information about the proposal",
"denomsToAdd": ["uatom"],
"denomsToRemove": []
}
+
tip

Besides native provider denoms (e.g., uatom for the Cosmos Hub), please use the ibc/* denom trace format. +For example, for untrn transferred over the path transfer/channel-569, the denom trace +can be queried using the following command:

> gaiad query ibc-transfer denom-hash transfer/channel-569/untrn
hash: 0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5

Then use the resulting hash in the ChangeRewardDenomProposal, e.g.,

{
"title": "Add untrn as a reward denom",
"description": "Here is more information about the proposal",
"denomsToAdd": ["ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5"],
"denomsToRemove": []
}
+ + \ No newline at end of file diff --git a/v4.2.0/features/proposals.html.html b/v4.2.0/features/proposals.html.html new file mode 100644 index 0000000000..a2fbf6d24b --- /dev/null +++ b/v4.2.0/features/proposals.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/features/reward-distribution.html b/v4.2.0/features/reward-distribution.html new file mode 100644 index 0000000000..eb0c7e2304 --- /dev/null +++ b/v4.2.0/features/reward-distribution.html @@ -0,0 +1,33 @@ + + + + + +Reward Distribution | Interchain Security + + + + +
Version: v4.2.0

Reward Distribution

+

Sending and distributing rewards from consumer chains to the provider chain is handled by the Reward Distribution sub-protocol.

+

Consumer chains have the option of sharing (a portion of) their block rewards (inflation tokens and fees) with the provider chain validators and delegators. +In replicated security, block rewards are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel. +This channel is created during consumer chain initialization, unless it is provided via the ConsumerAdditionProposal when adding a new consumer chain. +For more details, see the reward distribution parameters.

+
tip

Providing an IBC transfer channel (see DistributionTransmissionChannel) enables a consumer chain to re-use one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ibc denom that may already be in use. +This is especially important for standalone chains transitioning to become consumer chains. +For more details, see the changeover procedure.

+

Reward distribution on the provider is handled by the distribution module.

+

Whitelisting Reward Denoms

+

The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the ConsumerRewardsPool. +To avoid spam, the provider must whitelist denoms before accepting them as ICS rewards. +Only whitelisted denoms are transferred from the ConsumerRewardsPool to the FeePoolAddress, to be distributed to delegators and validators. +The whitelisted denoms can be adjusted through governance by sending a ChangeRewardDenomProposal.

+

To query the list of whitelisted reward denoms on the Cosmos Hub, use the following command:

+
> gaiad q provider registered-consumer-reward-denoms
denoms:
- ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5
- ibc/6B8A3F5C2AD51CD6171FA41A7E8C35AD594AB69226438DB94450436EA57B3A89
- uatom
+
tip

Use the following command to get a human readable denom from the ibc/* denom trace format:

>  gaiad query ibc-transfer denom-trace ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5
denom_trace:
base_denom: untrn
path: transfer/channel-569
+ + \ No newline at end of file diff --git a/v4.2.0/features/reward-distribution.html.html b/v4.2.0/features/reward-distribution.html.html new file mode 100644 index 0000000000..86dc7ba6ab --- /dev/null +++ b/v4.2.0/features/reward-distribution.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/features/slashing.html b/v4.2.0/features/slashing.html new file mode 100644 index 0000000000..6a5ab8f0b2 --- /dev/null +++ b/v4.2.0/features/slashing.html @@ -0,0 +1,48 @@ + + + + + +Consumer Initiated Slashing | Interchain Security + + + + +
Version: v4.2.0

Consumer Initiated Slashing

+

A consumer chain is essentially a regular Cosmos-SDK based chain that uses the Interchain Security module to achieve economic security by stake deposited on the provider chain, instead of its own chain. +In essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake).

+

To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized. +Any infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains.

+

In the current implementation there are two important changes brought by the Interchain Security module.

+

Downtime Infractions

+

Downtime infractions are reported by consumer chains and are acted upon on the provider as soon as the provider receives the infraction evidence.

+

Instead of slashing, the provider will only jail offending validator for the duration of time established by the chain parameters.

+
info

Slash throttling (sometimes called jail throttling) mechanism ensures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider.

+

Note that validators are only jailed for downtime on consumer chains that they opted-in to validate on, +or in the case of Top N chains, where they are automatically opted in by being in the Top N% of the validator set on the provider.

+

Equivocation Infractions

+

Equivocation infractions are reported by external agents (e.g., relayers) that can submit to the provider evidence of light client or double signing attacks observed on a consumer chain. +The evidence is submitted by sending MsgSubmitConsumerMisbehaviour or MsgSubmitConsumerDoubleVoting transactions to the provider. +When valid evidence is received, the malicious validators are slashed, jailed, and tombstoned on the provider. +This is enabled through the cryptographic verification of equivocation feature. +For more details, see ADR-005 and ADR-013.

+

Report equivocation infractions through CLI

+

The ICS provider module offers two commands for submitting evidence of misbehavior originating from a consumer chain. +Below are two examples illustrating the process on Cosmos Hub.

+

Use the following command to submit evidence of double signing attacks:

+
gaiad tx provider submit-consumer-double-voting [path/to/evidence.json] [path/to/infraction_header.json] --from node0 --home ../node0 --chain-id $CID 
+
Example of evidence.json
{
"vote_a": {
"type": 1,
"height": 25,
"round": 0,
"block_id": {
"hash": "tBBWTqjECl31S/clZGoxLdDqs93kTvy3qhpPqET/laY=",
"part_set_header": {
"total": 1,
"hash": "ai2qCLgVZAFph4FJ4Cqw5QW1GZKR4zjOv0bI/Um5AIc="
}
},
"timestamp": "2023-11-20T12:57:54.565207Z",
"validator_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",
"signature": "y9yILm9hmv45BZwAaaq9mS1FpH7QeAIJ5Jkcc3U2/k5uks9cuqr4NTIwaIrqMSMKwxVyqiR56xmCT59a6AngAA=="
},
"vote_b": {
"type": 1,
"height": 25,
"round": 0,
"block_id": {
"hash": "3P06pszgPatuIdLTP5fDWiase4SYHIq9YXGSbRk9/50=",
"part_set_header": {
"total": 1,
"hash": "S+SbOMxFRzfeNNpX9/jyFMz94VwBKk7Dpx6ZyvSYyNU="
}
},
"timestamp": "2023-11-20T12:57:54.599273Z",
"validator_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",
"validator_index": 0,
"signature": "DGFcn4Um1t2kXW60+JhMk5cj7ZFdE5goKVOGiZkLwnNv43+6aGmOWjoq0SHYVzM4MwSwOwbhgZNbkWX+EHGUBw=="
},
"total_voting_power": 300,
"validator_power": 100,
"timestamp": "2023-11-20T12:57:51.267308Z"
}
+
Example of infraction_header.json
{
"signed_header": {
"header": {
"version": {
"block": 11,
"app": 2
},
"chain_id": "consumer",
"height": 22,
"time": "2023-11-20T12:57:40.479686Z",
"last_block_id": {
"hash": "L63hyLJ+y9+fpb7WYKdmmBhPHwbfEGQEuKmvGzyBPiY=",
"part_set_header": {
"total": 18,
"hash": "euzRQjN7MjGtM6skXM4B8wOgAldWGfZSJRA9JRlO42s="
}
},
"last_commit_hash": "qdDJwVziW3pPqmf8QDGZG+5HVd3OF7fCVh2Z8KQqNVU=",
"data_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"validators_hash": "pVc+gSYkGesaP3OkK4ig3DBi4o9/GCdXGtO/PQ6i/Ik=",
"next_validators_hash": "pVc+gSYkGesaP3OkK4ig3DBi4o9/GCdXGtO/PQ6i/Ik=",
"consensus_hash": "BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8=",
"app_hash": "Yu3HX62w7orbbY/pm2QEK7yIwR+AlNdjSSqiK1kmuJM=",
"last_results_hash": "Yu3HX62w7orbbY/pm2QEK7yIwR+AlNdjSSqiK1kmuJM=",
"evidence_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"proposer_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA="
},
"commit": {
"height": 22,
"round": 1,
"block_id": {
"hash": "PKrS32IEZoFY2q2S3iQ68HQL751ieBhf5Eu/Y5Z/QPg=",
"part_set_header": {
"total": 1,
"hash": "8UuA7Oqw5AH/KOacpmHVSMOIDe4l2eC8VmdH2mzcpiM="
}
},
"signatures": [
{
"block_id_flag": 2,
"validator_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",
"timestamp": "2023-11-20T12:57:44.076538Z",
"signature": "bSOH4+Vg2I37zeJphOguGOD0GK3JzM1ghSgJd0UlW/DHn1u9Hvv4EekHuCu6qwRLZcuS/ZxNlmr9qYNfxX3bDA=="
},
{
"block_id_flag": 2,
"validator_address": "i/A830FM7cfmA8yTn9n3xBg5XpU=",
"timestamp": "2020-01-02T00:07:00Z",
"signature": "7bXSDtlOwGK/gLEsFpTWOzm2TFoaARrWQUpbgWEwKtLlUs7iE06TOvJ3yPPfTfqqN/qYnvxxgjl0M0EhUWu5Bg=="
},
{
"block_id_flag": 2,
"validator_address": "lrQDkJ2fk7UAgNzRZfcwMKSYa2E=",
"timestamp": "2023-11-20T12:57:44.076519Z",
"signature": "Pb6G4bCg4wafmV89WNnzXxbSCknZUHnSQfSCE5QMFxPtSUIN4A7SK5m7yltqMJF5zkyenlFiEI4J3OZ4KCjCAw=="
},
{
"block_id_flag": 2,
"validator_address": "+R94nXSeM1Z49e/CXpyHT3M+h3k=",
"timestamp": "2023-11-20T12:57:44.057451Z",
"signature": "j3EasIHNYA6MxW/PiWyruzHsjVsBV9t11W6Qx800WMm/+P+CkfR+UZAp7MPTvKZEZFuh3GUsBtyfb/vA+jJWCw=="
}
]
}
},
"validator_set": {
"validators": [
{
"address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",
"pub_key": {
"ed25519": "dtn+SfD+4QLo0+t0hAoP6Q2sGjh0XEI3LWVG+doh3u0="
},
"voting_power": 100,
"proposer_priority": -200
},
{
"address": "lrQDkJ2fk7UAgNzRZfcwMKSYa2E=",
"pub_key": {
"ed25519": "UgN2JsjPy2WLh7dzJRBkUQtdgNoT4/uGj7kbIVqqHT8="
},
"voting_power": 100,
"proposer_priority": 100
},
{
"address": "+R94nXSeM1Z49e/CXpyHT3M+h3k=",
"pub_key": {
"ed25519": "5svW8261x+cZosp2xIhqzgt2tyuawrSDyHlpbgS3BC4="
},
"voting_power": 100,
"proposer_priority": 100
},
{
"address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",
"pub_key": {
"ed25519": "dtn+SfD+4QLo0+t0hAoP6Q2sGjh0XEI3LWVG+doh3u0="
},
"voting_power": 100,
"proposer_priority": -200
}
],
"proposer": {
"address": "VUz+QceJ8Nu7GbJuVItwsfVjybA=",
"pub_key": {
"ed25519": "0s8KDTgEcwmOBrHWvV7mtBlItJ3upgM1FJsciwREdy4="
},
"voting_power": 1,
"proposer_priority": -3
}
},
"trusted_height": {
"revision_height": 18
},
"trusted_validators": {
"validators": [
{
"address": "VUz+QceJ8Nu7GbJuVItwsfVjybA=",
"pub_key": {
"ed25519": "0s8KDTgEcwmOBrHWvV7mtBlItJ3upgM1FJsciwREdy4="
},
"voting_power": 1,
"proposer_priority": -3
},
{
"address": "i/A830FM7cfmA8yTn9n3xBg5XpU=",
"pub_key": {
"ed25519": "FCmIw7hSuiAoWk/2f4LuGQ+3zx5101xiqU8DoC5wGkg="
},
"voting_power": 1,
"proposer_priority": 1
},
{
"address": "2DrZF0roNnnvEy4NS2aY811ncKg=",
"pub_key": {
"ed25519": "MI9c6sphsWlx0RAHCYOjMRXMFkTUaEYwOiOKG/0tsMs="
},
"voting_power": 1,
"proposer_priority": 1
},
{
"address": "73aN0uOc5b/Zfq2Xcjl0kH2r+tw=",
"pub_key": {
"ed25519": "gWNcDup4mdnsuqET4QeFRzVb+FnSP4Vz3iNMj5wvWXk="
},
"voting_power": 1,
"proposer_priority": 1
}
],
"proposer": {
"address": "VUz+QceJ8Nu7GbJuVItwsfVjybA=",
"pub_key": {
"ed25519": "0s8KDTgEcwmOBrHWvV7mtBlItJ3upgM1FJsciwREdy4="
},
"voting_power": 1,
"proposer_priority": -3
}
}
}
+

Use the following command to submit evidence of light client attacks:

+
gaiad tx provider submit-consumer-misbehaviour [path/to/misbehaviour.json] --from node0 --home ../node0 --chain-id $CID
+
Example of misbehaviour.json
{
"client_id": "07-tendermint-0",
"header_1": {
"signed_header": {
"header": {
"version": {
"block": "11",
"app": "2"
},
"chain_id": "testchain2",
"height": "19",
"time": "2020-01-02T00:08:10Z",
"last_block_id": {
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"part_set_header": {
"total": 10000,
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
}
},
"last_commit_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",
"data_hash": "bW4ouLmLUycELqUKV91G5syFHHLlKL3qpu/e7v5moLg=",
"validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",
"next_validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",
"consensus_hash": "5eVmxB7Vfj/4zBDxhBeHiLj6pgKwfPH0JSF72BefHyQ=",
"app_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",
"last_results_hash": "CS4FhjAkftYAmGOhLu4RfSbNnQi1rcqrN/KrNdtHWjc=",
"evidence_hash": "c4ZdsI9J1YQokF04mrTKS5bkWjIGx6adQ6Xcc3LmBxQ=",
"proposer_address": "CbKqPquy50bcrY7JRdW7zXybSuA="
},
"commit": {
"height": "19",
"round": 1,
"block_id": {
"hash": "W2xVqzPw03ZQ1kAMpcpht9WohwMzsGnyKKNjPYKDF6U=",
"part_set_header": {
"total": 3,
"hash": "hwgKOc/jNqZj6lwNm97vSTq9wYt8Pj4MjmYTVMGDFDI="
}
},
"signatures": [
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"timestamp": "2020-01-02T00:08:10Z",
"signature": "PGTquCtnTNFFY5HfEFz9f9pA7PYqjtQfBwHq6cxF/Ux8OI6nVqyadD9a84Xm7fSm6mqdW+T6YVfqIKmIoRjJDQ=="
},
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",
"timestamp": "2020-01-02T00:08:10Z",
"signature": "0e39yoBorwORAH/K9qJ7D1N1Yr7CutMiQJ+oiIK39eMhuoK3UWzQyMGRLzDOIDupf8yD99mvGVVAlNIODlV3Dg=="
},
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",
"timestamp": "2020-01-02T00:08:10Z",
"signature": "lhc2tkwydag9D1iLQhdDCE8GgrHP94M1LbHFYMoL9tExaEq6RiFW/k71TQH5x96XQ9XYOznMIHKC2BDh4GlnAQ=="
},
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",
"timestamp": "2020-01-02T00:08:10Z",
"signature": "8xeSBf0nSFs/X/rQ9CZLzwkJJhQBLA2jKdPGP3MlULxm992XxrOsIYq47u1daxvSsn6ql5OVYjzBNU0qbPpvCA=="
}
]
}
},
"validator_set": {
"validators": [
{
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
{
"address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",
"pub_key": {
"ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",
"pub_key": {
"ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",
"pub_key": {
"ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="
},
"voting_power": "1",
"proposer_priority": "1"
}
],
"proposer": {
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
"total_voting_power": "0"
},
"trusted_height": {
"revision_number": "0",
"revision_height": "18"
},
"trusted_validators": {
"validators": [
{
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
{
"address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",
"pub_key": {
"ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",
"pub_key": {
"ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",
"pub_key": {
"ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="
},
"voting_power": "1",
"proposer_priority": "1"
}
],
"proposer": {
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
"total_voting_power": "0"
}
},
"header_2": {
"signed_header": {
"header": {
"version": {
"block": "11",
"app": "2"
},
"chain_id": "testchain2",
"height": "19",
"time": "2020-01-02T00:08:20Z",
"last_block_id": {
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"part_set_header": {
"total": 10000,
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
}
},
"last_commit_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",
"data_hash": "bW4ouLmLUycELqUKV91G5syFHHLlKL3qpu/e7v5moLg=",
"validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",
"next_validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",
"consensus_hash": "5eVmxB7Vfj/4zBDxhBeHiLj6pgKwfPH0JSF72BefHyQ=",
"app_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",
"last_results_hash": "CS4FhjAkftYAmGOhLu4RfSbNnQi1rcqrN/KrNdtHWjc=",
"evidence_hash": "c4ZdsI9J1YQokF04mrTKS5bkWjIGx6adQ6Xcc3LmBxQ=",
"proposer_address": "CbKqPquy50bcrY7JRdW7zXybSuA="
},
"commit": {
"height": "19",
"round": 1,
"block_id": {
"hash": "IZM8NKS+8FHB7CBmgB8Nz7BRVVXiiyqMQDvHFUvgzxo=",
"part_set_header": {
"total": 3,
"hash": "hwgKOc/jNqZj6lwNm97vSTq9wYt8Pj4MjmYTVMGDFDI="
}
},
"signatures": [
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"timestamp": "2020-01-02T00:08:20Z",
"signature": "pLIEZ4WSAtnMsgryujheHSq4+YG3RqTfMn2ZxgEymr0wyi+BNlQAKRtRfesm0vfYxvjzc/jhGqtUqHtSIaCwCQ=="
},
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",
"timestamp": "2020-01-02T00:08:20Z",
"signature": "XG7iTe/spWyTUkT7XDzfLMpYqrdyqizE4/X4wl/W+1eaQp0WsCHYnvPU3x9NAnYfZzaKdonZiDWs7wacbZTcDg=="
},
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",
"timestamp": "2020-01-02T00:08:20Z",
"signature": "TqegK7ORuICSy++wVdPHt8fL2WfPlYsMPv1XW79wUdcjnQkezOM50OSqYaP4ua5frIZsn+sWteDrlqFTdkl3BA=="
},
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",
"timestamp": "2020-01-02T00:08:20Z",
"signature": "dhvp3XlIaCxx5MFDs0TCkAPHSm0PS2EtJzYAx2c/7MWdLwUJFZrAUTeimQE2c9i9ro91cjZn/vI0/oFRXab6Aw=="
}
]
}
},
"validator_set": {
"validators": [
{
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
{
"address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",
"pub_key": {
"ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",
"pub_key": {
"ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",
"pub_key": {
"ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="
},
"voting_power": "1",
"proposer_priority": "1"
}
],
"proposer": {
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
"total_voting_power": "0"
},
"trusted_height": {
"revision_number": "0",
"revision_height": "18"
},
"trusted_validators": {
"validators": [
{
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
{
"address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",
"pub_key": {
"ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",
"pub_key": {
"ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",
"pub_key": {
"ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="
},
"voting_power": "1",
"proposer_priority": "1"
}
],
"proposer": {
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
"total_voting_power": "0"
}
}
}
+

Report equivocation infractions with Hermes

+

Ensure you have a well-configured Hermes v1.7.3+ relayer effectively relaying packets between a consumer chain and a provider chain. +The following command demonstrates how to run a Hermes instance in evidence mode to detect misbehaviors on a consumer chain and automatically submit the evidence to the provider chain.

+
hermes evidence --chain <CONSUMER-CHAIN-ID>
+
tip

hermes evidence takes a --check-past-blocks option giving the possibility to look for older evidence (default is 100).

+ + \ No newline at end of file diff --git a/v4.2.0/features/slashing.html.html b/v4.2.0/features/slashing.html.html new file mode 100644 index 0000000000..9232058e3a --- /dev/null +++ b/v4.2.0/features/slashing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/introduction/overview.html b/v4.2.0/introduction/overview.html new file mode 100644 index 0000000000..2402d45c49 --- /dev/null +++ b/v4.2.0/introduction/overview.html @@ -0,0 +1,33 @@ + + + + + +Overview | Interchain Security + + + + +
Version: v4.2.0

Overview

+
info

Interchain Security is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.


Interchain Security allows anyone to launch a "consumer" blockchain using a subset, or even the entire, validator set from the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit security and decentralization from the provider.

+

Why Interchain Security?

+
    +
  • The right amount of security for each application. Consumer chains can choose to inherit the whole validator set from the provider, or they can launch as an opt in chain where only a subset of the provider validators validate the consumer chain. This allows for a wide range of security tradeoffs.
  • +
  • Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum.
  • +
  • Projects keep majority of gas fees. Depending on configuration, these fees either go to the project’s community DAO, or can be used in the protocol in other ways.
  • +
  • No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. Validators from the provider chain validate on the consumer chain with their stake on the provider chain, earning additional rewards. For the consumer chain, this comes with the benefit of exposing their chain to the wider audience of the provider chain.
  • +
  • Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set.
  • +
+

Core protocol

+
info

Protocol specification is available as ICS-028 in the IBC repository.

+

Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer.

+

To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider.

+

Downtime Slashing

+

If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period.

+

Tokenomics and Rewards

+

Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance.

+ + \ No newline at end of file diff --git a/v4.2.0/introduction/overview.html.html b/v4.2.0/introduction/overview.html.html new file mode 100644 index 0000000000..afa42f912c --- /dev/null +++ b/v4.2.0/introduction/overview.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/introduction/params.html b/v4.2.0/introduction/params.html new file mode 100644 index 0000000000..207bc5618c --- /dev/null +++ b/v4.2.0/introduction/params.html @@ -0,0 +1,100 @@ + + + + + +Interchain Security Parameters | Interchain Security + + + + +
Version: v4.2.0

Interchain Security Parameters

+

The parameters necessary for Interchain Security (ICS) are defined in

+
    +
  • the Params structure in proto/interchain_security/ccv/provider/v1/provider.proto for the provider;
  • +
  • the Params structure in proto/interchain_security/ccv/consumer/v1/consumer.proto for the consumer.
  • +
+

Time-Based Parameters

+

ICS relies on the following time-based parameters.

+

ProviderUnbondingPeriod

+

ProviderUnbondingPeriod is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance.

+

ConsumerUnbondingPeriod

+

ConsumerUnbondingPeriod is the unbonding period on the consumer chain.

+
info

ConsumerUnbondingPeriod is set via the ConsumerAdditionProposal governance proposal to add a new consumer chain. +It is recommended that every consumer chain set and unbonding period shorter than ProviderUnbondingPeriod


Example:

ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day
+

Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer.

+

TrustingPeriodFraction

+

TrustingPeriodFraction is used to calculate the TrustingPeriod of created IBC clients on both provider and consumer chains.

+

Setting TrustingPeriodFraction to 0.5 would result in the following:

+
TrustingPeriodFraction = 0.5
ProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5
ConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5
+

Note that a light clients must be updated within the TrustingPeriod in order to avoid being frozen.

+

For more details, see the IBC specification of Tendermint clients.

+

CCVTimeoutPeriod

+

CCVTimeoutPeriod is the period used to compute the timeout timestamp when sending IBC packets.

+

For more details, see the IBC specification of Channel & Packet Semantics.

+
warning

If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed.

+

CCVTimeoutPeriod may have different values on the provider and consumer chains.

+
    +
  • CCVTimeoutPeriod on the provider must be larger than ConsumerUnbondingPeriod
  • +
  • CCVTimeoutPeriod on the consumer is initial set via the ConsumerAdditionProposal
  • +
+

InitTimeoutPeriod

+

InitTimeoutPeriod is the maximum allowed duration for CCV channel initialization to execute.

+

For any consumer chain, if the CCV channel is not established within InitTimeoutPeriod then the consumer chain will be removed and therefore will not be secured by the provider chain.

+

The countdown starts when the spawn_time specified in the ConsumerAdditionProposal is reached.

+

VscTimeoutPeriod

+

VscTimeoutPeriod is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live. +If the VscTimeoutPeriod is ever reached for a consumer chain that chain will be considered not live and removed from interchain security.

+
tip

VscTimeoutPeriod MUST be larger than the ConsumerUnbondingPeriod.

+

BlocksPerDistributionTransmission

+

BlocksPerDistributionTransmission is the number of blocks between rewards transfers from the consumer to the provider.

+

TransferPeriodTimeout

+

TransferPeriodTimeout is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider.

+

If this timeout expires, then the transfer is attempted again after BlocksPerDistributionTransmission blocks.

+
    +
  • TransferPeriodTimeout on the consumer is initial set via the ConsumerAdditionProposal gov proposal to add the consumer
  • +
  • TransferPeriodTimeout should be smaller than BlocksPerDistributionTransmission x avg_block_time
  • +
+

Reward Distribution Parameters

+
tip

The following chain parameters dictate consumer chain distribution amount and frequency. +They are set at consumer genesis and BlocksPerDistributionTransmission, ConsumerRedistributionFraction +TransferTimeoutPeriod must be provided in every ConsumerChainAddition proposal.

+

ConsumerRedistributionFraction

+

ConsumerRedistributionFraction is the fraction of tokens allocated to the consumer redistribution address during distribution events. The fraction is a string representing a decimal number. For example "0.75" would represent 75%.

+
tip

Example:

With ConsumerRedistributionFraction set to "0.75" the consumer chain would send 75% of its block rewards and accumulated fees to the consumer redistribution address, and the remaining 25% to the provider chain every BlocksPerDistributionTransmission blocks.

+

BlocksPerDistributionTransmission

+

BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.

+

TransferTimeoutPeriod

+

TransferTimeoutPeriod is the timeout period for consumer chain reward distribution IBC packets.

+

DistributionTransmissionChannel

+

DistributionTransmissionChannel is the provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.

+

ProviderFeePoolAddrStr

+

ProviderFeePoolAddrStr is the provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.

+

Slash Throttle Parameters

+

SlashMeterReplenishPeriod

+

SlashMeterReplenishPeriod exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed.

+

The meter is replenished to an amount equal to the slash meter allowance for that block, or SlashMeterReplenishFraction * CurrentTotalVotingPower.

+

SlashMeterReplenishFraction

+

SlashMeterReplenishFraction exists on the provider as the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs.

+

This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a sdk.Dec when used.

+

MaxThrottledPackets

+

MaxThrottledPackets exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value.

+

This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness.

+
info

MaxThrottledPackets was deprecated in ICS versions >= v3.2.0 due to the implementation of ADR-008.

+

RetryDelayPeriod

+

RetryDelayPeriod exists on the consumer for ICS versions >= v3.2.0 (introduced by the implementation of ADR-008) and is the period at which the consumer retries to send a SlashPacket that was rejected by the provider.

+

Epoch Parameters

+

BlocksPerEpoch

+

BlocksPerEpoch exists on the provider for ICS versions >= 3.3.0 (introduced by the implementation of ADR-014) +and corresponds to the number of blocks that constitute an epoch. This param is set to 600 by default. Assuming we need 6 seconds to +commit a block, the duration of an epoch corresponds to 1 hour. This means that a VSCPacket would be sent to a consumer +chain once at the end of every epoch, so once every 600 blocks. This parameter can be adjusted via a governance proposal, +however careful consideration is needed so that BlocksPerEpoch is not too large. A large BlocksPerEpoch could lead to a delay +of VSCPackets and hence potentially lead to unbonding pausing. +For setting BlocksPerEpoch, we also need to consider potential slow chain upgrades that could delay the sending of a +VSCPacket, as well as potential increases in the time it takes to commit a block (e.g., from 6 seconds to 30 seconds).

+ + \ No newline at end of file diff --git a/v4.2.0/introduction/params.html.html b/v4.2.0/introduction/params.html.html new file mode 100644 index 0000000000..5057e6ca97 --- /dev/null +++ b/v4.2.0/introduction/params.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/introduction/technical-specification.html b/v4.2.0/introduction/technical-specification.html new file mode 100644 index 0000000000..03f1a2e06e --- /dev/null +++ b/v4.2.0/introduction/technical-specification.html @@ -0,0 +1,17 @@ + + + + + +Technical Specification | Interchain Security + + + + +
+ + \ No newline at end of file diff --git a/v4.2.0/introduction/technical-specification.html.html b/v4.2.0/introduction/technical-specification.html.html new file mode 100644 index 0000000000..2cb87d9e40 --- /dev/null +++ b/v4.2.0/introduction/technical-specification.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/introduction/terminology.html b/v4.2.0/introduction/terminology.html new file mode 100644 index 0000000000..840d4416fb --- /dev/null +++ b/v4.2.0/introduction/terminology.html @@ -0,0 +1,35 @@ + + + + + +Terminology | Interchain Security + + + + +
Version: v4.2.0

Terminology

+

You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.

+

Shared Security

+

Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share its proof-of-stake security with another blockchain or off-chain process.

+

Interchain Security

+

Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC.

+

Replicated Security

+

A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC.

+

Partial Set Security

+

A major iteration of Interchain Security, also known as "Interchain Security V2". Partial Set Security allows a provider chain to share only a subset of its validator set with a consumer chain. This subset can be determined by the top N% validators by voting power, or by validators opting in to validate the consumer chain. Partial Set Security allows for more flexible security tradeoffs than Replicated Security.

+

Mesh security

+

A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see Replicated vs. Mesh Security on the Informal Blog.

+

Consumer Chain

+

Chain that is secured by the validator set of the provider, instead of its own. +Replicated security allows the provider chain validator set to validate blocks on the consumer chain.

+

Standalone Chain

+

Chain that is secured by its own validator set. This chain does not participate in replicated security.

+

Standalone chains may sometimes be called "sovereign" - the terms are synonymous.

+

Changeover Procedure

+

Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.

+ + \ No newline at end of file diff --git a/v4.2.0/introduction/terminology.html.html b/v4.2.0/introduction/terminology.html.html new file mode 100644 index 0000000000..58866181cb --- /dev/null +++ b/v4.2.0/introduction/terminology.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/validators/changeover-procedure.html b/v4.2.0/validators/changeover-procedure.html new file mode 100644 index 0000000000..dbce473557 --- /dev/null +++ b/v4.2.0/validators/changeover-procedure.html @@ -0,0 +1,62 @@ + + + + + +Validator Instructions for Changeover Procedure | Interchain Security + + + + +
Version: v4.2.0

Validator Instructions for Changeover Procedure

+

More details available in Changeover Procedure documentation.

+

A major difference between launching a new consumer chain vs. onboarding a standalone chain to ICS is that there is no consumer genesis available for the standalone chain. Since a standalone chain already exists, its state must be preserved once it transitions to being a consumer chain.

+

Timeline

+

Upgrading standalone chains can be best visualised using a timeline, such as the one available Excalidraw graphic by Stride.

+

There is some flexibility with regards to how the changeover procedure is executed, so please make sure to follow the guides provided by the team doing the changeover.

+

Standalone to consumer transition timeline

+

1. ConsumerAdditionProposal on provider chain

+

This step will add the standalone chain to the list of consumer chains secured by the provider. +This step dictates the spawn_time. After spawn_time the CCV state (initial validator set of the provider) will be available to the consumer.

+

To obtain it from the provider use:

+
gaiad q provider consumer-genesis stride-1 -o json > ccv-state.json
jq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' genesis.json ccv-state.json > ccv.json
+

Transformation of the exported consumer genesis state to the target version of the consumer might be needed in case the provider and consumer formats are incompatible. +Refer to the compatibility notes here to check if data transformation is needed for your case. +Instructions on how to transform the exported CCV genesis state (ccv-state.json in the example above) to the required target version can be found here

+

2. SoftwareUpgradeProposal on the standalone/consumer chain

+

This upgrade proposal will introduce ICS to the standalone chain, making it a consumer.

+

3. Assigning a consumer key

+

After spawn_time, make sure to assign a consumer key if you intend to use one.

+

Instructions are available here

+

4. Perform the software upgrade on standalone chain

+

Please use instructions provided by the standalone chain team and make sure to reach out if you are facing issues. +The upgrade preparation depends on your setup, so please make sure you prepare ahead of time.

+
danger

The ccv.json from step 1. must be made available on the machine running the standalone/consumer chain at standalone chain upgrade_height. This file contains the initial validator set and parameters required for normal ICS operation.

Usually, the file is placed in $NODE_HOME/config but this is not a strict requirement. The exact details are available in the upgrade code of the standalone/consumer chain.

+

Performing this upgrade will transition the standalone chain to be a consumer chain.

+

After 3 blocks, the standalone chain will stop using the "old" validator set and begin using the provider validator set.

+

FAQ

+

Can I reuse the same validator key for the consumer chain that I am already using on the standalone chain? Will I need to perform a AssignConsumerKey tx with this key before spawn time?

+

Validators must either assign a key or use the same key as on the provider.

+

If you are validating both the standalone and the provider, you can use your current standalone key with some caveats:

+
    +
  • you must submit an AssignConsumerKey tx with your current standalone validator key
  • +
  • it is best to submit AssignConsumerKey tx before spawn_time
  • +
  • if you do not submit the Tx, it is assumed that you will be re-using your provider key to validate the standalone/consumer chain
  • +
+

Can I continue using the same node that was validating the standalone chain?

+

Yes.

+

Please assign your consensus key as stated above.

+

Can I set up a new node to validate the standalone/consumer chain after it transitions to replicated security?

+

Yes.

+

If you are planning to do this please make sure that the node is synced with standalone network and to submit AssignConsumerKey tx before spawn_time.

+

What happens to the standalone validator set after it transitions to replicated security?

+

The standalone chain validators will stop being validators after the first 3 blocks are created while using replicated security. The standalone validators will become governors and still can receive delegations if the consumer chain is using the consumer-democracy module.

+

Governors DO NOT VALIDATE BLOCKS.

+

Instead, they can participate in the governance process and take on other chain-specific roles.

+

Credits

+

Thank you Stride team for providing detailed instructions about the changeover procedure.

+ + \ No newline at end of file diff --git a/v4.2.0/validators/changeover-procedure.html.html b/v4.2.0/validators/changeover-procedure.html.html new file mode 100644 index 0000000000..a3ab70d29b --- /dev/null +++ b/v4.2.0/validators/changeover-procedure.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/validators/joining-neutron.html b/v4.2.0/validators/joining-neutron.html new file mode 100644 index 0000000000..d19c010ca9 --- /dev/null +++ b/v4.2.0/validators/joining-neutron.html @@ -0,0 +1,23 @@ + + + + + +Joining Neutron | Interchain Security + + + + +
Version: v4.2.0

Joining Neutron

+

Neutron is the first consumer chain to implement ICS.

+

You can find instructions on joining the mainnet here.

+

To join Neutron chain on the interchain security testnet check here

+

Resources

+
+ + \ No newline at end of file diff --git a/v4.2.0/validators/joining-neutron.html.html b/v4.2.0/validators/joining-neutron.html.html new file mode 100644 index 0000000000..0e2bff8056 --- /dev/null +++ b/v4.2.0/validators/joining-neutron.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/validators/joining-stride.html b/v4.2.0/validators/joining-stride.html new file mode 100644 index 0000000000..8b17548ccb --- /dev/null +++ b/v4.2.0/validators/joining-stride.html @@ -0,0 +1,28 @@ + + + + + +Joining Stride | Interchain Security + + + + +
Version: v4.2.0

Joining Stride

+

Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.

+

stride-1 network (mainnet) will perform a software upgrade and at height 4616678 that will transition the network to using the Cosmos Hub's (cosmoshub-4) validator set.

+

You can find instructions about the Stride consumer chain launch and joining the mainnet here.

+

This Excalidraw graphic explains the timeline of Stride's changeover procedure.

+

Note

+

Stride re-uses an existing transfer channel to send consumer rewards to the provider chain, in order to preserve existing transfer IBC denom between stride-1 and cosmoshub-4.

+

Resources

+
+ + \ No newline at end of file diff --git a/v4.2.0/validators/joining-stride.html.html b/v4.2.0/validators/joining-stride.html.html new file mode 100644 index 0000000000..aa73d97827 --- /dev/null +++ b/v4.2.0/validators/joining-stride.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/validators/joining-testnet.html b/v4.2.0/validators/joining-testnet.html new file mode 100644 index 0000000000..19713b6a7f --- /dev/null +++ b/v4.2.0/validators/joining-testnet.html @@ -0,0 +1,63 @@ + + + + + +Joining Interchain Security testnet | Interchain Security + + + + +
Version: v4.2.0

Joining Interchain Security testnet

Introduction

+

This short guide will teach you how to join the Interchain Security testnet.

+

The experience gained in the testnet will prepare you for validating interchain secured chains.

+
tip

Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set.

For general information about running cosmos-sdk based chains check out the validator basics and Running a Node section of Cosmos SDK docs

+

Joining the provider chain

+
info

At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain.

+

A comprehensive guide is available here.

+

Initialization

+

First, initialize your $NODE_HOME using the provider chain binary.

+
NODE_MONIKER=<your_node>
CHAIN_ID=provider
NODE_HOME=<path_to_your_home>

gaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME
+

Add your key to the keyring - more details available here.

+

In this example we will use the test keyring-backend. This option is not safe to use in production.

+
gaiad keys add <key_moniker> --keyring-backend test

# save the address as variable for later use
MY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)
+

Before issuing any transactions, use the provider testnet faucet to add funds to your address.

+
curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider

# example output:
{
"address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",
"amount": "10000000uatom",
"chain": "provider",
"hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",
"status": "success"
}
+

Then, use the account associated with the keyring to issue a create-validator transaction which will register your validator on chain.

+
gaiad tx staking create-validator \
--amount=1000000uatom \
--pubkey=$(gaiad tendermint show-validator) \
--moniker="choose a moniker" \
--chain-id=$CHAIN_ID" \
--commission-rate="0.10" \
--commission-max-rate="0.20" \
--commission-max-change-rate="0.01" \
--min-self-delegation="1000000" \
--gas="auto" \
--gas-prices="0.0025uatom" \
--from=<key_moniker>
+
tip

Check this guide to edit your validator.

+

After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use statesync to catch up to the rest of the network.

+

You can use this script to modify your config.toml with the required statesync parameters.

+
# create the statesync script
$: cd $NODE_HOME
$: touch statesync.sh
$ chmod 700 statesync.sh # make executable
+

Paste the following instructions into the statesync.sh:

+
#!/bin/bash

SNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"

LATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \
BLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \
TRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)

sed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\1true| ; \
s|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\1\"$SNAP_RPC,$SNAP_RPC\"| ; \
s|^(trust_height[[:space:]]+=[[:space:]]+).*$|\1$BLOCK_HEIGHT| ; \
s|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\1\"$TRUST_HASH\"|" $NODE_HOME/config/config.toml
+

Then, you can execute the script:

+
$: ./statesync.sh # setup config.toml for statesync
+

Finally, copy the provider genesis and start your node:

+
$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/interchain-security/provider/provider-genesis.json
$: wget $GENESIS_URL -O genesis.json
$: genesis.json $NODE_HOME/config/genesis.json
# start the service
$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"
+

Additional scripts to setup your nodes are available here and here. The scripts will configure your node and create the required services - the scripts only work in linux environments.

+

Joining consumer chains

+
tip

Once you reach the active set on the provider chain, you will be required to validate all available consumer chains.

We strongly recommend that you assign a separate key for each consumer chain. +Check out this guide to learn more about key assignment in interchain security.

+

To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries.

+
info

When running the provider chain and consumers on the same machine please update the PORT numbers for each of them and make sure they do not overlap (otherwise the binaries will not start).

Important ports to re-configure:

    +
  • --rpc.laddr
  • +
  • --p2p.laddr
  • +
  • --api.address
  • +
  • --grpc.address
  • +
  • --grpc-web.address
  • +
+

Re-using consensus key

+

To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the priv_validator_key.json into the home directory of your consumer chain (<consumer_home>/config/priv_validator_key.json).

+

When you start the chain, the consensus key will be the same on the provider and the consumer chain.

+

Assigning consensus keys

+

Whenever you initialize a new node, it will be configured with a consensus key you can use.

+
# machine running consumer chain
consumerd init <node_moniker> --home <home_path> --chain-id consumer-1

# use the output of this command to get the consumer chain consensus key
consumerd tendermint show-validator
# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}
+

Then, let the provider know which key you will be using for the consumer chain:

+
# machine running the provider chain
gaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b sync -y -o json
+

After this step, you are ready to copy the consumer genesis into your nodes's /config folder, start your consumer chain node and catch up to the network.

+ + \ No newline at end of file diff --git a/v4.2.0/validators/joining-testnet.html.html b/v4.2.0/validators/joining-testnet.html.html new file mode 100644 index 0000000000..cbe054cfe9 --- /dev/null +++ b/v4.2.0/validators/joining-testnet.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/validators/overview.html b/v4.2.0/validators/overview.html new file mode 100644 index 0000000000..84299b3c0f --- /dev/null +++ b/v4.2.0/validators/overview.html @@ -0,0 +1,70 @@ + + + + + +Overview | Interchain Security + + + + +
Version: v4.2.0

Overview

+
tip

We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.

+

At present, replicated security requires all validators of the provider chain (ie. Cosmos Hub) to run validator nodes for all governance-approved consumer chains.

+

Once a ConsumerAdditionProposal passes, validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains.

+

Provider chain and consumer chains represent standalone chains that only share the validator set ie. the same validator operators are tasked with running all chains.

+
info

To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 180 validators for Cosmos Hub).

+

Startup sequence overview

+

Consumer chains cannot start and be secured by the validator set of the provider unless a ConsumerAdditionProposal is passed. +Each proposal contains defines a spawn_time - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider.

+
tip

Validators are required to run consumer chain binaries only after spawn_time has passed.

+

Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains.

+

The image below illustrates the startup sequence +startup

+

1. Consumer Chain init + 2. Genesis generation

+

Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ConsumerAdditionProposal

+

3. Submit Proposal

+

Consumer chain team (or their advocates) submits a ConsumerAdditionProposal. +The most important parameters for validators are:

+
    +
  • spawn_time - the time after which the consumer chain must be started
  • +
  • genesis_hash - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and spawn_time is reached
  • +
  • binary_hash - hash of the consumer chain binary used to validate the software builds
  • +
+

4. CCV Genesis state generation

+

After reaching spawn_time the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain genesis.json. The CCV validator set consists of the validator set on the provider at spawn_time.

+

The state can be queried on the provider chain (in this case the Cosmos Hub):

+
 gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json
+

This is used by the launch coordinator to create the final genesis.json that will be distributed to validators in step 5.

+

5. Updating the genesis file

+

Upon reaching the spawn_time the initial validator set state will become available on the provider chain. The initial validator set is included in the final genesis.json of the consumer chain.

+

6. Chain start

+
info

The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences.

+

The new genesis.json containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided genesis.json to start their consumer chain node.

+
tip

Please pay attention to any onboarding repositories provided by the consumer chain teams. +Recommendations are available in Consumer Onboarding Checklist. +Another comprehensive guide is available in the Interchain Security testnet repo.

+

7. Creating IBC connections

+

Finally, to fully establish interchain security an IBC relayer is used to establish connections and create the required channels.

+
warning

The relayer can establish the connection only after the consumer chain starts producing blocks.

+
hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> 
hermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1
hermes start
+

Downtime Infractions

+

At present, the consumer chain can report evidence about downtime infractions to the provider chain. The min_signed_per_window and signed_blocks_window can be different on each consumer chain and are subject to changes via consumer chain governance.

+
info

Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains.

To unjail, the validator must wait for the jailing period to elapse on the provider chain and submit an unjail transaction on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains.

More information is available in Downtime Slashing documentation

+

Double-signing Infractions

+

To learn more about equivocation handling in interchain security check out the Slashing documentation section.

+

Key assignment

+

Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use.

+

For more information check out the Key assignment overview and guide

+

References:

+
+ + \ No newline at end of file diff --git a/v4.2.0/validators/overview.html.html b/v4.2.0/validators/overview.html.html new file mode 100644 index 0000000000..5062b6167a --- /dev/null +++ b/v4.2.0/validators/overview.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/validators/partial-set-security-for-validators.html b/v4.2.0/validators/partial-set-security-for-validators.html new file mode 100644 index 0000000000..378411cc9c --- /dev/null +++ b/v4.2.0/validators/partial-set-security-for-validators.html @@ -0,0 +1,113 @@ + + + + + +Partial Set Security | Interchain Security + + + + +
Version: v4.2.0

Partial Set Security

+

Partial Set Security allows consumer chains to join as Opt-In or Top N. +Here, we show how a validator can opt in, opt out, or set a custom commission rate on a consumer chain, as well +as useful queries that a validator can use to figure out which chains it has to validate, etc.

+

Messages

+

How to opt in to a consumer chain?

+
warning

A validator is automatically opted in to a Top N chain if the validator belongs to the top N% of the validators on the provider chain.

+

In a Top N chain, a validator that does not belong to the top N% of the validators on the provider can still choose +to opt in to a consumer chain. In other words, validators can opt in, in both Opt-In and Top N chains.

+

A validator can opt in to a consumer chain by issuing the following message:

+
interchain-security-pd tx provider opt-in <consumer-chain-id> <optional consumer-pub-key>
+

where

+
    +
  • consumer-chain-id is the string identifier of the consumer chain the validator wants to opt in to;
  • +
  • consumer-pub-key corresponds to the public key the validator wants to use on the consumer chain, and it has the +following format {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}.
  • +
+

A validator can opt in to an existing consumer chain that is already running, or to a proposed +consumer chain that is still being voted on. A validator can use the following command to retrieve the currently existing +consumer chains:

+
interchain-security-pd query provider list-consumer-chains
+

and this command to see the currently proposed consumer chains:

+
interchain-security-pd query provider list-proposed-consumer-chains
+
tip

By setting the consumer-pub-key, a validator can both opt in to a chain and assign a +public key on a consumer chain. Note that a validator can always assign +a new consumer key at a later stage. The key-assignment rules +still apply when setting consumer-pub-key when opting in.

+
info

A validator is only eligible for consumer rewards from a consumer chain if the validator is opted into that chain.

+

How to opt out from a consumer chain?

+

A validator can opt out from a consumer by issuing the following message:

+
interchain-security-pd tx provider opt-out <consumer-chain-id>
+

where

+
    +
  • consumer-chain-id is the string identifier of the consumer chain.
  • +
+
warning

A validator cannot opt out from a Top N chain if it belongs to the top N% validators of the provider.

+
warning

If a validator moves from the Top N to outside of the top N% of the validators on the provider, it will not +be automatically opted-out. The validator has to manually opt out.

+
warning

A validator can stop its node on a consumer chain only after opting out and confirming through the has-to-validate +query (see below) that it does +not have to validate the consumer chain any longer.

+
warning

If all validators opt out from an Opt-In chain, the chain will halt with a consensus failure upon receiving the VSCPacket with an empty validator set.

+

How to set specific per consumer chain commission rate?

+

A validator can choose to set a different commission rate on each of the consumer chains. +This can be done with the following command:

+
interchain-security-pd tx provider set-consumer-commission-rate <consumer-chain-id> <commission-rate>
+

where

+
    +
  • consumer-chain-id is the string identifier of the consumer chain;
  • +
  • comission-rate decimal in [minRate, 1] where minRate corresponds to the minimum commission rate set on the +provider chain (see min_commission_rate in interchain-security-pd query staking params).
  • +
+

If a validator does not set a commission rate on a consumer chain, the commission rate defaults to their commission rate on the provider chain.

+
tip

Validators can set their commission rate even for consumer chains that they are not currently opted in on, and the commission rate will be applied when they opt in. This is particularly useful for Top N chains, where validators might be opted in automatically, +so validators can set the commission rate in advance.

+
tip

If a validator opts out and then back in, this will not reset their commission rate back to the default. Instead, their +set commission rate still applies.

+

Queries

+

Partial Set Security introduces a number of queries to assist validators determine which consumer chains they have to +validate, their commission rate per chain, etc.

+

Which chains does a validator have to validate?

+

Naturally, a validator is aware of the Opt-In chains it has to validate because in order to validate an Opt-In chain, +a validator has to manually opt in to the chain. This is not the case for Top N chains where a validator might be required +to validate such a chain without explicitly opting in if it belongs to the top N% of the validators on the provider.

+

We introduce the following query:

+
interchain-security-pd query provider has-to-validate <provider-validator-address>
+

that can be used by validator with provider-validator-address address to retrieve the list of chains that it has to validate.

+
tip

As a validator, the list of chains returned by has-to-validate is the list of chains you should be validating to avoid +getting jailed for downtime.

+

How do you know how much voting power you need to have to be in the top N for a chain?

+

This can be seen as part of the list-consumer-chains query:

+
interchain-security-pd query provider list-consumer-chains
+

where the min_power_in_top_N field shows the minimum voting power required to be +automatically opted in to the chain.

+
tip

list-consumer-chains shows the minimal voting power right now, but +the automatic opt-in happens only when epochs end on the provider. +In consequence, a validators power might be large enough to be automatically opted in +during an epoch, but if their power is sufficiently decreased before the epoch ends, +they will not be opted in automatically.

+

How to retrieve all the opted-in validators on a consumer chain?

+

With the following query:

+
interchain-security-pd query provider consumer-opted-in-validators <consumer-chain-id>
+

we can see all the opted-in validators on consumer-chain-id that were manually or automatically opted in.

+

How to retrieve all the consumer validators on a consumer chain?

+

With the following query:

+
interchain-security-pd query provider consumer-validators <consumer-chain-id>
+

we can see all the consumer validators (i.e., validator set) of consumer-chain-id. The consumer validators are the +ones that are currently (or in the future, see warning) validating the consumer chain. A consumer validator is an opted-in +validator but not vice versa. For example, an opted-in validator V might not be a consumer validator because V is +denylisted or because V is removed due to a validator-set cap.

+
warning

The returned consumer validators from this query do not necessarily correspond to the validator set that is +validating the consumer chain at this exact moment. This is because the VSCPacket sent to a consumer chain might be +delayed and hence this query might return the validator set that the consumer chain would have at some future +point in time.

+

How can we see the commission rate a validator has set on a consumer chain?

+

Using the following query:

+
interchain-security-pd query provider validator-consumer-commission-rate <consumer-chain-id> <provider-validator-address>
+

we retrieve the commission rate set by validator with provider-validator-address address on consumer-chain-id.

+ + \ No newline at end of file diff --git a/v4.2.0/validators/partial-set-security-for-validators.html.html b/v4.2.0/validators/partial-set-security-for-validators.html.html new file mode 100644 index 0000000000..7e9fed9855 --- /dev/null +++ b/v4.2.0/validators/partial-set-security-for-validators.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v4.2.0/validators/withdraw_rewards.html b/v4.2.0/validators/withdraw_rewards.html new file mode 100644 index 0000000000..f7e8bf83b4 --- /dev/null +++ b/v4.2.0/validators/withdraw_rewards.html @@ -0,0 +1,31 @@ + + + + + +Withdrawing consumer chain validator rewards | Interchain Security + + + + +
Version: v4.2.0

Withdrawing consumer chain validator rewards

+

Here are example steps for withdrawing rewards from consumer chains in the provider chain

+
info

The examples used are from rs-testnet, the replicated security persistent testnet.

Validator operator address: cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 +Self-delegation address: cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

+

Prior to withdrawing rewards, query balances for self-delegation address:

+
gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

balances:
- amount: "1000000000000"
denom: uatom
pagination:
next_key: null
total: "0"
+

Querying validator rewards

+

Query rewards for the validator address:

+
gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6

rewards:
- amount: "158.069895000000000000"
denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD
- amount: "841842390516.072526500000000000"
denom: uatom
+

The ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD denom represents rewards from a consumer chain.

+

Withdrawing rewards and commission

+

1. Withdraw rewards

+
gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y

txhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A
+

2. Confirm withdrawal

+

After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:

+
gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

balances:
- amount: "216"
denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD
- amount: "2233766225342"
denom: uatom
pagination:
next_key: null
total: "0"
+ + \ No newline at end of file diff --git a/v4.2.0/validators/withdraw_rewards.html.html b/v4.2.0/validators/withdraw_rewards.html.html new file mode 100644 index 0000000000..300b08a414 --- /dev/null +++ b/v4.2.0/validators/withdraw_rewards.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0.html b/v5.0.0.html new file mode 100644 index 0000000000..c46d8dad7a --- /dev/null +++ b/v5.0.0.html @@ -0,0 +1,19 @@ + + + + + +Interchain Security Docs | Interchain Security + + + + +
+ + \ No newline at end of file diff --git a/v5.0.0.html.html b/v5.0.0.html.html new file mode 100644 index 0000000000..9daa3ca08a --- /dev/null +++ b/v5.0.0.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-001-key-assignment.html b/v5.0.0/adrs/adr-001-key-assignment.html new file mode 100644 index 0000000000..d0f6035cb7 --- /dev/null +++ b/v5.0.0/adrs/adr-001-key-assignment.html @@ -0,0 +1,79 @@ + + + + + +Key Assignment | Interchain Security + + + + +
Version: v5.0.0

ADR 001: Key Assignment

+

Changelog

+
    +
  • 2022-12-01: Initial Draft
  • +
  • 2024-03-01: Updated to take into account they key-assigment-replacement deprecation.
  • +
+

Status

+

Accepted

+

Context

+

KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate.

+

Decision

+

It is possible to change the keys at any time by submitting a transaction (i.e., MsgAssignConsumerKey).

+

State required

+
    +
  • ValidatorConsumerPubKey - Stores the validator assigned keys for every consumer chain.
  • +
+
ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey
+
    +
  • ValidatorByConsumerAddr - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol.
  • +
+
ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress
+
    +
  • ConsumerAddrsToPrune - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning ValidatorByConsumerAddr.
  • +
+
ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses
+

Protocol overview

+

On receiving a MsgAssignConsumerKey(chainID, providerAddr, consumerKey) message:

+
// get validator from staking module  
validator, found := stakingKeeper.GetValidator(providerAddr)
if !found {
return ErrNoValidatorFound
}
providerConsAddr := validator.GetConsAddr()

// make sure consumer key is not in use
consumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey)
if _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found {
return ErrInvalidConsumerConsensusPubKey
}

// check whether the consumer chain is already registered
// i.e., a client to the consumer was already created
if _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered {
// get the previous key assigned for this validator on this consumer chain
oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr)
if found {
// mark this old consumer key as prunable once the VSCMaturedPacket
// for the current VSC ID is received
oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)
vscID := GetValidatorSetUpdateId()
AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr)
}
} else {
// if the consumer chain is not registered, then remove the previous reverse mapping
if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found {
oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey)
DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr)
}
}


// set the mapping from this validator's provider address to the new consumer key
SetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey)

// set the reverse mapping: from this validator's new consensus address
// on the consumer to its consensus address on the provider
SetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr)
+

When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see MakeConsumerGenesis).

+
func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) {
// ...
// get initial valset from the staking module
var updates []abci.ValidatorUpdate{}
stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) {
validator := stakingKeeper.GetValidator(providerAddr)
providerKey := validator.TmConsPublicKey()
updates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power})
return false
})

// applies the key assignment to the initial validator
for i, update := range updates {
providerAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey)
if consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found {
updates[i].PubKey = consumerKey
}
}
gen.InitialValSet = updates

// get a hash of the consumer validator set from the update
updatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates)
hash := tendermint.NewValidatorSet(updatesAsValSet).Hash()

return gen, hash, nil
}
+

Note that key assignment works hand-in-hand with epochs. +For each consumer chain, we store the consumer validator set that is currently (i.e., in this epoch) validating the consumer chain. +Specifically, for each validator in the set we store among others, the public key that it is using on the consumer chain during the current (i.e., ongoing) epoch. +At the end of every epoch, if there were validator set changes on the provider, then for every consumer chain, we construct a VSCPacket +with all the validator updates and add it to the list of PendingVSCPackets. We compute the validator updates needed by a consumer chain by +comparing the stored list of consumer validators with the current bonded validators on the provider, with something similar to this:

+
// get the valset that has been validating the consumer chain during this epoch 
currentValidators := GetConsumerValSet(consumerChain)
// generate the validator updates needed to be sent through a `VSCPacket` by comparing the current validators
// in the epoch with the latest bonded validators
valUpdates := DiffValidators(currentValidators, stakingmodule.GetBondedValidators())
// update the current validators set for the upcoming epoch to be the latest bonded validators instead
SetConsumerValSet(stakingmodule.GetBondedValidators())
+

where DiffValidators internally checks if the consumer public key for a validator has changed since the last +epoch and if so generates a validator update. This way, a validator can change its consumer public key for a consumer +chain an arbitrary amount of times and only the last set consumer public key would be taken into account.

+

On receiving a SlashPacket from a consumer chain with id chainID for a infraction of a validator data.Validator:

+
func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) {
// ...
// the slash packet validator address may be known only on the consumer chain;
// in this case, it must be mapped back to the consensus address on the provider chain
consumerAddr := sdk.ConsAddress(data.Validator.Address)
providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr)
if !found {
// the validator has the same key on the consumer as on the provider
providerAddr = consumerAddr
}
// ...
}
+

On receiving a VSCMatured:

+
func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement {
// ...
// prune previous consumer validator address that are no longer needed
consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId)
for _, addr := range consumerAddrs {
DeleteValidatorByConsumerAddr(chainID, addr)
}
DeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId)
// ...
}
+

On stopping a consumer chain:

+
func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan bool) (err error) {
// ...
// deletes all the state needed for key assignments on this consumer chain
// ...
}
+

Consequences

+

Positive

+
    +
  • Validators can use different consensus keys on the consumer chains.
  • +
+

Negative

+
    +
  • None
  • +
+

Neutral

+
    +
  • The consensus state necessary to create a client to the consumer chain must use the hash returned by the MakeConsumerGenesis method as the nextValsHash.
  • +
  • The consumer chain can no longer check the initial validator set against the consensus state on InitGenesis.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-001-key-assignment.html.html b/v5.0.0/adrs/adr-001-key-assignment.html.html new file mode 100644 index 0000000000..3f3ce44c70 --- /dev/null +++ b/v5.0.0/adrs/adr-001-key-assignment.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-002-throttle.html b/v5.0.0/adrs/adr-002-throttle.html new file mode 100644 index 0000000000..de4780b1db --- /dev/null +++ b/v5.0.0/adrs/adr-002-throttle.html @@ -0,0 +1,164 @@ + + + + + +Jail Throttling | Interchain Security + + + + +
Version: v5.0.0

ADR 002: Jail Throttling

+

Changelog

+
    +
  • 2023-01-26: Initial Draft
  • +
  • 2023-02-07: Property refined, ADR ready to review/merge
  • +
  • 2023-11-22: Refactor for better understanding
  • +
+

Status

+

Accepted

+

Context

+

The CCV spec is based around the assumption that the provider binary and all consumers binaries are non-malicious, and follow the defined protocols. +In practice, this assumption may not hold. +A malicious consumer binary could potentially include code which is able to send many slash/jail packets at once to the provider.

+

Before the throttling feature was implemented, the following attack was possible. +Attacker(s) would create provider validators just below the provider's active set. +Using a malicious consumer binary, slash packets would be relayed to the provider, that would slash/jail a significant portion (or all) of honest validator at once. +Control of the provider would then pass over to the attackers' validators. +This enables the attacker(s) to halt the provider. +Or even worse, commit arbitrary state on the provider, potentially stealing all tokens bridged to the provider over IBC.

+

Decision

+

The throttling feature was designed to slow down the mentioned attack from above, allowing validators and the community to appropriately respond to the attack, +i.e., this feature limits (enforced by on-chain params) the rate that the provider validator set can be jailed over time.

+

Required State

+

Slash meter: There exists one slash meter on the provider which stores an amount of voting power (integer), corresponding to an allowance of validators that can be jailed over time. +This meter is initialized to a certain value on genesis, decremented by the amount of voting power jailed whenever a slash packet is handled, and periodically replenished as decided by on-chain params.

+

Global entry queue: There exists a single queue which stores "global slash entries". +These entries allow the provider to appropriately handle slash packets sent from any consumer in FIFO ordering. +This queue is responsible for coordinating the order that slash packets (from multiple chains) are handled over time.

+

Per-chain data queue: For each established consumer, there exists a queue which stores "throttled packet data", +i.e.,pending slash packet data is queued together with pending VSC matured packet data in FIFO ordering. +Order is enforced by IBC sequence number. +These "per-chain" queues are responsible for coordinating the order that slash packets are handled in relation to VSC matured packets from the same chain.

+

Note: The reason for a multiple-queue design is the VSC Maturity and Slashing Order property (see spec). +There are other ways to ensure such a property (like a queue of linked lists, etc.), but the proposed approach seemed to be the most understandable and easiest to implement with a KV store.

+

Params

+

SlashMeterReplenishPeriod -- the period after which the slash meter is replenished.

+

SlashMeterReplenishFraction -- the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs. This param also serves as a maximum fraction of total voting power that the slash meter can hold.

+

MaxThrottledPackets -- the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value. +This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness.

+

Protocol Overview

+

OnRecvSlashPacket

+

Upon the provider receiving a slash packet from any of the established consumers during block execution, two things occur:

+
    +
  1. A global slash entry is queued.
  2. +
  3. The data of such a packet is added to the per-chain queue.
  4. +
+

OnRecvVSCMaturedPacket

+

Upon the provider receiving a VSCMatured packet from any of the established consumers during block execution, the VSCMatured packet data is added to the per-chain queue.

+

Endblocker

+

In the EndBlock of the provider CCV module, there are three actions performed:

+
    +
  • replenish the slash meter;
  • +
  • handle the leading VSCMaturedPackets;
  • +
  • and handle the throttle queues.
  • +
+
Slash Meter Replenishment
+

Once the slash meter becomes not full, it'll be replenished after SlashMeterReplenishPeriod by incrementing the meter with its allowance for the replenishment block, where allowance = SlashMeterReplenishFraction * currentTotalVotingPower. +The slash meter will never exceed its current allowance (function of the total voting power for the block) in value.

+

Note a few things:

+
    +
  1. The slash meter can go negative in value, and will do so when handling a single slash packet that jails a validator with significant voting power. +In such a scenario, the slash meter may take multiple replenishment periods to once again reach a positive value (or 0), meaning no other slash packets may be handled for multiple replenishment periods.
  2. +
  3. Total voting power of a chain changes over time, especially as validators are jailed. +As validators are jailed, total voting power decreases, and so does the jailing allowance. +See below for more detailed throttling property discussion.
  4. +
  5. The voting power allowance added to the slash meter during replenishment will always be greater than or equal to 1. +If the SlashMeterReplenishFraction is set too low, integer rounding will put this minimum value into effect. +That is, if SlashMeterReplenishFraction * currentTotalVotingPower < 1, then the effective allowance would be 1. +This min value of allowance ensures that there's some packets handled over time, even if that is a very long time. +It's a crude solution to an edge case caused by too small of a replenishment fraction.
  6. +
+

The behavior described above is achieved by executing CheckForSlashMeterReplenishment() every EndBlock, BEFORE HandleThrottleQueues() is executed.

+
Handle Leading VSCMaturedPackets
+

In every block, it is possible that VSCMaturedPacket data was queued before any slash packet data. +Since this "leading" VSCMatured packet data does not have to be throttled (see VSC Maturity and Slashing Order), we can handle all VSCMatured packet data at the head of the queue, before the any throttling or packet data handling logic executes.

+
Handle Throttle Queues
+

In every EndBlock, the following logic is executed to handle data from the throttle queues.

+
meter := getSlashMeter()

// Keep iterating as long as the meter has a positive (or 0) value, and global slash entries exist
while meter.IsPositiveOrZero() && entriesExist() {
// Get next entry in queue
entry := getNextGlobalSlashEntry()
// Decrement slash meter by the voting power that will be removed from the valset from handling this slash packet
valPower := entry.getValPower()
meter = meter - valPower
// Using the per-chain queue, handle the single slash packet using its queued data,
// then handle all trailing VSCMatured packets for this consumer
handleSlashPacketAndTrailingVSCMaturedPackets(entry)
// Delete entry in global queue, delete handled data
entry.Delete()
deleteThrottledSlashPacketData()
deleteTrailingVSCMaturedPacketData()
}
+

System Properties

+

All CCV system properties should be maintained by implementing this feature, see CCV spec - Consumer Initiated Slashing.

+

One implementation-specific property introduced is that if any of the chain-specific packet data queues become larger than MaxThrottledPackets, then the provider binary will panic, and the provider chain will halt. +Therefore this param should be set carefully. See SetThrottledPacketDataSize. +This behavior ensures that if the provider binaries are queuing up more packet data than machines can handle, the provider chain halts deterministically between validators.

+

Main Throttling Property

+

Using on-chain params and the sub protocol defined, slash packet throttling is implemented such that the following property holds under some conditions.

+

First, we introduce the following definitions:

+
    +
  • A consumer initiated slash attack "starts" when the first slash packet from such an attack is received by the provider.
  • +
  • The "initial validator set" for the attack is the validator set that existed on the provider when the attack started.
  • +
  • There is a list of honest validators such that if they are jailed, X% of the initial validator set will be jailed.
  • +
+

For the Throttling Property to hold, the following assumptions must be true:

+
    +
  1. We assume the total voting power of the chain (as a function of delegations) does not increase over the course of the attack.
  2. +
  3. No validator has more than SlashMeterReplenishFraction of total voting power on the provider.
  4. +
  5. SlashMeterReplenishFraction is large enough that SlashMeterReplenishFraction * currentTotalVotingPower > 1, +i.e., the replenish fraction is set high enough that we can ignore the effects of rounding.
  6. +
  7. SlashMeterReplenishPeriod is sufficiently longer than the time it takes to produce a block.
  8. +
+

Note if these assumptions do not hold, throttling will still slow down the described attack in most cases, just not in a way that can be succinctly described. It's possible that more complex properties can be defined.

+

Throttling Property: The time it takes to jail/tombstone X% of the initial validator set will be greater than or equal to +SlashMeterReplenishPeriodXSlashMeterReplenishFraction2SlashMeterReplenishPeriod\mathit{SlashMeterReplenishPeriod} \cdot \frac{X}{\mathit{SlashMeterReplenishFraction}} - 2 \cdot \mathit{SlashMeterReplenishPeriod}.

+
+

Intuition

+

Let's use the following notation:

+
    +
  • CC: Number of replenishment cycles
  • +
  • PP: SlashMeterReplenishPeriod\mathit{SlashMeterReplenishPeriod}
  • +
  • FF: SlashMeterReplenishFraction\mathit{SlashMeterReplenishFraction}
  • +
  • VmaxV_{\mathit{max}}: Max power of a validator as a fraction of total voting power
  • +
+

In CC number of replenishment cycles, the fraction of total voting power that can be removed, aa, is aFC+Vmaxa \leq F \cdot C + V_{\mathit{max}} (where VmaxV_{\mathit{max}} is there to account for the power fraction of the last validator removed, one which pushes the meter to the negative value).

+

So, we need at least CaVmaxFC \geq \frac{a - V_{\mathit{max}}}{F} cycles to remove aa fraction of the total voting power.

+

Since we defined the start of the attack to be the moment when the first slash request arrives, then FF fraction of the initial validator set can be jailed immediately. For the remaining XFX - F fraction of the initial validator set to be jailed, it takes at least C(XF)VmaxFC \geq \frac{(X - F) - V_{\mathit{max}}}{F} cycles. Using the assumption that VmaxFV_{\mathit{max}} \leq F (assumption 2), we get CX2FFC \geq \frac{X - 2F}{F} cycles.

+

In order to execute CC cycles, we need CPC \cdot P time.

+

Thus, jailing the remaining XFX - F fraction of the initial validator set corresponds to P(X2F)F\frac{P \cdot (X - 2F)}{F} time.

+

In other words, the attack must take at least PXF2P\frac{P \cdot X}{F} - 2P time (in the units of replenish period PP).

+
+

This property is useful because it allows us to reason about the time it takes to jail a certain percentage of the initial provider validator set from consumer initiated slash requests. +For example, if SlashMeterReplenishFraction is set to 0.06, then it takes no less than 4 replenishment periods to jail 33% of the initial provider validator set on the Cosmos Hub. +Note that as of writing this on 11/29/22, the Cosmos Hub does not have a validator with more than 6% of total voting power.

+

Note also that 4 replenishment period is a worst case scenario that depends on well crafted attack timings.

+

How Unjailing Affects the Main Throttling Property

+

Note that the jailing allowance is directly proportional to the current total voting power of the provider chain. Therefore, if honest validators don't unjail themselves during the attack, the total voting power of the provider chain will decrease over the course of the attack, and the attack will be slowed down, main throttling property is maintained.

+

If honest validators do unjail themselves, the total voting power of the provider chain will still not become higher than when the attack started (unless new token delegations happen), therefore the main property is still maintained. Moreover, honest validators unjailing themselves helps prevent the attacking validators from gaining control of the provider.

+

In summary, the throttling mechanism as designed has desirable properties whether or not honest validators unjail themselves over the course of the attack.

+

Consequences

+

Positive

+
    +
  • The described attack is slowed down in seemingly all cases.
  • +
  • If certain assumptions hold, the described attack is slowed down in a way that can be precisely time-bounded.
  • +
+

Negative

+
    +
  • Throttling introduces a vector for a malicious consumer chain to halt the provider, see issue below. +However, this is sacrificing liveness in a edge case scenario for the sake of security. +As an improvement, using retries would fully prevent this attack vector.
  • +
+

Neutral

+
    +
  • Additional state is introduced to the provider chain.
  • +
  • VSCMatured and slash packet data is not always handled in the same block that it is received.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-002-throttle.html.html b/v5.0.0/adrs/adr-002-throttle.html.html new file mode 100644 index 0000000000..6e61266e64 --- /dev/null +++ b/v5.0.0/adrs/adr-002-throttle.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-003-equivocation-gov-proposal.html b/v5.0.0/adrs/adr-003-equivocation-gov-proposal.html new file mode 100644 index 0000000000..aff42f556b --- /dev/null +++ b/v5.0.0/adrs/adr-003-equivocation-gov-proposal.html @@ -0,0 +1,60 @@ + + + + + +Equivocation governance proposal | Interchain Security + + + + +
Version: v5.0.0

ADR 003: Equivocation governance proposal

+

Changelog

+
    +
  • 2023-02-06: Initial draft
  • +
  • 2023-11-30: Change status to deprecated
  • +
+

Status

+

Deprecated

+

Context

+

Note: ADR deprecated as the equivocation proposal was removed by the +cryptographic verification of equivocation feature +(see ADR-005 and +ADR-013).

+

We want to limit the possibilities of a consumer chain to execute actions on the provider chain to maintain and ensure optimum security of the provider chain.

+

For instance, a malicious consumer consumer chain can send slash packet to the provider chain, which will slash a validator without the need of providing an evidence.

+

Decision

+

To protect against a malicious consumer chain, slash packets unrelated to downtime are ignored by the provider chain. Thus, an other mechanism is required to punish validators that have committed a double-sign on a consumer chain.

+

A new kind of governance proposal is added to the provider module, allowing to slash and tombstone a validator for double-signing in case of any harmful action on the consumer chain.

+

If such proposal passes, the proposal handler delegates to the evidence module to process the equivocation. This module ensures the evidence isn’t too old, or else ignores it (see code). Too old is determined by 2 consensus params :

+
    +
  • evidence.max_age_duration number of nanoseconds before an evidence is considered too old
  • +
  • evidence.max_age_numblocks number of blocks before an evidence is considered too old.
  • +
+

On the hub, those parameters are equals to

+
// From https://cosmos-rpc.polkachu.com/consensus_params?height=13909682
(...)
"evidence": {
"max_age_num_blocks": "1000000",
"max_age_duration": "172800000000000",
(...)
},
(...)
+

A governance proposal takes 14 days, so those parameters must be big enough so the evidence provided in the proposal is not ignored by the evidence module when the proposal passes and is handled by the hub.

+

For max_age_num_blocks=1M, the parameter is big enough if we consider the hub produces 12k blocks per day (blocks_per_year/365 = 436,0000/365). The evidence can be up to 83 days old (1,000,000/12,000) and not be ignored.

+

For max_age_duration=172,800,000,000,000, the parameter is too low, because the value is in nanoseconds so it’s 2 days. Fortunately the condition that checks those 2 parameters uses a AND, so if max_age_num_blocks condition passes, the evidence won’t be ignored.

+

Consequences

+

Positive

+
    +
  • Remove the possibility from a malicious consumer chain to “attack” the provider chain by slashing/jailing validators.
  • +
  • Provide a more acceptable implementation for the validator community.
  • +
+

Negative

+
    +
  • Punishment action of double-signing isn’t “automated”, a governance proposal is required which takes more time.
  • +
  • You need to pay 250ATOM to submit an equivocation evidence.
  • +
+

Neutral

+

References

+
+ + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-003-equivocation-gov-proposal.html.html b/v5.0.0/adrs/adr-003-equivocation-gov-proposal.html.html new file mode 100644 index 0000000000..58beb95430 --- /dev/null +++ b/v5.0.0/adrs/adr-003-equivocation-gov-proposal.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-004-denom-dos-fixes.html b/v5.0.0/adrs/adr-004-denom-dos-fixes.html new file mode 100644 index 0000000000..69937ca9da --- /dev/null +++ b/v5.0.0/adrs/adr-004-denom-dos-fixes.html @@ -0,0 +1,59 @@ + + + + + +ADR Template | Interchain Security + + + + +
Version: v5.0.0

ADR 004: Denom DOS fixes

+

Changelog

+
    +
  • 5/9/2023: ADR created
  • +
+

Status

+

Accepted

+

Context

+

The provider and consumer modules are vulnerable to similar issues involving an attacker sending millions of denoms to certain addresses and causing the chain to halt. This ADR outlines both fixes since they are similar. Both fixes involve processing only denoms that are on a whitelist to avoid iterating over millions of junk denoms but have different requirements and are implemented in different ways.

+

Decision

+

Provider

+
    +
  • Put the distribution module's FeePoolAddress back on the blocklist so that it cannot receive funds from users.
  • +
  • Create a new address called ConsumerRewardPool and unblock it, allowing funds to be sent to it.
  • +
  • Create a set of strings in the store for allowed ConsumerRewardDenoms.
  • +
  • Create an endpoint called RegisterConsumerRewardDenom which deducts a fee from the sender's account, sends it to the community pool and adds a string to the ConsumerRewardDenoms set.
  • +
  • Create a parameter called ConsumerRewardDenomRegistrationFee which determines the fee which is charged to register a consumer reward denom in the step above.
  • +
  • Create a function called TransferRewardsToFeeCollector which gets the entire ConsumerRewardDenoms set from the store, iterates over it, and for each entry: +
      +
    • Gets the balance of this denom for the ConsumerRewardPool account
    • +
    • Sends the entire balance out to the FeePoolAddress using SendCoinsFromModuleToModule which is not affected by the blocklist.
    • +
    +
  • +
  • Run TransferRewardsToFeeCollector in the endblock
  • +
+

Now, nobody can send millions of junk denoms to the FeePoolAddress because it is on the block list. If they send millions of junk denoms to the ConsumerRewardPool, this does not matter because all balances are not iterated over, only those which are in the ConsumerRewardDenoms set.

+

We also add a new tx: register-consumer-reward-denom, and a new query: registered-consumer-reward-denoms

+

Consumer

+
    +
  • Create a new param RewardDenoms with a list of strings
  • +
  • Create a new param ProviderRewardDenoms with a list of strings
  • +
  • Create a function AllowedRewardDenoms which iterates over ProviderRewardDenoms and converts each denom to its ibc-prefixed denom using the provider chain's ibc channel information, then concatenates the RewardDenoms list and returns the combined list of allowed denoms.
  • +
  • In SendRewardsToProvider, instead of iterating over the balances of all denoms in the ToSendToProvider address, iterate over AllowedRewardDenoms
  • +
+

Now, if somebody sends millions of junk denoms to ToSendToProvider, they will not be iterated over. Only the RewardDenoms and ProviderRewardDenoms will be iterated over. Since we do not require this feature to be permissionless on the consumer, the registration fee process is not needed.

+

Consequences

+

Positive

+
    +
  • Denom DOS is no longer possible on either provider or consumer.
  • +
+

Negative

+
    +
  • Consumer chain teams must pay a fee to register a denom for distribution on the provider, and add some extra parameters in their genesis file.
  • +
+ + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-004-denom-dos-fixes.html.html b/v5.0.0/adrs/adr-004-denom-dos-fixes.html.html new file mode 100644 index 0000000000..a354241624 --- /dev/null +++ b/v5.0.0/adrs/adr-004-denom-dos-fixes.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-005-cryptographic-equivocation-verification.html b/v5.0.0/adrs/adr-005-cryptographic-equivocation-verification.html new file mode 100644 index 0000000000..9ee7ac5f4f --- /dev/null +++ b/v5.0.0/adrs/adr-005-cryptographic-equivocation-verification.html @@ -0,0 +1,145 @@ + + + + + +Cryptographic verification of equivocation evidence | Interchain Security + + + + +
Version: v5.0.0

ADR 005: Cryptographic verification of equivocation evidence

+

Changelog

+
    +
  • 5/1/2023: First draft
  • +
  • 7/23/2023: Add light client attacks handling
  • +
  • 9/6/2023: Add double signing attacks handling
  • +
  • 11/3/2023: Update limitations to clarify amnesia attacks are ignored
  • +
+

Status

+

Accepted

+

Context

+

Currently, we use a governance proposal to slash validators for equivocation (double signing and light client attacks). +Every proposal needs to go through a (two weeks) voting period before it can be approved. +Given a three-week unbonding period, this means that an equivocation proposal needs to be submitted within one week since the infraction occurred.

+

This ADR proposes a system to slash validators automatically for equivocation, immediately upon the provider chain's receipt of the evidence. Another thing to note is that we intend to introduce this system in stages, since even the partial ability to slash and/or tombstone is a strict improvement in security. +The feature is implemented in two parts, each with its dedicated endpoint. One endpoint handles light client attacks, while the other handles double signing attacks.

+

Light Client Attack

+

In a nutshell, the light client is a process that solely verifies a specific state machine's +consensus without executing the transactions. The light clients get new headers by querying +multiple nodes, called primary and witness nodes.

+

Light clients download new headers committed on chain from a primary. Headers can be verified in two ways: sequentially, +where the block height of headers is serial, or using skipping. This second verification method allows light clients to download headers +with nonconsecutive block height, where some intermediate headers are skipped (see Tendermint Light Client, Figure 1 and Figure 3). +Additionally, light clients are cross-checking new headers obtained from a primary with witnesses to ensure all nodes share the same state.

+

A light client attack occurs when a Byzantine validator sends invalid headers to a light client. +As the light client doesn't execute transactions, it can be deceived into trusting corrupted application state transitions. +For instance, if a light client receives header A from the primary and header B from a witness for the same block height H, +and both headers are successfully verified, it indicates a light client attack. +Note that in this case, either the primary or the witness or both are malicious.

+

The types of light client attacks are defined by analyzing the differences between the conflicting headers. +There are three types of light client attacks: lunatic attack, equivocation attack, and amnesia attack. +For details, see the CometBFT specification.

+

When a light client agent detects two conflicting headers, it will initially verify their traces (see cometBFT detector) using its primary and witness nodes. +If these headers pass successful verification, the Byzantine validators will be identified based on the header's commit signatures +and the type of light client attack. The agent will then transmit this information to its nodes using a LightClientAttackEvidence evidence to be eventually voted on and added to a block. +Note that from a light client agent perspective, it is not possible to establish whether a primary or a witness node, or both, are malicious. +Therefore, it will create and send two evidences: one against the primary (sent to the witness), and one against the witness (sent to the primary). +Both nodes will then verify it before broadcasting it and adding it to the evidence pool. +If an evidence is finally committed to a block, the chain's evidence module will execute it, resulting in the jailing and the slashing of the validators responsible for the light client attack.

+

Light clients are a core component of IBC. In the event of a light client attack, IBC relayers notify the affected chains by submitting an IBC misbehavior message. +A misbehavior message includes the conflicting headers that constitute a light client attack evidence. Upon receiving such a message, +a chain will first verify whether these headers would have convinced its light client. This verification is achieved by checking +the header states against the light client consensus states (see IBC misbehaviour handler). If the misbehaviour is successfully verified, the chain will then "freeze" the +light client, halting any further trust in or updating of its states.

+

Double Signing Attack

+

A double signing attack, also known as equivocation, +occurs when a validator votes for two different blocks in the same round of the CometBFT consensus. +This consensus mechanism operates with multiple voting rounds at each block height, +and it strictly prohibits sending two votes of the same type during a round +(see CometBFT State Machine Overview).

+

When a node observes two votes from the same peer, it will use these two votes to create +a DuplicateVoteEvidence +evidence and gossip it to the other nodes in the network +(see CometBFT equivocation detection). +Each node will then verify the evidence according to the CometBFT rules that define a valid double signing infraction, and based on this verification, they will decide whether to add the evidence to a block. +During the evidence verification process, the signatures of the conflicting votes must be verified successfully. +Note that this is achieved using the public key of the misbehaving validator, along with the chain ID of the chain where the infraction occurred (see CometBFT equivocation verification).

+

Once a double signing evidence is committed to a block, the consensus layer will report the equivocation to the evidence module of the Cosmos SDK application layer. +The application will, in turn, punish the malicious validator through jailing, tombstoning and slashing +(see handleEquivocationEvidence).

+

Decision

+

Light Client Attack

+

In the first part of the feature, we introduce a new endpoint: HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour). +The main idea is to leverage the current IBC misbehaviour handling and update it to solely jail and slash the validators that +performed a light client attack. Note that in this context, we assume that chains connected via a light client +share the same validator set, as is the case with Replicated Security.

+

This endpoint reuses the IBC client libraries to verify that the misbehaviour headers would have fooled the light client. +Additionally, it’s crucial that the endpoint logic results in the slashing and jailing of validators under the same conditions +as a light client agent detector. Therefore, the endpoint ensures that the two conditions are met: +the headers in the misbehaviour message have the same block height, and +the light client isn’t expired.

+

After having successfully verified a misbehaviour, the endpoint executes the jailing and slashing of the malicious validators similarly as in the evidence module.

+

Double Signing Attack

+

In the second part of the feature, we introduce a new endpoint HandleConsumerDoubleVoting( ctx sdk.Context, evidence *tmtypes.DuplicateVoteEvidence, chainID string, pubkey cryptotypes.PubKey). +Simply put, the handling logic verifies a double signing evidence against a provided +public key and chain ID and, if successful, executes the jailing of the malicious validator who double voted.

+

We define a new +MsgSubmitConsumerDoubleVoting message to report a double voting evidence observed +on a consumer chain to the endpoint of the provider chain. This message contains two fields: +a double signing evidence +duplicate_vote_evidence and a light client header for the infraction block height, +referred to as infraction_block_header. +The latter provides the malicious validator's public key and the chain ID required to verify the signature of the votes contained in the evidence.

+

Note that double signing evidence is not verified using the same conditions as in the implementation CometBFT (see +verify(evidence types.Evidence) method). Specifically, we do not check that the evidence hasn't expired. +More details can be found in the "Current limitations" section below.

+

Upon a successful equivocation verification, the misbehaving validator is jailed for the maximum time +(see DoubleSignJailEndTime +in the SDK evidence module).

+

Current limitations:

+
    +
  • +

    We cannot derive an infraction height from the evidence, so it is only possible to jail validators, not actually slash them. +To explain the technical reasons behind this limitation, let's recap the initial consumer initiated slashing logic. +In a nutshell, consumer heights are mapped to provider heights through VSCPackets, namely through the so called vscIDs. +When an infraction occurs on the consumer, a SlashPacket containing the vscID obtained from mapping the consumer infraction height +is sent to the provider. Upon receiving the packet, the provider maps the consumer infraction height to a local infraction height, +which is used to slash the misbehaving validator. In the context of untrusted consumer chains, all their states, including vscIDs, +could be corrupted and therefore cannot be used for slashing purposes.

    +
  • +
  • +

    For the same reasons explained above, the age of a consumer double signing evidence can't be verified, +either using its infraction height or its unsigned timestamp. Note that changes the jailing behaviour, potentially leading to a validator's jailing based on some "old" evidence from a consumer, which wouldn't occur if the consumer were a standalone chain.

    +
  • +
  • +

    In the first stage of this feature, validators are jailed indefinitely without being tombstoned. +The underlying reason is that a malicious validator could take advantage of getting tombstoned +to avoid being slashed on the provider (see comment).

    +
  • +
  • +

    Currently, the endpoint can only handle equivocation light client attacks. This is because the lunatic attacks require the endpoint to possess the ability to dissociate which header is conflicted or trusted upon receiving a misbehavior message. Without this information, it's not possible to extract the Byzantine validators from the conflicting headers (see comment). In addition, "amnesia" attacks are ignored, similar to CometBFT (see ADR-056).

    +
  • +
+

Consequences

+

Positive

+
    +
  • It is now possible for the provider chain to jail validators who committed +light client or double signing attacks on a consumer chain.
  • +
+

Negative

+
    +
  • N/A
  • +
+

References

+
+ + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-005-cryptographic-equivocation-verification.html.html b/v5.0.0/adrs/adr-005-cryptographic-equivocation-verification.html.html new file mode 100644 index 0000000000..b4629b33c1 --- /dev/null +++ b/v5.0.0/adrs/adr-005-cryptographic-equivocation-verification.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html b/v5.0.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html new file mode 100644 index 0000000000..781163699a --- /dev/null +++ b/v5.0.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html @@ -0,0 +1,98 @@ + + + + + +ADR Template | Interchain Security + + + + +
Version: v5.0.0

ADR 007: Pause validator unbonding during equivocation proposal

+

Changelog

+
    +
  • 2023-05-16: Initial Draft
  • +
  • 2023-11-30: Change the status to rejected
  • +
+

Status

+

Rejected

+

Context

+

Note: ADR rejected as the equivocation proposal was removed by the +cryptographic verification of equivocation feature +(see ADR-005 and +ADR-013).

+

Currently, if an equivocation slashing proposal is created after more than one +week has passed since the equivocation, it is possible that the validator in +question could unbond and get away without being slashed, since the unbonding +period is 3 weeks, and the voting period is 2 weeks. For this reason, it might +be good to pause unbondings for validators named in an equivocation slashing +proposal until the proposal's voting period is over.

+

Decision

+

How

+

Pausing the unbonding period is already possible thanks to the changes in the +staking module of the cosmos-sdk:

+
    +
  • stakingKeeper.PutUnbondingOnHold pauses an unbonding period
  • +
  • stakingKeeper.UnbondingCanComplete unpauses an unbonding period
  • +
+

These methods use a reference counter under the hood, that gets incremented +every time PutUnbondingOnHold is called, and decreased when +UnbondingCanComplete is called instead. A specific unbonding is considered +fully unpaused when its underlying reference counter reaches 0. Therefore, as +long as we safeguard consistency - i.e. we make sure we eventually decrement +the reference counter for each time we have incremented it - we can safely use +this existing mechanism without conflicts with the Completion of Unbonding +Operations system.

+

When pause

+

The unbonding period (if there is any unbonding) should be paused once an +equivocation proposal enters the voting period. For that, the gov module's +hook AfterProposalDeposit can be used.

+

If the hook is triggered with a an equivocation proposal in voting period, then +for each equivocation of the proposal, the unbonding operations of the related +validator that were initiated after the equivocation block time must be paused

+
    +
  • i.e. the underlying reference counter has to be increased.
  • +
+

Note that even after the voting period has started, a proposal can receive +additional deposits. The hook is triggered however at arrival of a deposit, so +a check to verify that the proposal is not already in voting period is +required.

+

When unpause

+

We can use a gov module's hook also here and it is +AfterProposalVotingPeriodEnded.

+

If the hook is triggered with an equivocation proposal, then for each +associated equivocation, the unbonding operations of the related validator that +were initiated between the equivocation block time and the start of the +proposal voting period must be unpaused - i.e. decrease the underlying +reference counter - regardless of the proposal outcome.

+

Consequences

+

Positive

+
    +
  • Validators subject to an equivocation proposal cannot finish unbonding +their tokens before the end of the voting period.
  • +
+

Negative

+
    +
  • A malicious consumer chain could forge slash packets enabling submission of +an equivocation proposal on the provider chain, resulting in the freezing of +validator's unbondings for an undeterminated amount of time.
  • +
  • Misbehavior on a consumer chain can potentially go unpunished, if no one +submits an equivocation proposal in time, or if the proposal doesn't pass.
  • +
+

Neutral

+
    +
  • This feature can't be used for social slashing, because an equivocation +proposal is only accepted if there's a slash log for the related +validator(s), meaning the consumer chain has reported the equivocation to +the provider chain.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html b/v5.0.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html new file mode 100644 index 0000000000..6977214159 --- /dev/null +++ b/v5.0.0/adrs/adr-007-pause-unbonding-on-eqv-prop.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-008-throttle-retries.html b/v5.0.0/adrs/adr-008-throttle-retries.html new file mode 100644 index 0000000000..c3b4032e5c --- /dev/null +++ b/v5.0.0/adrs/adr-008-throttle-retries.html @@ -0,0 +1,133 @@ + + + + + +Throttle with retries | Interchain Security + + + + +
Version: v5.0.0

Throttle with retries

ADR 008: Throttle with retries

+

Changelog

+
    +
  • 6/9/23: Initial draft
  • +
  • 6/22/23: added note on consumer pending packets storage optimization
  • +
  • 7/14/23: Added note on upgrade order
  • +
+

Status

+

Accepted

+

Context

+

For context on why the throttling mechanism exists, see ADR 002.

+

Note the terms slash throttling and jail throttling are synonymous, since in replicated security a SlashPacket simply jails a validator for downtime infractions.

+

Currently the throttling mechanism is designed so that provider logic (slash meter, etc.) dictates how many SlashPackets can be handled over time. +Throttled SlashPackets are persisted on the provider, leading to multiple possible issues. Namely:

+
    +
  • If SlashPackets or VSCMaturedPackets are actually throttled/queued on the provider, state can grow and potentially lead to a DoS attack. +We have short term solutions around this, but overall they come with their own weaknesses. +See #594.
  • +
  • If a jailing attack described in ADR 002 were actually to be carried out with the current throttling design, we'd likely have to halt the provider, and perform an emergency upgrade and/or migration to clear the queues of SlashPackets that were deemed to be malicious. +Alternatively, validators would just have to tough it out and wait for the queues to clear, during which all/most validators would be jailed. +Right after being jailed, validators would have to unjail themselves promptly to ensure safety. +The coordination required to maintain safety in such a scenario is not ideal.
  • +
+

As a solution, we can improve the throttling mechanism to instead queue/persist relevant data on each consumer, and have consumers retry slash requests as needed.

+

Decision

+

Consumer changes

+

Note the consumer already queues up both SlashPackets and VSCMaturedPackets via AppendPendingPacket. +Those packets are dequeued in every EndBlock in SendPackets and sent to the provider.

+

Instead, we will now introduce the following logic on EndBlock:

+
    +
  • Slash packets will always be sent to the provider once they're at the head of the queue. +However, once sent, the consumer will not send any subsequent VSCMaturedPackets from the queue until the provider responds with an acknowledgement that the sent SlashPacket has been handled, i.e., validator was jailed. +That is, SlashPackets block the sending of subsequent VSCMaturedPackets in the consumer queue.
  • +
  • If two SlashPackets are at the head of the queue, the consumer will send the first SlashPacket, and then wait for a success acknowledgement from the provider before sending the second SlashPacket. +This seems like it'd simplify implementation.
  • +
  • VSCMaturedPackets at the head of the queue (i.e., NOT following a SlashPacket) can be sent immediately, and do not block any other packets in the queue, since the provider always handles them immediately.
  • +
+

To prevent the provider from having to keep track of what SlashPackets have been rejected, the consumer will have to retry the sending of SlashPackets over some period of time. +This can be achieved with an on-chain consumer param, i.e., RetryDelayPeriod. +To reduce the amount of redundant re-sends, we recommend setting RetryDelayPeriod ~ SlashMeterReplenishmentPeriod, i.e., waiting for the provider slash meter to be replenished before resending the rejected SlashPacket.

+

Note to prevent weird edge case behavior, a retry would not be attempted until either a success or failure acknowledgement has been received from the provider.

+

With the behavior described, we maintain very similar behavior to the previous throttling mechanism regarding the timing that SlashPackets and VSCMaturedPackets are handled on the provider. +Obviously the queueing and blocking logic is moved, and the two chains would have to send more messages between one another (only in the case the throttling mechanism is triggered).

+

In the normal case, when no or a few SlashPackets are being sent, the VSCMaturedPackets will not be delayed, and hence unbonding will not be delayed.

+

For the implementation of this design, see throttle_retry.go.

+

Consumer pending packets storage optimization

+

In addition to the mentioned consumer changes, an optimization will need to be made to the consumer's pending packets storage to properly implement the feature from this ADR.

+

The consumer ccv module previously queued "pending packets" to be sent in each EndBlock in SendPackets. +These packets are queued in state with a protobuf list of ConsumerPacketData. +For a single append operation, the entire list is deserialized, then a packet is appended to that list, and the list is serialized again. +See older version of AppendPendingPacket. +That is, a single append operation has O(N) complexity, where N is the size of the list.

+

This poor append performance isn't a problem when the pending packets list is small. +But with this ADR being implemented, the pending packets list could potentially grow to the order of thousands of entries when SlashPackets need to be resent.

+

We can improve the append time for this queue by converting it from a protobuf-esq list, to a queue implemented with sdk-esq code. +The idea is to persist a uint64 index that will be incremented each time you queue up a packet. +You can think of this as storing the tail of the queue. +Then, packet data will be keyed by that index, making the data naturally ordered byte-wise for sdk's iterator. +The index will also be stored in the packet data value bytes, so that the index can later be used to delete certain packets from the queue.

+

Two things are achieved with this approach:

+
    +
  • More efficient packet append/enqueue times
  • +
  • The ability to delete select packets from the queue (previously all packets were deleted at once)
  • +
+

Provider changes

+

The main change needed for the provider is the removal of queuing logic for SlashPackets and VSCMaturedPackets upon being received.

+

Instead, the provider will consult the slash meter to determine if a SlashPacket can be handled immediately. +If not, the provider will return an acknowledgement message to the consumer communicating that the SlashPacket could not be handled, and needs to be sent again in the future (retried).

+

VSCMaturedPackets will always be handled immediately upon being received by the provider.

+

Note spec. Specifically the section on VSC Maturity and Slashing Order. Previously the onus was on the provider to maintain this property via queuing packets and handling them FIFO.

+

Now this property will be maintained by the consumer sending packets in the correct order, and blocking the sending of VSCMaturedPackets as needed. Then, the ordered IBC channel will ensure that SlashPackets and VSCMaturedPackets are received in the correct order on the provider.

+

The provider's main responsibility regarding throttling will now be to determine if a received SlashPacket can be handled via slash meter etc., and appropriately acknowledge to the sending consumer.

+

Handling VSCMaturedPackets immediately

+

Why the provider can handle VSCMatured packets immediately

+

A VSCMaturedPacket communicates to the provider that sufficient time passed on the consumer since the corresponding VSCPacket has been applied (on the consumer) such that infractions committed on the consumer could have been submitted.

+

If the consumer is following the queuing/blocking protocol described, then no bad behavior occurs and the VSC Maturity and Slashing Order property is maintained.

+

If a consumer sends VSCMaturedPackets too leniently -- the consumer is malicious and sends duplicate VSCMaturedPackets, or sends the packets sooner than the CCV protocol specifies -- then the provider needs to handle VSCMaturedPackets immediately to prevent DOS, state bloat, or other issues. +The only possible negative outcome is that the malicious consumer may not be able to jail a validator who should have been jailed. +The malicious behavior only creates a negative outcome for the consumer chain that is being malicious.

+

If a consumer blocks the sending of VSCMaturedPackets, then unbonding operations on the provider will be delayed, but only until the VSC timeout period has elapsed. +At that time, the consumer is removed. +Again the malicious behavior only creates a negative outcome for the consumer chain that is being malicious.

+

Splitting of PRs and Upgrade Order

+

This feature will implement consumer changes in #1024.

+

These changes should be deployed to production for all consumers before the provider changes are deployed to production.

+

In other words, the consumer changes in #1024 are compatible with the current ("v1") provider implementation of throttling that's running on the Cosmos Hub as of July 2023.

+

Once all consumers have deployed the changes in #1024, the provider changes from #1321 can be deployed to production, fully enabling v2 throttling.

+

Consequences

+
    +
  • Consumers will now have to manage their own queues, and retry logic.
  • +
  • Consumers still aren't trustless, but the provider is now less susceptible to mismanaged or malicious consumers.
  • +
  • Recovering from the "jailing attack" is more elegant.
  • +
  • Some issues like #1001 will now be handled implicitly by the improved throttling mechanism.
  • +
  • SlashPackets and VSCMaturedPackets can be handled immediately once received by the provider if the slash meter allows.
  • +
  • In general, we reduce the amount of computation that happens in the provider EndBlock.
  • +
+

Positive

+
    +
  • We no longer have to reason about a "global queue" and a "chain specific queue", and keeping those all in-sync. +Now SlashPackets and VSCMaturedPackets queuing is handled on each consumer individually.
  • +
  • Due to the above, the throttling protocol becomes less complex overall.
  • +
  • We no longer have to worry about throttle related DoS attack on the provider, since no queuing exists on the provider.
  • +
+

Negative

+
    +
  • Increased number of IBC packets being relayed anytime throttling logic is triggered.
  • +
  • Consumer complexity increases, since consumers now have manage queuing themselves, and implement packet retry logic.
  • +
+

Neutral

+
    +
  • Core throttling logic on the provider remains unchanged, i.e., slash meter, replenishment cycles, etc.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-008-throttle-retries.html.html b/v5.0.0/adrs/adr-008-throttle-retries.html.html new file mode 100644 index 0000000000..6a83abd026 --- /dev/null +++ b/v5.0.0/adrs/adr-008-throttle-retries.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-009-soft-opt-out.html b/v5.0.0/adrs/adr-009-soft-opt-out.html new file mode 100644 index 0000000000..06640ba8b3 --- /dev/null +++ b/v5.0.0/adrs/adr-009-soft-opt-out.html @@ -0,0 +1,49 @@ + + + + + +Soft Opt-Out | Interchain Security + + + + +
Version: v5.0.0

Soft Opt-Out

ADR 009: Soft Opt-Out

+

Changelog

+
    +
  • 6/13/23: Initial draft of ADR. Feature already implemented and in production.
  • +
+

Status

+

Accepted

+

Context

+

Some small validators may not have the resources needed to validate all consumer chains. Therefore a need exists to allow the bottom x% of validators to opt-out of validating a consumer chain. Meaning downtime infractions for these validators are dropped without ever reaching the provider.

+

This document specifies a modification to the ccv protocol which allows the bottom x% of the validator set by power to opt out of validating consumer chains without being jailed or otherwise punished for it. The feature is implemented with entirely consumer-side code.

+

Decision

+

A consumer param exists, known as SoftOptOutThreshold, which is a string decimal in the range of [0, 0.2], that determines the portion of validators which are allowed to opt out of validating that specific consumer.

+

In every consumer beginblocker, a function is ran which determines the so called smallest non opt-out voting power. Validators with voting power greater than or equal to this value must validate the consumer chain, while validators below this value may opt out of validating the consumer chain.

+

The smallest non opt-out voting power is recomputed every beginblocker in UpdateSmallestNonOptOutPower(). In a nutshell, the method obtains the total voting power of the consumer, iterates through the full valset (ordered power ascending) keeping track of a power sum, and when powerSum / totalPower > SoftOptOutThreshold, the SmallestNonOptOutPower is found and persisted.

+

Then, whenever the Slash() interface is executed on the consumer, if the voting power of the relevant validator being slashed is less than SmallestNonOptOutPower for that block, the slash request is dropped and never sent to the provider.

+

Consequences

+

Positive

+
    +
  • Small validators can opt out of validating specific consumers without being punished for it.
  • +
+

Negative

+
    +
  • The bottom x% is still part of the total voting power of the consumer chain. This means that if the soft opt-out threshold is set to 10% for example, and every validator in the bottom 10% opts out from validating the consumer, then a 24% downtime of the remaining voting power would halt the chain. This may be especially problematic during consumer upgrades.
  • +
  • In nominal scenarios, consumers with soft opt out enabled will be constructing slash packets for small vals, which may be dropped. This is wasted computation, but necessary to keep implementation simple. Note that the sdk's full downtime logic is always executed on the consumer, which can be computationally expensive and slow down certain blocks.
  • +
  • In a consumer chain, when a validator that has opted out becomes the proposer, there will naturally be no proposal made and validators would need to move to the next consensus round for the same height to reach a decision. As a result, we would need more time to finalize blocks on a consumer chain.
  • +
+

Neutral

+
    +
  • Validators in the bottom of the valset who don't have to validate, may receive large delegation(s) which suddenly boost the validator to the subset that has to validate. This may catch the validator off guard.
  • +
+

References

+
    +
  • Original issue with some napkin math #784
  • +
+ + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-009-soft-opt-out.html.html b/v5.0.0/adrs/adr-009-soft-opt-out.html.html new file mode 100644 index 0000000000..ffbf699b66 --- /dev/null +++ b/v5.0.0/adrs/adr-009-soft-opt-out.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-010-standalone-changeover.html b/v5.0.0/adrs/adr-010-standalone-changeover.html new file mode 100644 index 0000000000..74e7d65a38 --- /dev/null +++ b/v5.0.0/adrs/adr-010-standalone-changeover.html @@ -0,0 +1,53 @@ + + + + + +Standalone to Consumer Changeover | Interchain Security + + + + +
Version: v5.0.0

Standalone to Consumer Changeover

ADR 010: Standalone to Consumer Changeover

+

Changelog

+
    +
  • 6/30/23: Feature completed, first draft of ADR.
  • +
+

Status

+

Implemented

+

Context

+

Stride will be the first consumer to "changeover" from a standalone cosmos blockchain, to a consumer chain secured by the Cosmos Hub. This document will outline the changes made to the replicated security protocol to support this changeover process.

+

Decision

+

Process

+

Prior to the changeover, the consumer chain will have an existing staking keeper and validator set, these may be referred to as the "standalone staking keeper" and "standalone validator set" respectively.

+

The first step in the changeover process is to submit a ConsumerAdditionProposal. If the proposal passes, the provider will create a new IBC client for the consumer at spawn time, with the provider's validator set. A consumer genesis will also be constructed by the provider for validators to query. Within this consumer genesis contains the initial validator set for the consumer to apply after the changeover.

+

Next, the standalone consumer chain runs an upgrade which adds the CCV module, and is properly setup to execute changeover logic.

+

The consumer upgrade height must be reached after the provider has created the new IBC client. Any replicated security validators who will run the consumer, but are not a part of the sovereign validator set, must sync up a full node before the consumer upgrade height is reached. The disk state of said full node will be used to run the consumer chain after the changeover has completed.

+

The meat of the changeover logic is that the consumer chain validator set is updated to that which was specified by the provider via the queried consumer genesis. Validators which were a part of the old set, but not the new set, are given zero voting power. Once these validator updates are given to Comet, the set is committed, and in effect 2 blocks later (see FirstConsumerHeight).

+

A relayer then establishes the new IBC connection between the provider and consumer. The CCV channel handshake is started on top of this connection. Once the CCV channel is established and VSC packets are being relayed, the consumer chain is secured by the provider.

+

Changes to CCV Protocol

+
    +
  • Consumer Genesis state is updated to include a PreCCV boolean. When this boolean is set true in the consumer genesis JSON, special logic is executed on InitGenesis to trigger the changeover process on the consumer's first endblocker after the upgrade which adds the CCV module. Note that InitGenesis is not automatically called during chain upgrades, so the consumer must manually call the consumer's InitGenesis method in an upgrade handler.
  • +
  • The ConsumerAdditionProposal type is updated to include a DistributionTransmissionChannel field. This field allows the consumer to use an existing IBC transfer channel to send rewards as a part of the CCV protocol. Consumers that're not changing over from a standalone chain will leave this field blank, indicating that a new transfer channel should be created on top of the same connection as the CCV channel.
  • +
  • The CCV consumer keeper is updated to contain an optional reference to the standalone staking keeper. The standalone staking keeper is used to slash for infractions that happened before the changeover was completed. Ie. any infraction from a block height before the changeover, that is submitted after the changeover, will call the standalone staking keeper's slash method. Note that a changeover consumer's standalone staking keeper becomes a democracy module keeper, so it is possible for a governance token to be slashed.
  • +
+

Consequences

+

Positive

+
    +
  • Existing cosmos chains are now able to onboard over to a consumer chain secured by a provider.
  • +
  • The previous staking keepers for such chains can be transitioned to democracy staking module keepers.
  • +
+

Negative

+
    +
  • The delineation between different types of consumers in this repo becomes less clear. Ie. there is code in the democracy consumer's app.go that only applies to a previously standalone chain, but that file also serves as the base for a normal democracy consumer launched with RS from genesis.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-010-standalone-changeover.html.html b/v5.0.0/adrs/adr-010-standalone-changeover.html.html new file mode 100644 index 0000000000..b12e648e19 --- /dev/null +++ b/v5.0.0/adrs/adr-010-standalone-changeover.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-011-improving-test-confidence.html b/v5.0.0/adrs/adr-011-improving-test-confidence.html new file mode 100644 index 0000000000..e5c1e967d8 --- /dev/null +++ b/v5.0.0/adrs/adr-011-improving-test-confidence.html @@ -0,0 +1,158 @@ + + + + + +Improving testing and increasing confidence | Interchain Security + + + + +
Version: v5.0.0

ADR 011: Improving testing and increasing confidence

+

Changelog

+
    +
  • 2023-08-11: Proposed, first draft of ADR.
  • +
+

Status

+

Proposed

+

Context

+

Testing, QA, and maintenance of interchain-security libraries is an ever-evolving area of software engineering we have to keep incrementally improving. The purpose of the QA process is to catch bugs as early as possible. In an ideal development workflow a bug should never reach production. A bug found in the specification stage is a lot cheaper to resolve than a bug discovered in production (or even in testnet). Ideally, all bugs should be found during the CI execution, and we hope that no bugs will ever even reach the testnet (although nothing can replace actual system stress test under load interacting with users).

+

During development and testnet operation the following types of bugs were the most commonly found:

+
    +
  • improper iterator usage
  • +
  • unbounded array access/iteration
  • +
  • improper input handling and validation
  • +
  • improper cached context usage
  • +
  • non-determinism check (improper use of maps in go, relying on random values)
  • +
  • KV store management and/or how keys are defined
  • +
  • deserialization issues arising from consumer/provider versioning mismatch
  • +
+

Such bugs can be discovered earlier with better tooling. Some of these bugs can induce increases in block times, chain halts, state corruption, or introduce an attack surface which is difficult to remove if other systems have started depending on that behavior.

+

Current state of testing

+

Our testing suites consist of multiple parts, each with their own trade-offs and benefits with regards to code coverage, complexity and confidence they provide.

+

Unit testing

+

Unit testing is employed mostly for testing single-module functionality. It is the first step in testing and often the most practical. While highly important, unit tests often test a single piece of code and don't test relationships between different moving parts, this makes them less valuable when dealing with multi-module interactions.

+

Unit tests often employ mocks to abstract parts of the system that are not under test. Mocks are not equivalent to actual models and should not be treated as such.

+

Out of all the approaches used, unit testing has the most tools available and the coverage can simply be displayed as % of code lines tested. Although this is a very nice and very easy to understand metric, it does not speak about the quality of the test coverage.

+

Since distributed systems testing is a lot more involved, unit tests are oftentimes not sufficient to cover complex interactions. Unit tests are still necessary and helpful, but in cases where unit tests are not helpful e2e or integration tests should be favored.

+

Integration testing

+

With integration testing we test the multi-module interactions while isolating them from the remainder of the system. +Integration tests can uncover bugs that are often missed by unit tests.

+

It is very difficult to gauge the actual test coverage imparted by integration tests and the available tooling is limited. +In interchain-security we employ the ibc-go/testing framework to test interactions in-memory.

+

At present, integration testing does not involve the consensus layer - it is only concerned with application level state and logic.

+

End-to-end testing

+

In our context end-to-end testing comprises of tests that use the actual application binaries in an isolated environment (e.g. docker container). During test execution the inputs are meant to simulate actual user interaction, either by submitting transactions/queries using the command line or using gRPC/REST APIs and checking for state changes after an action has been performed. With this testing strategy we also include the consensus layer in all of our runs. This is the closest we can get to testing user interactions without starting a full testnet.

+

End-to-end testing strategies vary between different teams and projects and we strive to unify our approach to the best of our ability (at least for ICS and gaia).

+

The available tooling does not give us significant (or relevant) line of code coverage information since most of the tools are geared towards analyzing unit tests and simple code branch evaluation.

+

We aim to adapt our best practices by learning from other similar systems and projects such as cosmos-sdk, ibc-go and CometBFT.

+

Decision

+

1. Connect specifications to code and tooling

+

Oftentimes, specifications are disconnected from the development and QA processes. This gives rise to problems where the specification does not reflect the actual state of the system and vice-versa. +Usually specifications are just text files that are rarely used and go unmaintained after a while, resulting in consistency issues and misleading instructions/expectations about system behavior.

+

Decision context and hypothesis

+

Specifications written in a dedicated and executable specification language are easier to maintain than the ones written entirely in text. +Additionally, we can create models based on the specification OR make the model equivalent to a specification.

+

Models do not care about the intricacies of implementation and neither do specifications. Since both models and specifications care about concisely and accurately describing a system (such as a finite state machine), we see a benefit of adding model based tools (such as quint) to our testing and development workflows.

+

Main benefit

+

MBT tooling can be used to generate test traces that can be executed by multiple different testing setups.

+

2. Improve e2e tooling

+

Matrix tests

+

Instead of only running tests against current main branch we should adopt an approach where we also:

+
    +
  • run regression tests against different released software versions (ICS v1 vs v2 vs v3)
  • +
  • run non-determinism tests to uncover issues quickly
  • +
+

Matrix tests can be implemented using CometMock and refactoring our current e2e CI setup.

+

Introducing e2e regression testing

+

This e2e test suite would execute using a cronjob in our CI (nightly, multiple times a day etc.)

+

Briefly, the same set of traces is run against different maintained versions of the software and the main branch. +This would allow us to discover potential issues during development instead of in a testnet scenarios.

+

The most valuable issues that can be discovered in this way are state breaking changes, regressions and version incompatibilities.

+

The setup is illustrated by the image below. +e2e matrix tests

+

This table explains which versions are tested against each other for the same set of test traces:

+
    +
  • ✅ marks a passing test
  • +
  • ❌ marks a failing test
  • +
+
USES: ICS v1 PROVIDERstart chainadd keydelegateundelegateredelegatedowntimeequivocationstop chain
v1 consumer (sdk45,ibc4.3)
v2 consumer (sdk45, ibc4.4)
v3 consumer (sdk47, ibc7)
main consumer
neutron
stride
+

Introducing e2e CometMock tests

+

CometMock is a mock implementation of the CometBFT consensus engine. It supports most operations performed by CometBFT while also being lightweight and relatively easy to use.

+

CometMock tests allow more nuanced control of test scenarios because CometMock can "fool" the blockchain app into thinking that a certain number of blocks had passed. +This allows us to test very nuanced scenarios, difficult edge cases and long-running operations (such as unbonding operations).

+

Examples of tests made easier with CometMock are listed below:

+
    +
  • regression tests
  • +
  • non-determinism tests
  • +
  • upgrade tests
  • +
  • state-breaking changes
  • +
+

With CometMock, the matrix test approach can also be used. The image below illustrates a CometMock setup that can be used to discover non-deterministic behavior and state-breaking changes. +e2e matrix tests

+

This table explains which versions are tested against each other for the same set of test traces:

+
    +
  • ✅ marks a passing test
  • +
  • ❌ marks a failing test
  • +
+
SCENARIOstart chainadd keydelegateundelegateredelegatedowntimeequivocationstop chain
v3 provi + v3 consu
main provi + main consu
commit provi + commit consu
+

Briefly; multiple versions of the application are run against the same CometMock instance and any deviations in app behavior would result in app hash errors (the apps would be in different states after performing the same set of actions).

+

3. Introduce innovative testing approaches

+

When discussing e2e testing, some very important patterns emerge - especially if test traces are used instead of ad-hoc tests written by hand.

+

We see a unique opportunity to clearly identify concerns and modularize the testing architecture.

+

The e2e testing frameworks can be split into a pipeline consisting of 3 parts: model, driver and harness.

+

Model

+

Model is the part of the system that can emulate the behavior of the system under test. +Ideally, it is very close to the specification and is written in a specification language such as quint, TLA+ or similar. +One of the purposes of the model is that it can be used to generate test traces.

+

Driver

+

The purpose of the driver is to accept test traces (generated by the model or written by hand), process them and provide inputs to the next part of the pipeline.

+

Basically, the driver sits between the model and the actual infrastructure on which the test traces are being executed on.

+

Harness

+

Harness is the infrastructure layer of the pipeline that accepts inputs from the driver.

+

There can be multiple harnesses as long as they can perform four things:

+
    +
  • bootstrap a test execution environment (local, docker, k8s…)
  • +
  • accept inputs from drivers
  • +
  • perform the action specified by the driver
  • +
  • report results after performing actions
  • +
+

Consequences

+

The procedure outlined in this ADR is not an all-or-nothing approach. Concepts introduced here do not rely on each other, so this ADR may only be applied partially without negative impact on test coverage and code confidence.

+

Positive

+
    +
  1. introduction of maintainable MBT solutions
  2. +
+
    +
  • improvement over the current "difftest" setup that relies on an opinionated typescript model and go driver
  • +
+
    +
  1. increased code coverage and confidence
  2. +
+
    +
  • using CometMock allows us to run more tests in less time
  • +
  • adding matrix e2e tests allows us to quickly pinpoint differences between code versions
  • +
+

Negative

+

It might be easier to forgo the MBT tooling and instead focus on pure property based testing

+ +

The solutions are potentially expensive if we increase usage of the CI pipeline - this is fixed by running "expensive" tests using a cronjob, instead of running them on every commit.

+

Neutral

+

The process of changing development and testing process is not something that can be thought of and delivered quickly. Luckily, the changes can be rolled out incrementally without impacting existing workflows.

+

References

+
+

Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!

+
+
+ + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-011-improving-test-confidence.html.html b/v5.0.0/adrs/adr-011-improving-test-confidence.html.html new file mode 100644 index 0000000000..8c86e9fa21 --- /dev/null +++ b/v5.0.0/adrs/adr-011-improving-test-confidence.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-012-separate-releasing.html b/v5.0.0/adrs/adr-012-separate-releasing.html new file mode 100644 index 0000000000..7b521c6cd5 --- /dev/null +++ b/v5.0.0/adrs/adr-012-separate-releasing.html @@ -0,0 +1,79 @@ + + + + + +Separate Releasing | Interchain Security + + + + +
Version: v5.0.0

ADR 012: Separate Releasing

+

Changelog

+
    +
  • 0.0202020202020202: Initial draft of idea in #801
  • +
  • 0.01652892561983471: Put idea in this ADR
  • +
  • 0.05: Reject this ADR
  • +
+

Status

+

Rejected

+

Context

+

Spike results

+

I explored the idea of #801 with this spike branch. Here's my conclusions:

+

Splitting this repo to have multiple go.mods is possible. However there are various intricacies involved in decoupling the package hierarchy to have x/ccv/types as the lowest level dep, with x/ccv/consumer and x/ccv/provider being one dep layer above, with high-level tests depending on all three of the mentioned packages. I'd estimate this decoupling would take 2-5 workdays to finish, and require significant review effort.

+

Why go.mod split is not the way to go

+

Let's take a step back and remember the issue we're trying to solve - We need a clean way to decouple semver/releasing for the consumer and provider modules. After more consideration, splitting up go.mods gives us little benefit in achieving this. Reasons:

+
    +
  • The go.mod dependency system is tied to git tags for the entire repo (ex: require github.com/cometbft/cometbft v0.37.2 refers to a historical tag for the entire cometbft repo).
  • +
  • It'd be an odd dev experience to allow modules to reference past releases of other modules in the same repo. When would we ever want the consumer module to reference a past release of the types module for example?
  • +
  • If we allow for go.mod replace statements to build from local source code, why split up the package deps at all?
  • +
  • Splitting go.mods adds a bunch of complexity with go.work files and all that shiz. VSCode does not play well with multiple module repos either.
  • +
+

Why separate repos is cool but also not the way to go

+

All this considered, the cleanest solution to decoupling semver/releasing for the consumer and provider modules would be to have multiple repos, each with their own go.mod (3-4 repos total including high level tests). With this scheme we could separately tag each repo as changes are merged, they could share some code from types being an external dep, etc.

+

I don't think any of us want to split up the monorepo, that's a lot of work and seems like bikeshedding. There's another solution that's very simple..

+

Decision

+

Slightly adapting the current semver ruleset:

+
    +
  • A library API breaking change to EITHER the provider or consumer module will result in an increase of the MAJOR version number for BOTH modules (X.y.z-provider AND X.y.z-consumer).
  • +
  • A state breaking change (change requiring coordinated upgrade and/or state migration) will result in an increase of the MINOR version number for the AFFECTED module(s) (x.Y.z-provider AND/OR x.Y.z-consumer).
  • +
  • Any other changes (including node API breaking changes) will result in an increase of the PATCH version number for the AFFECTED module(s) (x.y.Z-provider AND/OR x.y.Z-consumer).
  • +
+

Example release flow

+

We upgrade main to use a new version of SDK. This is a major version bump, triggering a new release for both the provider and consumer modules, v5.0.0-provider and v5.0.0-consumer.

+
    +
  • A state breaking change is merged to main for the provider module. We release only a v5.1.0-provider off main.
  • +
  • Another state breaking change is merged to main for the provider module. We release only a v5.2.0-provider off main.
  • +
  • At this point, the latest consumer version is still v5.0.0-consumer. We now merge a state breaking change for the consumer module to main, and consequently release v5.1.0-consumer. Note that v5.1.0-consumer is tagged off a LATER commit from main than v5.2.0-provider. This is fine, as the consumer module should not be affected by the provider module's state breaking changes.
  • +
  • Once either module sees a library API breaking change, we bump the major version for both modules. For example, we merge a library API breaking change to main for the provider module. We release v6.0.0-provider and v6.0.0-consumer off main. Note that most often, a library API breaking change will affect both modules simultaneously (example being bumping sdk version).
  • +
+

Consequences

+

Positive

+
    +
  • Consumer repos have clear communication of what tagged versions are relevant to them. Consumer devs should know to never reference an ICS version that starts with provider, even if it'd technically build.
  • +
  • Consumer and provider modules do not deviate as long as we continually release off a shared main branch. Backporting remains relatively unchanged besides being explicit about what module(s) your changes should affect.
  • +
  • No code changes, just changes in process. Very simple.
  • +
+

Negative

+
    +
  • ~~Slightly more complexity.~~Considerably more complex to manage the ICS library. +This is because ICS needs to support multiple versions of SDK (e.g., 0.45, 0.47, 0.50). +In addition, ICS needs to support a special fork of SDK (with LSM included) for the Cosmos Hub. +This means that instead of focusing on main the development team needs to manage multiple release +branches with different dependency trees.
  • +
  • This solution does not allow having provider and consumer on separate versions of e.g. the Cosmos SDK.
  • +
+

Neutral

+

References

+
+

Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!

+
+
+ + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-012-separate-releasing.html.html b/v5.0.0/adrs/adr-012-separate-releasing.html.html new file mode 100644 index 0000000000..593946c3a7 --- /dev/null +++ b/v5.0.0/adrs/adr-012-separate-releasing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-013-equivocation-slashing.html b/v5.0.0/adrs/adr-013-equivocation-slashing.html new file mode 100644 index 0000000000..0754152d7d --- /dev/null +++ b/v5.0.0/adrs/adr-013-equivocation-slashing.html @@ -0,0 +1,103 @@ + + + + + +Slashing on the provider for consumer equivocation | Interchain Security + + + + +
Version: v5.0.0

ADR 013: Slashing on the provider for consumer equivocation

+

Changelog

+
    +
  • 1st Sept. 2023: Initial draft
  • +
+

Status

+

Accepted

+

Context

+

This ADR presents some approaches on how to slash on the provider chain validators that performed equivocations on consumer chains. +Currently, the provider chain can receive and verify evidence of equivocation, but it cannot slash the misbehaving validator.

+

In the remainder of this section, we explain how slashing is performed on a single chain and show why slashing on the provider for equivocation on the consumer is challenging.

+

Note that future versions of the Cosmos SDK, CometBFT, and ibc-go could modify the way we slash, etc. Therefore, a future reader of this ADR, should note that when we refer to Cosmos SDK, CometBFT, and ibc-go we specifically refer to their v0.47, v0.37 and v7.3.0 versions respectively.

+

Single-chain slashing

+

Slashing is implemented across the slashing +and staking modules. +The slashing module's keeper calls the staking module's Slash() method, passing among others, the infractionHeight (i.e., the height when the equivocation occurred), the validator's power at the infraction height, and the slashFactor (currently set to 5% in case of equivocation on the Cosmos Hub).

+

Slashing undelegations and redelegations

+

To slash undelegations, Slash goes through all undelegations and checks whether they started before or after the infraction occurred. If an undelegation started before the infractionHeight, then it is not slashed, otherwise it is slashed by slashFactor.

+

The slashing of redelegations happens in a similar way, meaning that Slash goes through all redelegations and checks whether the redelegations started before or after the infractionHeight.

+

Slashing delegations

+

Besides undelegations and redelegations, the validator's delegations need to also be slashed. +This is performed by deducting the appropriate amount of tokens from the validator. Note that this deduction is computed based on the voting power the misbehaving validator had at the height of the equivocation. As a result of the tokens deduction, +the tokens per share +reduce and hence later on, when delegators undelegate or redelegate, the delegators retrieve back less +tokens, effectively having their tokens slashed. The rationale behind this slashing mechanism, as mentioned in the Cosmos SDK documentation

+
+

[...] is to simplify the accounting around slashing. Rather than iteratively slashing the tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, effectively reducing the value of each issued delegator share.

+
+

This approach of slashing delegations does not utilize the +infractionHeight in any way and hence the following scenario could occur:

+
    +
  1. a validator V performs an equivocation at a height Hi
  2. +
  3. a new delegator D delegates to V after height Hi
  4. +
  5. evidence of the equivocation by validator V is received
  6. +
  7. the tokens of delegator D are slashed
  8. +
+

In the above scenario, delegator D is slashed, even though D's voting power did not contribute to the infraction.

+

Old evidence

+

In the single-chain case, old evidence (e.g., from 3 years ago) is ignored. This is achieved through +CometBFT that ignores old evidence based on the parameters MaxAgeNumBlocks and MaxAgeDuration (see here). +Additionally, note that when the evidence is sent by CometBFT to the application, the evidence is rechecked in the evidence module of Cosmos SDK and if it is old, the evidence is ignored. +In Cosmos Hub, the MaxAgeNumBlocks is set to 1000000 (i.e., ~70 days if we assume we need ~6 sec per block) and MaxAgeDuration is set to 172800000000000 ns (i.e., 2 days). Because of this check, we can easily exclude old evidence.

+

Slashing for equivocation on the consumer

+

In the single-chain case, slashing requires both the infractionHeight and the voting power. +In order to slash on the provider for an equivocation on a consumer, we need to have both the provider's infractionHeight and voting power. +Note that the infractionHeight on the consumer chain must be mapped to a height on the provider chain. +Unless we have a way to find the corresponding infractionHeight and power on the provider chain, we cannot slash for equivocation on the consumer in the same way as we would slash in the single-chain case.

+

The challenge of figuring out the corresponding infractionHeight and power values on the provider chain is due to the following trust assumption:

+
    +
  • We trust the consensus layer and validator set of the consumer chains, but we do not trust the application layer.
  • +
+

As a result, we cannot trust anything that stems from the application state of a consumer chain.

+

Note that when a relayer or a user sends evidence through a MsgSubmitConsumerDoubleVoting message, the provider gets access to DuplicateVoteEvidence:

+
type DuplicateVoteEvidence struct {
VoteA *Vote `json:"vote_a"`
VoteB *Vote `json:"vote_b"`

// abci specific information
TotalVotingPower int64
ValidatorPower int64
Timestamp time.Time
}
+

The "abci specific information" fields cannot be trusted because they are not signed. Therefore, +we can use neither ValidatorPower for slashing on the provider chain, nor the Timestamp to check the evidence age. We can get the infractionHeight from the votes, but this infractionHeight corresponds to the infraction height on the consumer and not on the provider chain. +Similarly, when a relayer or a user sends evidence through a MsgSubmitConsumerMisbehaviour message, the provider gets access to Misbehaviour that we cannot use to extract the infraction height, power, or the time on the provider chain.

+

Proposed solution

+

As a first iteration, we propose the following approach. At the moment the provider receives evidence of equivocation on a consumer:

+
    +
  1. slash all the undelegations and redelegations using slashFactor;
  2. +
  3. slash all delegations using as voting power the sum of the voting power of the misbehaving validator and the power of all the ongoing undelegations and redelegations.
  4. +
+

Evidence expiration: Additionally, because we cannot infer the actual time of the evidence (i.e., the timestamp of the evidence cannot be trusted), we do not consider evidence expiration and hence old evidence is never ignored (e.g., the provider would act on 3 year-old evidence of equivocation on a consumer). +Additionally, we do not need to store equivocation evidence to avoid slashing a validator more than once, because we do not slash tombstoned validators and we tombstone a validator when slashed.

+

We do not act on evidence that was signed by a validator consensus key that is pruned when we receive the evidence. We prune a validator's consensus key if the validator has assigned a new consumer key (using MsgAssignConsumerKey) and an unbonding period on the consumer chain has elapsed (see key assignment ADR). Note that the provider chain is informed that the unbonding period has elapsed on the consumer when the provider receives a VSCMaturedPacket and because of this, if the consumer delays the sending of a VSCMaturedPacket, we would delay the pruning of the key as well.

+

Implementation

+

The following logic needs to be added to the HandleConsumerDoubleVoting and HandleConsumerMisbehaviour methods:

+
undelegationsInTokens := sdk.NewInt(0)
for _, v := range k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validatorAddress) {
for _, entry := range v.Entries {
if entry.IsMature(now) && !entry.OnHold() {
// undelegation no longer eligible for slashing, skip it
continue
}
undelegationsInTokens = undelegationsInTokens.Add(entry.InitialBalance)
}
}

redelegationsInTokens := sdk.NewInt(0)
for _, v := range k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validatorAddress) {
for _, entry := range v.Entries {
if entry.IsMature(now) && !entry.OnHold() {
// redelegation no longer eligible for slashing, skip it
continue
}
redelegationsInTokens = redelegationsInTokens.Add(entry.InitialBalance)
}
}

infractionHeight := 0
undelegationsAndRedelegationsInPower = sdk.TokensToConsensusPower(undelegationsInTokens.Add(redelegationsInTokens))
totalPower := validator's voting power + undelegationsAndRedelegationsInPower
slashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)

k.stakingKeeper.Slash(ctx, validatorConsAddress, infractionHeight, totalPower, slashFraction, DoubleSign)
+

Infraction height: We provide a zero infractionHeight to the Slash method in order to slash all ongoing undelegations and redelegations (see checks in Slash, SlashUnbondingDelegation, and SlashRedelegation).

+

Power: We pass the sum of the voting power of the misbehaving validator when the evidence was received (i.e., at evidence height) and the power of all the ongoing undelegations and redelegations. +If we assume that the slashFactor is 5%, then the voting power we pass is power + totalPower(undelegations) + totalPower(redelegations). +Hence, when the Slash method slashes all the undelegations and redelegations it would end up with 0.05 * power + 0.05 * totalPower(undelegations) + 0.05 * totalPower(redelegations) - 0.05 * totalPower(undelegations) - 0.05 * totalPower(redelegations) = 0.05 * power and hence it would slash 5% of the validator's power when the evidence is received.

+

Positive

+

With the proposed approach we can quickly implement slashing functionality on the provider chain for consumer chain equivocations. +This approach does not need to change the staking module and therefore does not change in any way how slashing is performed today for a single chain.

+

Negative

+
    +
  • We definitely slash more when it comes to undelegations and redelegations because we slash for all of them without considering an infractionHeight.
  • +
  • We potentially slash more than what we would have slashed if we knew the voting power at the corresponding infractionHeight in the provider chain.
  • +
  • We slash on old evidence of equivocation on a consumer.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-013-equivocation-slashing.html.html b/v5.0.0/adrs/adr-013-equivocation-slashing.html.html new file mode 100644 index 0000000000..101dff94f9 --- /dev/null +++ b/v5.0.0/adrs/adr-013-equivocation-slashing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-014-epochs.html b/v5.0.0/adrs/adr-014-epochs.html new file mode 100644 index 0000000000..8749f91177 --- /dev/null +++ b/v5.0.0/adrs/adr-014-epochs.html @@ -0,0 +1,72 @@ + + + + + +Epochs | Interchain Security + + + + +
Version: v5.0.0

ADR 014: Epochs

+

Changelog

+
    +
  • 2024-01-05: Proposed, first draft of ADR.
  • +
  • 2024-02-29: Updated so that it describes the implementation where we store the whole consumer validator set.
  • +
+

Status

+

Proposed

+

Context

+

In every block that the provider valset changes, a VSCPacket must be sent to every consumer and a corresponding VSCMaturedPacket sent back. +Given that the validator powers may change very often on the provider chain (e.g., the Cosmos Hub), this approach results in a large workload for the relayers. +Although the validator powers may change very often, these changes are usually small and have an insignificant impact on the chain's security. +In other words, the valset on the consumers can be slightly outdated without affecting security. +As a matter of fact, this already happens due to relaying delays.

+

As a solution, this ADR introduces the concept of epochs. +An epoch consists of multiple blocks. +The provider sends VSCPackets once per epoch. +A VSCPacket contains all the validator updates that are needed by a consumer chain.

+

Decision

+

The implementation of epochs requires the following changes:

+
    +
  • For each consumer chain, we store the consumer validator set that is currently (i.e., in this epoch) validating the +consumer chain. For each validator in the set we store i) its voting power, and ii) the public key that it is +using on the consumer chain during the current (i.e., ongoing) epoch. +The initial consumer validator set for a chain is set during the creation of the consumer genesis.
  • +
  • We introduce the BlocksPerEpoch param that sets the number of blocks in an epoch. By default, BlocksPerEpoch is +set to be 600 which corresponds to 1 hour, assuming 6 seconds per block. This param can be changed through +a governance proposal. In the provider EndBlock we check BlockHeight() % BlocksPerEpoch() == 0 +to decide when an epoch has ended.
  • +
  • At the end of every epoch, if there were validator set changes on the provider, then for every consumer chain, we +construct a VSCPacket with all the validator updates and add it to the list of PendingVSCPackets. We compute the +validator updates needed by a consumer chain by comparing the stored list of consumer validators with the current +bonded validators on the provider, with something similar to this:
  • +
+
// get the valset that has been validating the consumer chain during this epoch 
currentValidators := GetConsumerValSet(consumerChain)
// generate the validator updates needed to be sent through a `VSCPacket` by comparing the current validators
// in the epoch with the latest bonded validators
valUpdates := DiffValidators(currentValidators, stakingmodule.GetBondedValidators())
// update the current validators set for the upcoming epoch to be the latest bonded validators instead
SetConsumerValSet(stakingmodule.GetBondedValidators())
+

Note that a validator can change its consumer public key for a specific consumer chain an arbitrary amount of times during +a block and during an epoch. Then, when we generate the validator updates in DiffValidators, we have to check whether +the current consumer public key (retrieved by calling GetValidatorConsumerPubKey) is different from the consumer public +key the validator was using in the current epoch.

+

Consequences

+

Positive

+
    +
  • Reduce the cost of relaying.
  • +
  • Reduce the amount of IBC packets needed for ICS.
  • +
  • Simplifies key-assignment code because +we only need to check if the consumer_public_key has been modified since the last epoch to generate an update.
  • +
+

Negative

+
    +
  • Increase the delay in the propagation of validator set changes (but for reasonable epoch lengths on the order of ~hours or less, this is unlikely to be significant).
  • +
+

Neutral

+

N/A

+

References

+
+ + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-014-epochs.html.html b/v5.0.0/adrs/adr-014-epochs.html.html new file mode 100644 index 0000000000..e8555d37fd --- /dev/null +++ b/v5.0.0/adrs/adr-014-epochs.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-015-partial-set-security.html b/v5.0.0/adrs/adr-015-partial-set-security.html new file mode 100644 index 0000000000..b1d6d0256e --- /dev/null +++ b/v5.0.0/adrs/adr-015-partial-set-security.html @@ -0,0 +1,154 @@ + + + + + +Partial Set Security | Interchain Security + + + + +
Version: v5.0.0

ADR 015: Partial Set Security

+

Changelog

+
    +
  • 2024-01-22: Proposed, first draft of ADR.
  • +
+

Status

+

Proposed

+

Context

+

Currently, in Replicated Security, the entire validator set of the provider chain is used to secure consumer chains. There are at least three concerns with this approach. +First, a large number of validators might be forced to validate consumer chains they are not interested in securing. +Second, it is costly for small validators to secure additional chains. This concern is only partially addressed through soft opt-out that allows small validators to opt out from validating consumer chains. +Third and for the above reasons, it is challenging for a new consumer chain to join Replicated Security.

+

As a solution, we present Partial Set Security (PSS). As the name suggests, PSS allows for every consumer chain to be secured by only a subset of the provider validator set. +In what follows we propose the exact steps we need to take to implement PSS. This is a first iteration of PSS, and therefore we present the most minimal solution that make PSS possible.

+

Decision

+

In Replicated Security, all the provider validators have to secure every consumer chain (with the exception of those validators allowed to opt out through the soft opt-out feature).

+

In PSS, we allow validators to opt in and out of validating any given consumer chain. +This has one exception: we introduce a parameter N for each consumer chain and require that the validators in top N% of the provider's voting power have to secure the consumer chain. +Validators outside of the top N% can dynamically opt in if they want to validate on the consumer chain.

+

For example, if a consumer chain has N = 95%, then it ultimately receives the same security it receives today with Replicated Security (with a default SoftOptOutThreshold of 5%). +On the other hand, if a consumer chain has N = 0%, then no validator is forced to validate the chain, but validators can opt in to do so instead.

+

For the remainder of this ADR, we call a consumer chain Top N if it has joined as a Top N chain with N > 0 and Opt In chain otherwise. An Opt In consumer chain is secured only by the validators that have opted in to secure that chain.

+

We intend to implement PSS using a feature branch off v4.0.0 interchain security.

+

How do consumer chains join?

+

As a simplification and to avoid chain id squatting, a consumer chain can only join PSS through a governance proposal and not in a permissionless way.

+

However, this proposal type will be modified so that it requires a lower quorum percentage than normal proposal, and every validator who voted "YES" on the proposal will form the consumer chain's initial validator set.

+

Consumer chains join PSS the same way chains now join Replicated Security, namely through a ConsumerAdditionProposal proposal. +We extend ConsumerAdditionProposal with one optional field:

+

uint32 top_N: Corresponds to the percentage of validators that join under the Top N case. +For example, 53 corresponds to a Top 53% chain, meaning that the top 53% provider validators have to validate the proposed consumer chain. +top_N can be 0 or include any value in [50, 100]. A chain can join with top_N == 0 as an Opt In, or with top_N ∈ [50, 100] as a Top N chain.

+

In case of a Top N chain, we restrict the possible values of top_N from (0, 100] to [50, 100]. +By having top_N >= 50 we can guarantee that we cannot have a successful attack, assuming that at most 1/3 of provider validators can be malicious. +This is because, a Top N chain with N >= 50% would have at least 1/3 honest validators, which is sufficient to stop attacks. +Additionally, by having N >= 50% (and hence N > (VetoThreshold = 33.4%)) we enable the top N validators to Veto any ConsumerAdditionProposal for consumer chains they do not want to validate.

+

If a proposal has the top_N argument wrongly set, it should get rejected in [ValidateBasic] (https://github.com/cosmos/interchain-security/blob/v4.0.0/x/ccv/provider/types/proposal.go#L86).

+

In the code, we distinguish whether a chain is Top N or Opt In by checking whether top_N is zero or not.

+

In a future version of PSS, we intend to introduce a ConsumerModificationProposal so that we can modify the parameters of a consumer chain, e.g, a chain that is Opt In to become Top N, etc.

+

State & Query

+

We augment the provider module’s state to keep track of the top_N value for each consumer chain. The key to store this information would be:

+
topNBytePrefix | len(chainID) | chainID
+

To create the above key, we can use ChainIdWithLenKey.

+

Then in the keeper we introduce methods as follows:

+
func (k Keeper) SetTopN(ctx sdk.Context, chainID string, topN uint32)
func (k Keeper) IsTopN(ctx sdk.Context, chainID string) bool
func (k Keeper) IsOptIn(ctx sdk.Context, chainID string) bool

// returns the N if Top N chain, otherwise an error
func (k Keeper) GetTopN(ctx sdk.Context, chainID string) (uint32, error)
+

We also extend the interchain-security-pd query provider list-consumer-chains query to return information on whether a consumer chain is an Opt In or a Top N chain and with what N. +This way, block explorers can present informative messages such as "This chain is secured by N% of the provider chain" for consumer chains.

+

How do validators opt in?

+

A validator can opt in by sending a new type of message that we introduce in tx.proto.

+
message MsgOptIn {
// the chain id of the consumer chain to opt in to
string chainID = 1;
// the provider address of the validator
string providerAddr = 2;
// (optional) the consensus public key to use on the consumer
optional string consumerKey = 3;
}
+

Note that in a Top N consumer chain, the top N% provider validators have to validate the consumer chain. +Nevertheless, validators in the bottom (100 - N)% can opt in to validate as well. +Provider validators that belong or enter the top N% validators are automatically opted in to validate a Top N consumer chain. +This means that if a validator V belongs to the top N% validators but later falls (e.g., due to undelegations) to the bottom (100 - N)%, V is still considered opted in and has to validate unless V sends a MsgOptOut message (see below). +By automatically opting in validators when they enter the top N% validators and by forcing top N% validators to explicitly opt out in case they fall to the (100 - N)% bottom validators we simplify the design of PSS.

+

Note that a validator can send a MsgOptIn message even if the consumer chain is not yet running. To do this we reuse the IsConsumerProposedOrRegistered. If the chainID does not exist, the MsgOptIn should fail, as well as if the provider address does not exist.

+

Optionally, a validator that opts in can provide a consumerKey so that it assigns a different consumer key (from the provider) to the consumer chain. +Naturally, a validator can always change the consumer key on a consumer chain by sending a MsgAssignConsumerKey message at a later point in time, as is done in Replicated Security.

+

State & Query

+

For each validator, we store a pair (blockHeight, isOptedIn) that contains the block height the validator opted in and whether the validator is currently opted in or not, under the key:

+
optedInBytePrefix | len(chainID) | chainID | addr
+

By using a prefix iterator on optedInBytePrefix | len(chainID) | chainID we retrieve all the opted in validators.

+

We introduce the following Keeper methods.

+
// returns all the validators that have opted in on chain `chainID`
func (k Keeper) GetOptedInValidators(ctx sdk.Context, chainID string) []Validators

func (k Keeper) IsValidatorOptedIn(ctx sdk.Context, chainID string, val Validator) bool
+

We introduce the following two queries:

+
interchain-security-pd query provider optedInValidators $chainID
interchain-security-pd query provider hasToValidate $providerAddr
+

One query to retrieve the validators that are opted in and hence the validators that need to validate the consumer chain and one query that given a validator's address returns all the chains this validator has to validate.

+

When do validators opt in?

+

As described earlier, validators can manually opt in by sending a MsgOptIn message. +Additionally, in a Top N chain, a validator is automatically opted in when it moves from the bottom (100 - N)% to the top N% validators.

+

Lastly, validators can also opt in if they vote Yes during the ConsumerAdditionProposal that introduces a consumer chain. +This simplifies validators operations because they do not have to send an additional message to opt in.

+

Because the Tally method deletes the votes after reading them, we cannot check the votes of the validators after the votes have been tallied. +To circumvent this, we introduce a hook for AfterProposalVote and keep track of all the votes cast by a validator. +If a validator casts more than one vote, we only consider the latest vote. +Finally, we only consider a validator has opted in if it casts a 100% Yes vote in case of a weighted vote.

+

How do validators opt out?

+

Validators that have opted in on a chain can opt out by sending the following message:

+
message MsgOptOut {
// the chain id of the consumer chain to opt out from
string chainID = 1;
// the provider address of the validator
string providerAddr = 2;
}
+

Validators can only opt out after a consumer chain has started and hence the above message returns an error if the chain with chainID is not running. +Additionally, a validator that belongs to the top N% validators cannot opt out from a Top N chain and hence a MsgOptOut would error in such a case.

+

State & Query

+

We also update the state of the opted-in validators when a validator has opted out by removing the opted-out validator.

+

Note that only opted-in validators can be punished for downtime on a consumer chain. +For this, we use historical info of all the validators that have opted in; We can examine the blockHeight stored under the key optedInBytePrefix | len(chainID) | chainID | addr to see if a validator was opted in. +This way we can jail validators for downtime knowing that indeed the validators have opted in at some point in the past. +Otherwise, we can think of a scenario where a validator V is down for a period of time, but before V gets punished for downtime, validator V opts out, and then we do not know whether V should be punished or not.

+

When does a consumer chain start?

+

A Top N consumer chain always starts at the specified date (spawn_time) if the ConsumerAdditionProposal has passed. +An Opt In consumer chain only starts if at least one validator has opted in. We check this in BeginBlockInit:

+
func (k Keeper) BeginBlockInit(ctx sdk.Context) {
propsToExecute := k.GetConsumerAdditionPropsToExecute(ctx)

for _, prop := range propsToExecute {
chainID := prop.ChainId
if !k.IsTopN(ctx, chainID) && len(k.GetOptedInValidators(ctx, chainID)) == 0 {
// drop the proposal
ctx.Logger().Info("could not start chain because no validator has opted in")
continue
}
...
+

How do we send the partial validator sets to the consumer chains?

+

A consumer chain should only be validated by opted in validators. +We introduce logic to do this when we queue the VSCPackets. +The logic behind this, is not as straightforward as it seems because CometBFT does not receive the validator set that has to validate a chain, but rather a delta of validator updates. +For example, to remove an opted-out validator from a consumer chain, we have to send a validator update with a power of 0, similarly to what is done in the assignment of consumer keys. +We intend to update this ADR at a later stage on how exactly we intend to implement this logic.

+

How do we distribute rewards?

+

Currently, rewards are distributed as follows: The consumer periodically sends rewards on the provider ConsumerRewardsPool address. +The provider then transfers those rewards to the fee collector address and those transferred rewards are distributed to validators and delegators.

+

In PSS, we distribute rewards only to validators that actually validate the consumer chain. +To do this, we have a pool associated with each consumer chain and consumers IBC transfer the rewards to this pool. +We then extract the rewards from each consumer pool and distribute them to the opted in validators.

+

Note that we only distribute rewards to validators that have been opted in for some time (e.g., 10000 blocks) to avoid cases where validators opt in just to receive rewards and then opt out immediately afterward.

+

Misbehaviour

+

Fraud votes

+

In an Opt In chain, a set of validators might attempt to perform an attack. To deter such potential attacks, PSS allows for the use of fraud votes. +A fraud vote is a governance proposal that enables the slashing of validators that performed an attack. +Due to their inherent complexity, we intend to introduce fraud votes in a different ADR and at a future iteration of PSS.

+

Double signing

+

We do not change the way slashing for double signing and light client attacks functions. +If a validator misbehaves on a consumer, then we slash that validator on the provider.

+

Downtime

+

We do not change the way downtime jailing functions. +If a validator is down on a consumer chain for an adequate amount of time, we jail this validator on the provider but only if the validator was opted in on this consumer chain in the recent past.

+

Consequences

+

Positive

+
    +
  • +

    Easier for new consumer chains to consume the provider's chain economic security because proposals are more likely to pass if not everyone is forced to validate.

    +
  • +
  • +

    Smaller validators are not forced to validate chains anymore if they do not want to.

    +
  • +
  • +

    We can deprecate the soft opt-out implementation.

    +
  • +
+

Negative

+
    +
  • A consumer chain does not receive the same economic security as with Replicated Security (assuming the value of SoftOptOutThreshold is 5%), unless it is a Top N chain with N >= 95%.
  • +
+

References

+
+ + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-015-partial-set-security.html.html b/v5.0.0/adrs/adr-015-partial-set-security.html.html new file mode 100644 index 0000000000..9d40cbd647 --- /dev/null +++ b/v5.0.0/adrs/adr-015-partial-set-security.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-template.html b/v5.0.0/adrs/adr-template.html new file mode 100644 index 0000000000..657b53731d --- /dev/null +++ b/v5.0.0/adrs/adr-template.html @@ -0,0 +1,50 @@ + + + + + +ADR Template | Interchain Security + + + + +
Version: v5.0.0

ADR [ADR-NUMBER]: [TITLE]

+

Changelog

+
    +
  • +
+

Status

+
+

A decision may be "proposed" if it hasn't been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement.

+
+

[Deprecated|Proposed|Accepted]

+

Context

+
+

This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution.

+
+

Decision

+
+

This section explains all of the details of the proposed solution, including implementation details. +It should also describe affects / corollary items that may need to be changed as a part of this. +If the proposed change will be large, please also indicate a way to do the change to maximize ease of review. +(e.g. the optimal split of things to do between separate PR's)

+
+

Consequences

+
+

This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones.

+
+

Positive

+

Negative

+

Neutral

+

References

+
+

Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!

+
+
    +
  • [references]
  • +
+ + \ No newline at end of file diff --git a/v5.0.0/adrs/adr-template.html.html b/v5.0.0/adrs/adr-template.html.html new file mode 100644 index 0000000000..646ae1a8c0 --- /dev/null +++ b/v5.0.0/adrs/adr-template.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/adrs/intro.html b/v5.0.0/adrs/intro.html new file mode 100644 index 0000000000..ff0a3fe49c --- /dev/null +++ b/v5.0.0/adrs/intro.html @@ -0,0 +1,60 @@ + + + + + +ADRs | Interchain Security + + + + +
Version: v5.0.0

Architecture Decision Records (ADR)

+

This is a location to record all high-level architecture decisions in the Interchain Security project.

+

You can read more about the ADR concept in this blog post.

+

An ADR should provide:

+
    +
  • Context on the relevant goals and the current state
  • +
  • Proposed changes to achieve the goals
  • +
  • Summary of pros and cons
  • +
  • References
  • +
  • Changelog
  • +
+

Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and +justification for a change in architecture, or for the architecture of something +new. The spec is much more compressed and streamlined summary of everything as +it is or should be.

+

If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match.

+

Note the context/background should be written in the present tense.

+

To suggest an ADR, please make use of the ADR template provided.

+

Table of Contents

+

Accepted

+ +

Proposed

+ +

Rejected

+ +

Deprecated

+
+ + \ No newline at end of file diff --git a/v5.0.0/adrs/intro.html.html b/v5.0.0/adrs/intro.html.html new file mode 100644 index 0000000000..9e09fd55f3 --- /dev/null +++ b/v5.0.0/adrs/intro.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/consumer-development/app-integration.html b/v5.0.0/consumer-development/app-integration.html new file mode 100644 index 0000000000..3da74b6763 --- /dev/null +++ b/v5.0.0/consumer-development/app-integration.html @@ -0,0 +1,32 @@ + + + + + +Developing an ICS consumer chain | Interchain Security + + + + +
Version: v5.0.0

Developing an ICS consumer chain

+

When developing an ICS consumer chain, besides just focusing on your chain's logic you should aim to allocate time to ensure that your chain is compatible with the ICS protocol. +To help you on your journey, the ICS team has provided multiple examples of a minimum viable consumer chain applications.

+

Basic consumer chain

+

The source code for the example app can be found here.

+

Please note that consumer chains do not implement the staking module - the validator set is replicated from the provider, meaning that the provider and the consumer use the same validator set and their stake on the provider directly determines their stake on the consumer. +At present there is no opt-in mechanism available, so all validators of the provider must also validate on the provider chain.

+

Your chain should import the consumer module from x/consumer and register it in the correct places in your app.go. +The x/consumer module will allow your chain to communicate with the provider using the ICS protocol. The module handles all IBC communication with the provider, and it is a simple drop-in. +You should not need to manage or override any code from the x/consumer module.

+

Democracy consumer chain

+

The source code for the example app can be found here.

+

This type of consumer chain wraps the basic CosmosSDK x/distribution, x/staking and x/governance modules allowing the consumer chain to perform democratic actions such as participating and voting within the chain's governance system.

+

This allows the consumer chain to leverage those modules while also using the x/consumer module.

+

With these modules enabled, the consumer chain can mint its own governance tokens, which can then be delegated to prominent community members which are referred to as "representatives" (as opposed to "validators" in standalone chains). The token may have different use cases besides just voting on governance proposals.

+

Standalone chain to consumer chain changeover

+

This feature is being actively worked on. Information will be provided at a later time.

+ + \ No newline at end of file diff --git a/v5.0.0/consumer-development/app-integration.html.html b/v5.0.0/consumer-development/app-integration.html.html new file mode 100644 index 0000000000..2346a78e94 --- /dev/null +++ b/v5.0.0/consumer-development/app-integration.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/consumer-development/changeover-procedure.html b/v5.0.0/consumer-development/changeover-procedure.html new file mode 100644 index 0000000000..51fd0be489 --- /dev/null +++ b/v5.0.0/consumer-development/changeover-procedure.html @@ -0,0 +1,136 @@ + + + + + +Changeover Procedure | Interchain Security + + + + +
Version: v5.0.0

Changeover Procedure

+

Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.

+

The relevant protocol specifications are available below:

+ +

Overview

+

Standalone to consumer changeover procedure can roughly be separated into 4 parts:

+

1. ConsumerAddition proposal submitted to the provider chain

+

The proposal is equivalent to the "normal" ConsumerAddition proposal submitted by new consumer chains.

+

However, here are the most important notes and differences between a new consumer chain and a standalone chain performing a changeover:

+
    +
  • chain_id must be equal to the standalone chain id
  • +
  • initial_height field has additional rules to abide by:
  • +
+
caution
{
...
"initial_height" : {
// must correspond to current revision number of standalone chain
// e.g. stride-1 => "revision_number": 1
"revision_number": 1,

// must correspond to a height that is at least 1 block after the upgrade
// that will add the `consumer` module to the standalone chain
// e.g. "upgrade_height": 100 => "revision_height": 101
"revision_height": 1,
},
...
}

RevisionNumber: 0, RevisionHeight: 111

+
    +
  • +

    genesis_hash can be safely ignored because the chain is already running. A hash of the standalone chain's initial genesis may be used

    +
  • +
  • +

    binary_hash may not be available ahead of time. All chains performing the changeover go through rigorous testing - if bugs are caught and fixed the hash listed in the proposal may not be the most recent one.

    +
  • +
  • +

    spawn_time listed in the proposal MUST be before the upgrade_height listed in the upgrade proposal on the standalone chain.

    +
  • +
+
caution

spawn_time must occur before the upgrade_height on the standalone chain is reached because the provider chain must generate the ConsumerGenesis that contains the validator set that will be used after the changeover.

+
    +
  • +

    unbonding_period must correspond to the value used on the standalone chain. Otherwise, the clients used for the ccv protocol may be incorrectly initialized.

    +
  • +
  • +

    distribution_transmission_channel should be set.

    +
  • +
+
note

Populating distribution_transmission_channel will enable the standalone chain to reuse one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ibc denom that may already be in use.

If the parameter is not set, a new channel will be created.

+
    +
  • +

    ccv_timeout_period has no important notes

    +
  • +
  • +

    transfer_timeout_period has no important notes

    +
  • +
  • +

    consumer_redistribution_fraction has no important notes

    +
  • +
  • +

    blocks_per_distribution_transmission has no important notes

    +
  • +
  • +

    historical_entries has no important notes

    +
  • +
+

2. upgrade proposal on standalone chain

+

The standalone chain creates an upgrade proposal to include the interchain-security/x/ccv/consumer module.

+
caution

The upgrade height in the proposal should correspond to a height that is after the spawn_time in the consumer addition proposal submitted to the provider chain.

+

Otherwise, the upgrade is indistinguishable from a regular on-chain upgrade proposal.

+

3. spawn time is reached

+

When the spawn_time is reached on the provider it will generate a ConsumerGenesis that contains the validator set that will supersede the standalone validator set.

+

This ConsumerGenesis must be available on the standalone chain during the on-chain upgrade.

+

4. standalone chain upgrade

+

Performing the on-chain upgrade on the standalone chain will add the ccv/consumer module and allow the chain to become a consumer of replicated security.

+
caution

The ConsumerGenesis must be exported to a file and placed in the correct folder on the standalone chain before the upgrade.

The file must be placed at the exact specified location, otherwise the upgrade will not be executed correctly.

Usually the file is placed in $NODE_HOME/config, but the file name and the exact directory is dictated by the upgrade code on the standalone chain.

    +
  • please check exact instructions provided by the standalone chain team
  • +
+

After the genesis.json file has been made available, the process is equivalent to a normal on-chain upgrade. The standalone validator set will sign the next couple of blocks before transferring control to provider validator set.

+

The standalone validator set can still be slashed for any infractions if evidence is submitted within the unboding_period.

+

Notes

+

The changeover procedure may be updated in the future to create a seamless way of providing the validator set information to the standalone chain.

+

Onboarding Checklist

+

This onboarding checklist is slightly different from the one under Onboarding

+

Additionally, you can check the testnet repo for a comprehensive guide on preparing and launching consumer chains.

+

1. Complete testing & integration

+
    +
  • test integration with gaia
  • +
  • test your protocol with supported relayer versions (minimum hermes 1.4.1)
  • +
  • test the changeover procedure
  • +
  • reach out to the ICS team if you are facing issues
  • +
+

2. Create an Onboarding Repository

+

To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain.

+

This should include (at minimum):

+
    +
  • genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see Transform Consumer Genesis)
  • +
  • information about relevant seed/peer nodes you are running
  • +
  • relayer information (compatible versions)
  • +
  • copy of your governance proposal (as JSON)
  • +
  • a script showing how to start your chain and connect to peers (optional)
  • +
  • take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable
  • +
+

Example of such a repository can be found here.

+

3. Submit a ConsumerChainAddition Governance Proposal to the provider

+

Before you submit a ConsumerChainAddition proposal, please provide a spawn_time that is before the upgrade_height of the upgrade that will introduce the ccv module to your chain.

+
danger

If the spawn_time happens after your upgrade_height the provider will not be able to communicate the new validator set to be used after the changeover.

+

Additionally, reach out to the community via the forum to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers.

+
    +
  • determine your chain's spawn time
  • +
  • determine consumer chain parameters to be put in the proposal
  • +
  • take note to include a link to your onboarding repository
  • +
+

Example of a consumer chain addition proposal.

+
// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain or add a standalone chain.
// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.
// It is recommended that spawn time occurs after the proposal end time and that it is scheduled to happen before the standalone chain upgrade
// that sill introduce the ccv module.
{
// Title of the proposal
"title": "Changeover Standalone chain",
// Description of the proposal
// format the text as a .md file and include the file in your onboarding repository
"description": ".md description of your chain and all other relevant information",
// Proposed chain-id of the new consumer chain.
// Must be unique from all other consumer chain ids of the executing provider chain.
"chain_id": "standalone-1",
// Initial height of new consumer chain.
// For a completely new chain, this will be {0,1}.
"initial_height" : {
// must correspond to current revision number of standalone chain
// e.g. standalone-1 => "revision_number": 1
"revision_number": 1,

// must correspond to a height that is at least 1 block after the upgrade
// that will add the `consumer` module to the standalone chain
// e.g. "upgrade_height": 100 => "revision_height": 101
"revision_number": 1,
},
// Hash of the consumer chain genesis state without the consumer CCV module genesis params.
// => not relevant for changeover procedure
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
// Hash of the consumer chain binary that should be run by validators on standalone chain upgrade
// => not relevant for changeover procedure as it may become stale
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
// Unbonding period for the consumer chain.
// It should should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
// IBC transfer packets will timeout after this interval elapses.
"transfer_timeout_period": 1800000000000,
// The fraction of tokens allocated to the consumer redistribution address during distribution events.
// The fraction is a string representing a decimal number. For example "0.75" would represent 75%.
// The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.
"consumer_redistribution_fraction": "0.75",
// BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.
// eg. send rewards to the provider every 1000 blocks
"blocks_per_distribution_transmission": 1000,
// The number of historical info entries to persist in store.
// This param is a part of the cosmos sdk staking module. In the case of
// a ccv enabled consumer chain, the ccv module acts as the staking module.
"historical_entries": 10000,
// The ID of a token transfer channel used for the Reward Distribution
// sub-protocol. If DistributionTransmissionChannel == "", a new transfer
// channel is created on top of the same connection as the CCV channel.
// Note that transfer_channel_id is the ID of the channel end on the consumer chain.
// it is most relevant for chains performing a standalone to consumer changeover
// in order to maintain the existing ibc transfer channel
"distribution_transmission_channel": "channel-123" // NOTE: use existing transfer channel if available
}
+

3. Submit an Upgrade Proposal & Prepare for Changeover

+

This proposal should add the ccv consumer module to your chain.

+
    +
  • proposal upgrade_height must happen after spawn_time in the ConsumerAdditionProposal
  • +
  • advise validators about the exact procedure for your chain and point them to your onboarding repository
  • +
+

4. Upgrade time 🚀

+
    +
  • after spawn_time, request ConsumerGenesis from the provider and place it in <CURRENT_USER_HOME_DIR>/.sovereign/config/genesis.json
  • +
  • upgrade the binary to the one listed in your UpgradeProposal
  • +
+

The chain starts after at least 66.67% of standalone voting power comes online. The consumer chain is considered interchain secured once the "old" validator set signs a couple of blocks and transfers control to the provider validator set.

+
    +
  • provide a repo with onboarding instructions for validators (it should already be listed in the proposal)
  • +
  • genesis.json after spawn_time obtained from provider (MUST contain the initial validator set)
  • +
  • maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)
  • +
+ + \ No newline at end of file diff --git a/v5.0.0/consumer-development/changeover-procedure.html.html b/v5.0.0/consumer-development/changeover-procedure.html.html new file mode 100644 index 0000000000..3931b07ad5 --- /dev/null +++ b/v5.0.0/consumer-development/changeover-procedure.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/consumer-development/consumer-chain-governance.html b/v5.0.0/consumer-development/consumer-chain-governance.html new file mode 100644 index 0000000000..55d159d4f4 --- /dev/null +++ b/v5.0.0/consumer-development/consumer-chain-governance.html @@ -0,0 +1,26 @@ + + + + + +Consumer Chain Governance | Interchain Security + + + + +
Version: v5.0.0

Consumer Chain Governance

+

Different consumer chains can do governance in different ways. However, no matter what the governance method is, there are a few settings specifically related to consensus that consumer chain governance cannot change. We'll cover what these are in the "Whitelist" section below.

+

Democracy module

+

The democracy module provides a governance experience identical to what exists on a standalone Cosmos chain, with one small but important difference. On a standalone Cosmos chain validators can act as representatives for their delegators by voting with their stake, but only if the delegator themselves does not vote. This is a lightweight form of liquid democracy.

+

Using the democracy module on a consumer chain is the exact same experience, except for the fact that it is not the actual validator set of the chain (since it is a consumer chain, these are the Cosmos Hub validators) acting as representatives. Instead, there is a separate representative role who token holders can delegate to and who can perform the functions that validators do in Cosmos governance, without participating in proof of stake consensus.

+

For an example, see the Democracy Consumer

+

CosmWasm

+

There are several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain.

+

For an example, see Neutron.

+

The Whitelist

+

Not everything on a consumer chain can be changed by the consumer's governance. Some settings having to do with consensus etc. can only be changed by the provider chain. Consumer chains include a whitelist of parameters that are allowed to be changed by the consumer chain governance. For an example, see Neutron's whitelist.

+ + \ No newline at end of file diff --git a/v5.0.0/consumer-development/consumer-chain-governance.html.html b/v5.0.0/consumer-development/consumer-chain-governance.html.html new file mode 100644 index 0000000000..2a7b30aa42 --- /dev/null +++ b/v5.0.0/consumer-development/consumer-chain-governance.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/consumer-development/consumer-genesis-transformation.html b/v5.0.0/consumer-development/consumer-genesis-transformation.html new file mode 100644 index 0000000000..f8bbf61e63 --- /dev/null +++ b/v5.0.0/consumer-development/consumer-genesis-transformation.html @@ -0,0 +1,41 @@ + + + + + +Consumer Genesis Transformation | Interchain Security + + + + +
Version: v5.0.0

Consumer Genesis Transformation

+

Preparing a consumer chain for onboarding requires some information explaining how to run your chain. This includes a genesis file with CCV data where the CCV data is exported from the provider chain and added to the consumers genesis file (for more details check the documentation on Onboarding and Changeover). +In case that the provider chain is running an older version of the InterChainSecurity (ICS) module than the consumer chain - or vice versa - the exported CCV data might need to be transformed to the format supported by the ICS implementation run on the consumer chain. This is the case if the consumer chain runs version 4 of ICS or later and the provider is running version 3 or older of the ICS module.

+

Check the compatibility notes for known incompatibilities between provider and consumer versions and indications if a consumer genesis transformation is required.

+

To transform such CCV data follow the instructions below

+

1. Prerequisite

+
    +
  • used provider and consumer versions require transformation step as indicated in in the compatibility notes
  • +
  • interchain-security-cd application supports the versions used by the consumer and provider
  • +
+

2. Export the CCV data

+

Export the CCV data from the provider chain as described in the Onboarding and Changeover your following. +As a result the CCV data will be stored in a file in JSON format.

+

3. Transform CCV data

+

To transform the CCV data

+
    +
  • to the format supported by the current version of the consumer run the following command: +
    interchain-security-cd genesis transform [genesis-file]
    +where 'genesis-file' is the path to the file containing the CCV data exported in step 2. +As a result the CCV data in the new format will be written to standard output.
  • +
  • a specific target version of a consumer run the following command: +
    interchain-security-cd genesis transform --to <target_version> [genesis-file]

    +where <target_version is the ICS version the consumer chain is running. +Use interchain-security-cd genesis transform --help to get more details about supported target versions and more.
  • +
+

Use the new CCV data as described in the procedure you're following.

+ + \ No newline at end of file diff --git a/v5.0.0/consumer-development/consumer-genesis-transformation.html.html b/v5.0.0/consumer-development/consumer-genesis-transformation.html.html new file mode 100644 index 0000000000..4b38b1c9b4 --- /dev/null +++ b/v5.0.0/consumer-development/consumer-genesis-transformation.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/consumer-development/offboarding.html b/v5.0.0/consumer-development/offboarding.html new file mode 100644 index 0000000000..b857fe32e9 --- /dev/null +++ b/v5.0.0/consumer-development/offboarding.html @@ -0,0 +1,19 @@ + + + + + +Offboarding Checklist | Interchain Security + + + + +
Version: v5.0.0

Consumer Offboarding

+

To offboard a consumer chain simply submit a ConsumerRemovalProposal governance proposal listing a stop_time. After stop time passes, the provider chain will remove the chain from the ICS protocol (it will stop sending validator set updates).

+
// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain.
// If it passes, all the consumer chain's state is removed from the provider chain. The outstanding unbonding
// operation funds are released.
{
// the title of the proposal
"title": "This was a great chain",
"description": "Here is a .md formatted string specifying removal details",
// the chain-id of the consumer chain to be stopped
"chain_id": "consumerchain-1",
// the time on the provider chain at which all validators are responsible to stop their consumer chain validator node
"stop_time": "2023-03-07T12:40:00.000000Z",
}
+

More information will be listed in a future version of this document.

+ + \ No newline at end of file diff --git a/v5.0.0/consumer-development/offboarding.html.html b/v5.0.0/consumer-development/offboarding.html.html new file mode 100644 index 0000000000..85aa21a41d --- /dev/null +++ b/v5.0.0/consumer-development/offboarding.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/consumer-development/onboarding.html b/v5.0.0/consumer-development/onboarding.html new file mode 100644 index 0000000000..5cb7124842 --- /dev/null +++ b/v5.0.0/consumer-development/onboarding.html @@ -0,0 +1,57 @@ + + + + + +Onboarding Checklist | Interchain Security + + + + +
Version: v5.0.0

Consumer Onboarding Checklist

+

The following checklists will aid in onboarding a new consumer chain to interchain security.

+

Additionally, you can check the testnet repo for a comprehensive guide on preparing and launching consumer chains.

+

1. Complete testing & integration

+
    +
  • test integration with gaia
  • +
  • test your protocol with supported relayer versions (minimum hermes 1.4.1)
  • +
  • reach out to the ICS team if you are facing issues
  • +
+

2. Create an Onboarding Repository

+

To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain.

+

This should include (at minimum):

+
    +
  • genesis.json without CCV data (before the proposal passes)
  • +
  • genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see Transform Consumer Genesis)
  • +
  • information about relevant seed/peer nodes you are running
  • +
  • relayer information (compatible versions)
  • +
  • copy of your governance proposal (as JSON)
  • +
  • a script showing how to start your chain and connect to peers (optional)
  • +
  • take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable
  • +
+

Example of such a repository can be found here.

+

3. Submit a Governance Proposal

+

Before you submit a ConsumerChainAddition proposal, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch. +If possible, please set your spawn time so people from different parts of the globe can be available in case of emergencies. Ideally, you should set your spawn time to be between 12:00 UTC and 20:00 UTC so most validator operators are available and ready to respond to any issues.

+

Additionally, reach out to the community via the forum to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers.

+
    +
  • determine your chain's spawn time
  • +
  • determine consumer chain parameters to be put in the proposal
  • +
  • take note to include a link to your onboarding repository
  • +
  • describe the purpose and benefits of running your chain
  • +
+

Example of a consumer chain addition proposal.

+
// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain.
// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time.
// It is recommended that spawn time occurs after the proposal end time.
{
// Title of the proposal
"title": "Add consumer chain",
// Description of the proposal
// format the text as a .md file and include the file in your onboarding repository
"description": ".md description of your chain and all other relevant information",
// Proposed chain-id of the new consumer chain.
// Must be unique from all other consumer chain ids of the executing provider chain.
"chain_id": "newchain-1",
// Initial height of new consumer chain.
// For a completely new chain, this will be {0,1}.
"initial_height" : {
"revision_height": 0,
"revision_number": 1,
},
// Hash of the consumer chain genesis state without the consumer CCV module genesis params.
// It is used for off-chain confirmation of genesis.json validity by validators and other parties.
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
// Hash of the consumer chain binary that should be run by validators on chain initialization.
// It is used for off-chain confirmation of binary validity by validators and other parties.
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1",
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
// Unbonding period for the consumer chain.
// It should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
// IBC transfer packets will timeout after this interval elapses.
"transfer_timeout_period": 1800000000000,
// The fraction of tokens allocated to the consumer redistribution address during distribution events.
// The fraction is a string representing a decimal number. For example "0.75" would represent 75%.
// The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction.
"consumer_redistribution_fraction": "0.75",
// BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.
// eg. send rewards to the provider every 1000 blocks
"blocks_per_distribution_transmission": 1000,
// The number of historical info entries to persist in store.
// This param is a part of the cosmos sdk staking module. In the case of
// a ccv enabled consumer chain, the ccv module acts as the staking module.
"historical_entries": 10000,
// The ID of a token transfer channel used for the Reward Distribution
// sub-protocol. If DistributionTransmissionChannel == "", a new transfer
// channel is created on top of the same connection as the CCV channel.
// Note that transfer_channel_id is the ID of the channel end on the consumer chain.
// it is most relevant for chains performing a standalone to consumer changeover
// in order to maintain the existing ibc transfer channel
"distribution_transmission_channel": "channel-123"
}
+

4. Launch

+

The consumer chain starts after at least 66.67% of all provider's voting power comes online. The consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer

+
    +
  • provide a repo with onboarding instructions for validators (it should already be listed in the proposal)
  • +
  • genesis.json with ccv data populated (MUST contain the initial validator set)
  • +
  • maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels)
  • +
  • have a block explorer in place to track chain activity & health
  • +
+ + \ No newline at end of file diff --git a/v5.0.0/consumer-development/onboarding.html.html b/v5.0.0/consumer-development/onboarding.html.html new file mode 100644 index 0000000000..f91b7f84e8 --- /dev/null +++ b/v5.0.0/consumer-development/onboarding.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/faq.html b/v5.0.0/faq.html new file mode 100644 index 0000000000..09822bbd8d --- /dev/null +++ b/v5.0.0/faq.html @@ -0,0 +1,70 @@ + + + + + +Frequently Asked Questions | Interchain Security + + + + +
Version: v5.0.0

Frequently Asked Questions

What is the meaning of Validator Set Replication?

+

VSR simply means that the same validator set is used to secure both the provider and consumer chains. VSR is ensured through ICS protocol which keeps consumers up to date with the validator set of the provider.

+

What is a consumer chain?

+

Consumer chain is blockchain operated by the same validator operators as the provider chain. The ICS protocol ensures the validator set replication properties (informs consumer chain about the current state of the validator set on the provider)

+

Consumer chains are run on infrastructure (virtual or physical machines) distinct from the provider, have their own configurations and operating requirements.

+

What happens to consumer if provider is down?

+

In case the provider chain halts or experiences difficulties the consumer chain will keep operating - the provider chain and consumer chains represent different networks, which only share the validator set.

+

The consumer chain will not halt if the provider halts because they represent distinct networks and distinct infrastructures. Provider chain liveness does not impact consumer chain liveness.

+

However, if the trusting_period (currently 5 days for protocol safety reasons) elapses without receiving any updates from the provider, the consumer chain will essentially transition to a Proof of Authority chain. +This means that the validator set on the consumer will be the last validator set of the provider that the consumer knows about.

+

Steps to recover from this scenario and steps to "release" the validators from their duties will be specified at a later point. +At the very least, the consumer chain could replace the validator set, remove the ICS module and perform a genesis restart. The impact of this on the IBC clients and connections is currently under careful consideration.

+

What happens to provider if consumer is down?

+

Consumer chains do not impact the provider chain. +The ICS protocol is concerned only with validator set replication and the only communication that the provider requires from the consumer is information about validator activity (essentially keeping the provider informed about slash events).

+

Can I run the provider and consumer chains on the same machine?

+

Yes, but you should favor running them in separate environments so failure of one machine does not impact your whole operation.

+

Can the consumer chain have its own token?

+

As any other cosmos-sdk chain the consumer chain can issue its own token, manage inflation parameters and use them to pay gas fees.

+

How are Tx fees paid on consumer?

+

The consumer chain operates as any other cosmos-sdk chain. The ICS protocol does not impact the normal chain operations.

+

Are there any restrictions the consumer chains need to abide by?

+

No. Consumer chains are free to choose how they wish to operate, which modules to include, use CosmWASM in a permissioned or a permissionless way. +The only thing that separates consumer chains from standalone chains is that they share their validator set with the provider chain.

+

What's in it for the validators and stakers?

+

The consumer chains sends a portion of its fees and inflation as reward to the provider chain as defined by ConsumerRedistributionFraction. The rewards are distributed (sent to the provider) every BlocksPerDistributionTransmission.

+
note

ConsumerRedistributionFraction and BlocksPerDistributionTransmission are parameters defined in the ConsumerAdditionProposal used to create the consumer chain. These parameters can be changed via consumer chain governance.

+

Can the consumer chain have its own governance?

+

Yes.

+

In that case the validators are not necessarily part of the governance structure. Instead, their place in governance is replaced by "representatives" (governors). The representatives do not need to run validators, they simply represent the interests of a particular interest group on the consumer chain.

+

Validators can also be representatives but representatives are not required to run validator nodes.

+

This feature discerns between validator operators (infrastructure) and governance representatives which further democratizes the ecosystem. This also reduces the pressure on validators to be involved in on-chain governance.

+

Can validators opt-out of replicated security?

+

At present, the validators cannot opt-out of validating consumer chains.

+

There are multiple opt-out mechanisms under active research.

+

How does Equivocation Governance Slashing work?

+

To avoid potential attacks directed at provider chain validators, a new mechanism was introduced:

+

When a validator double-signs on the consumer chain, a special type of slash packet is relayed to the provider chain. The provider will store information about the double signing validator and allow a governance proposal to be submitted. +If the double-signing proposal passes, the offending validator will be slashed on the provider chain and tombstoned. Tombstoning will permanently exclude the validator from the active set of the provider.

+
caution

An equivocation proposal cannot be submitted for a validator that did not double sign on any of the consumer chains.

+

Can Consumer Chains perform Software Upgrades?

+

Consumer chains are standalone chains, in the sense that they can run arbitrary logic and use any modules they want (ie CosmWASM).

+

Consumer chain upgrades are unlikely to impact the provider chain, as long as there are no changes to the ICS module.

+

How can I connect to the testnets?

+

Check out the Joining Replicated Security testnet section.

+

How do I start using ICS?

+

To become a consumer chain use this checklist and check the App integration section

+

Which relayers are supported?

+

Currently supported versions:

+
    +
  • Hermes 1.4.1
  • +
  • Support for the CCV module was added to the Go relayer in v2.2.0 but v2.4.0 has significant performance fixes which makes it the earliest suggested version to use.
  • +
+

How does key delegation work in ICS?

+

You can check the Key Assignment Guide for specific instructions.

+ + \ No newline at end of file diff --git a/v5.0.0/faq.html.html b/v5.0.0/faq.html.html new file mode 100644 index 0000000000..338cf4786a --- /dev/null +++ b/v5.0.0/faq.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/features/key-assignment.html b/v5.0.0/features/key-assignment.html new file mode 100644 index 0000000000..9674c05b94 --- /dev/null +++ b/v5.0.0/features/key-assignment.html @@ -0,0 +1,57 @@ + + + + + +Key Assignment | Interchain Security + + + + +
Version: v5.0.0

Key Assignment

+

Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate. +There are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains.

+

The feature is outlined in this ADR-001

+

By sending an AssignConsumerKey transaction, validators are able to indicate which consensus key they will be using to validate a consumer chain. On receiving the transaction, if the key assignment is valid, the provider will use the assigned consensus key when it sends future voting power updates to the consumer that involve the validator.

+
tip

Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity.

+

Rules

+
    +
  • a key can be assigned as soon as the consumer addition proposal is submitted to the provider
  • +
  • validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider
  • +
  • validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X
  • +
  • a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain
  • +
+
tip

Validators can use a different key for each consumer chain.

+

Adding a key

+

First, create a new node on the consumer chain using the equivalent:

+
consumerd init <moniker>
+

Then query your node for the consensus key.

+
consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}
+

Then, make an assign-consensus-key transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain.

+
gaiad tx provider assign-consensus-key <consumer-chain-id> '<pubkey>' --from <tx-signer> --home <home_dir> --gas 900000 -b sync -y -o json
+
    +
  • consumer-chain-id is the string identifier of the consumer chain, as assigned on the provider chain
  • +
  • consumer-pub-key has the following format {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}
  • +
+

Check that the key was assigned correctly by querying the provider:

+
gaiad query provider validator-consumer-key <consumer-chain-id> cosmosvalcons1e....3xsj3ayzf4uv6
+

You must use a valcons address. You can obtain it by querying your node on the provider gaiad tendermint show-address

+

OR

+
gaiad query provider validator-provider-key <consumer-chain-id> consumervalcons1e....123asdnoaisdao
+

You must use a valcons address. You can obtain it by querying your node on the consumer consumerd tendermint show-address

+

OR

+
gaiad query provider all-pairs-valconsensus-address <consumer-chain-id>
+

You just need to use the chainId of consumer to query all pairs valconsensus address with consumer-pub-key for each of pair

+

Changing a key

+

To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied

+

Removing a key

+

To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the Adding a key section and using your provider consensus key.

+

Querying proposed consumer chains

+

To query the consumer addition proposals that are in the voting period, you can use the following command on the provider:

+
gaiad query provider list-proposed-consumer-chains
+

This query is valuable for staying informed about when keys can be assigned to newly proposed consumer chains.

+ + \ No newline at end of file diff --git a/v5.0.0/features/key-assignment.html.html b/v5.0.0/features/key-assignment.html.html new file mode 100644 index 0000000000..28e708dd02 --- /dev/null +++ b/v5.0.0/features/key-assignment.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/features/proposals.html b/v5.0.0/features/proposals.html new file mode 100644 index 0000000000..cff66a33c4 --- /dev/null +++ b/v5.0.0/features/proposals.html @@ -0,0 +1,42 @@ + + + + + +ICS Provider Proposals | Interchain Security + + + + +
Version: v5.0.0

ICS Provider Proposals

+

Interchain security module introduces 3 new proposal types to the provider.

+

The proposals are used to propose upcoming interchain security events through governance.

+

ConsumerAdditionProposal

+
info

If you are preparing a ConsumerAdditionProposal you can find more information in the consumer onboarding checklist.

+

Proposal type used to suggest adding a new consumer chain.

+

When proposals of this type are passed and the spawn_time specified in the proposal is reached, all provider chain validators are expected to run infrastructure (validator nodes) for the proposed consumer chain.

+

Minimal example:

+
{
// Time on the provider chain at which the consumer chain genesis is finalized and all validators
// will be responsible for starting their consumer chain validator node.
"spawn_time": "2023-02-28T20:40:00.000000Z",
"title": "Add consumer chain",
"description": ".md description of your chain and all other relevant information",
"chain_id": "newchain-1",
"initial_height" : {
"revision_height": 0,
"revision_number": 1,
},
// Unbonding period for the consumer chain.
// It should be smaller than that of the provider.
"unbonding_period": 86400000000000,
// Timeout period for CCV related IBC packets.
// Packets are considered timed-out after this interval elapses.
"ccv_timeout_period": 259200000000000,
"transfer_timeout_period": 1800000000000,
"consumer_redistribution_fraction": "0.75",
"blocks_per_distribution_transmission": 1000,
"historical_entries": 10000,
"genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0",
"binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1"
// relevant for chains performing a standalone to consumer changeover
// in order to maintain the existing ibc transfer channel
"distribution_transmission_channel": "channel-123"
}
+

More examples can be found in the interchain security testnet repository here and here.

+

ConsumerRemovalProposal

+

Proposal type used to suggest removing an existing consumer chain.

+

When proposals of this type are passed, the consumer chain in question will be gracefully removed from interchain security and validators will no longer be required to run infrastructure for the specified chain. +After the consumer chain removal, the chain in question will no longer be secured by the provider's validator set.

+
info

The chain in question my continue to produce blocks, but the validator set can no longer be slashed for any infractions committed on that chain. +Additional steps are required to completely offboard a consumer chain, such as re-introducing the staking module and removing the provider's validators from the active set. +More information will be made available in the Consumer Offboarding Checklist.

+

Minimal example:

+
{
// the time on the provider chain at which all validators are responsible to stop their consumer chain validator node
"stop_time": "2023-03-07T12:40:00.000000Z",
// the chain-id of the consumer chain to be stopped
"chain_id": "consumerchain-1",
"title": "This was a great chain",
"description": "Here is a .md formatted string specifying removal details"
}
+

ChangeRewardDenomProposal

+

Proposal type used to mutate the set of denoms accepted by the provider as rewards.

+
tip

A ChangeRewardDenomProposal will only be accepted on the provider chain if at least one of the denomsToAdd or denomsToRemove fields is populated with at least one denom. Also, a denom cannot be repeated in both sets.

+

Minimal example:

+
{
"title": "Add uatom as a reward denom",
"description": "Here is more information about the proposal",
"denomsToAdd": ["uatom"],
"denomsToRemove": []
}
+
tip

Besides native provider denoms (e.g., uatom for the Cosmos Hub), please use the ibc/* denom trace format. +For example, for untrn transferred over the path transfer/channel-569, the denom trace +can be queried using the following command:

> gaiad query ibc-transfer denom-hash transfer/channel-569/untrn
hash: 0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5

Then use the resulting hash in the ChangeRewardDenomProposal, e.g.,

{
"title": "Add untrn as a reward denom",
"description": "Here is more information about the proposal",
"denomsToAdd": ["ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5"],
"denomsToRemove": []
}
+ + \ No newline at end of file diff --git a/v5.0.0/features/proposals.html.html b/v5.0.0/features/proposals.html.html new file mode 100644 index 0000000000..28f6a85f12 --- /dev/null +++ b/v5.0.0/features/proposals.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/features/reward-distribution.html b/v5.0.0/features/reward-distribution.html new file mode 100644 index 0000000000..2f7f3377f4 --- /dev/null +++ b/v5.0.0/features/reward-distribution.html @@ -0,0 +1,33 @@ + + + + + +Reward Distribution | Interchain Security + + + + +
Version: v5.0.0

Reward Distribution

+

Sending and distributing rewards from consumer chains to the provider chain is handled by the Reward Distribution sub-protocol.

+

Consumer chains have the option of sharing (a portion of) their block rewards (inflation tokens and fees) with the provider chain validators and delegators. +In replicated security, block rewards are periodically sent from the consumer to the provider according to consumer chain parameters using an IBC transfer channel. +This channel is created during consumer chain initialization, unless it is provided via the ConsumerAdditionProposal when adding a new consumer chain. +For more details, see the reward distribution parameters.

+
tip

Providing an IBC transfer channel (see DistributionTransmissionChannel) enables a consumer chain to re-use one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the ibc denom that may already be in use. +This is especially important for standalone chains transitioning to become consumer chains. +For more details, see the changeover procedure.

+

Reward distribution on the provider is handled by the distribution module.

+

Whitelisting Reward Denoms

+

The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the ConsumerRewardsPool. +To avoid spam, the provider must whitelist denoms before accepting them as ICS rewards. +Only whitelisted denoms are transferred from the ConsumerRewardsPool to the FeePoolAddress, to be distributed to delegators and validators. +The whitelisted denoms can be adjusted through governance by sending a ChangeRewardDenomProposal.

+

To query the list of whitelisted reward denoms on the Cosmos Hub, use the following command:

+
> gaiad q provider registered-consumer-reward-denoms
denoms:
- ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5
- ibc/6B8A3F5C2AD51CD6171FA41A7E8C35AD594AB69226438DB94450436EA57B3A89
- uatom
+
tip

Use the following command to get a human readable denom from the ibc/* denom trace format:

>  gaiad query ibc-transfer denom-trace ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5
denom_trace:
base_denom: untrn
path: transfer/channel-569
+ + \ No newline at end of file diff --git a/v5.0.0/features/reward-distribution.html.html b/v5.0.0/features/reward-distribution.html.html new file mode 100644 index 0000000000..b88b4cdd73 --- /dev/null +++ b/v5.0.0/features/reward-distribution.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/features/slashing.html b/v5.0.0/features/slashing.html new file mode 100644 index 0000000000..8bce599efc --- /dev/null +++ b/v5.0.0/features/slashing.html @@ -0,0 +1,46 @@ + + + + + +Consumer Initiated Slashing | Interchain Security + + + + +
Version: v5.0.0

Consumer Initiated Slashing

+

A consumer chain is essentially a regular Cosmos-SDK based chain that uses the Interchain Security module to achieve economic security by stake deposited on the provider chain, instead of its own chain. +In essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake).

+

To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized. +Any infraction committed on any of the consumer chains is reflected on the provider and all other consumer chains.

+

In the current implementation there are two important changes brought by the Interchain Security module.

+

Downtime Infractions

+

Downtime infractions are reported by consumer chains and are acted upon on the provider as soon as the provider receives the infraction evidence.

+

Instead of slashing, the provider will only jail offending validator for the duration of time established by the chain parameters.

+
info

Slash throttling (sometimes called jail throttling) mechanism ensures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider.

+

Equivocation Infractions

+

Equivocation infractions are reported by external agents (e.g., relayers) that can submit to the provider evidence of light client or double signing attacks observed on a consumer chain. +The evidence is submitted by sending MsgSubmitConsumerMisbehaviour or MsgSubmitConsumerDoubleVoting transactions to the provider. +When valid evidence is received, the malicious validators are slashed, jailed, and tombstoned on the provider. +This is enabled through the cryptographic verification of equivocation feature. +For more details, see ADR-005 and ADR-013.

+

Report equivocation infractions through CLI

+

The ICS provider module offers two commands for submitting evidence of misbehavior originating from a consumer chain. +Below are two examples illustrating the process on Cosmos Hub.

+

Use the following command to submit evidence of double signing attacks:

+
gaiad tx provider submit-consumer-double-voting [path/to/evidence.json] [path/to/infraction_header.json] --from node0 --home ../node0 --chain-id $CID 
+
Example of evidence.json
{
"vote_a": {
"type": 1,
"height": 25,
"round": 0,
"block_id": {
"hash": "tBBWTqjECl31S/clZGoxLdDqs93kTvy3qhpPqET/laY=",
"part_set_header": {
"total": 1,
"hash": "ai2qCLgVZAFph4FJ4Cqw5QW1GZKR4zjOv0bI/Um5AIc="
}
},
"timestamp": "2023-11-20T12:57:54.565207Z",
"validator_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",
"signature": "y9yILm9hmv45BZwAaaq9mS1FpH7QeAIJ5Jkcc3U2/k5uks9cuqr4NTIwaIrqMSMKwxVyqiR56xmCT59a6AngAA=="
},
"vote_b": {
"type": 1,
"height": 25,
"round": 0,
"block_id": {
"hash": "3P06pszgPatuIdLTP5fDWiase4SYHIq9YXGSbRk9/50=",
"part_set_header": {
"total": 1,
"hash": "S+SbOMxFRzfeNNpX9/jyFMz94VwBKk7Dpx6ZyvSYyNU="
}
},
"timestamp": "2023-11-20T12:57:54.599273Z",
"validator_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",
"validator_index": 0,
"signature": "DGFcn4Um1t2kXW60+JhMk5cj7ZFdE5goKVOGiZkLwnNv43+6aGmOWjoq0SHYVzM4MwSwOwbhgZNbkWX+EHGUBw=="
},
"total_voting_power": 300,
"validator_power": 100,
"timestamp": "2023-11-20T12:57:51.267308Z"
}
+
Example of infraction_header.json
{
"signed_header": {
"header": {
"version": {
"block": 11,
"app": 2
},
"chain_id": "consumer",
"height": 22,
"time": "2023-11-20T12:57:40.479686Z",
"last_block_id": {
"hash": "L63hyLJ+y9+fpb7WYKdmmBhPHwbfEGQEuKmvGzyBPiY=",
"part_set_header": {
"total": 18,
"hash": "euzRQjN7MjGtM6skXM4B8wOgAldWGfZSJRA9JRlO42s="
}
},
"last_commit_hash": "qdDJwVziW3pPqmf8QDGZG+5HVd3OF7fCVh2Z8KQqNVU=",
"data_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"validators_hash": "pVc+gSYkGesaP3OkK4ig3DBi4o9/GCdXGtO/PQ6i/Ik=",
"next_validators_hash": "pVc+gSYkGesaP3OkK4ig3DBi4o9/GCdXGtO/PQ6i/Ik=",
"consensus_hash": "BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8=",
"app_hash": "Yu3HX62w7orbbY/pm2QEK7yIwR+AlNdjSSqiK1kmuJM=",
"last_results_hash": "Yu3HX62w7orbbY/pm2QEK7yIwR+AlNdjSSqiK1kmuJM=",
"evidence_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"proposer_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA="
},
"commit": {
"height": 22,
"round": 1,
"block_id": {
"hash": "PKrS32IEZoFY2q2S3iQ68HQL751ieBhf5Eu/Y5Z/QPg=",
"part_set_header": {
"total": 1,
"hash": "8UuA7Oqw5AH/KOacpmHVSMOIDe4l2eC8VmdH2mzcpiM="
}
},
"signatures": [
{
"block_id_flag": 2,
"validator_address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",
"timestamp": "2023-11-20T12:57:44.076538Z",
"signature": "bSOH4+Vg2I37zeJphOguGOD0GK3JzM1ghSgJd0UlW/DHn1u9Hvv4EekHuCu6qwRLZcuS/ZxNlmr9qYNfxX3bDA=="
},
{
"block_id_flag": 2,
"validator_address": "i/A830FM7cfmA8yTn9n3xBg5XpU=",
"timestamp": "2020-01-02T00:07:00Z",
"signature": "7bXSDtlOwGK/gLEsFpTWOzm2TFoaARrWQUpbgWEwKtLlUs7iE06TOvJ3yPPfTfqqN/qYnvxxgjl0M0EhUWu5Bg=="
},
{
"block_id_flag": 2,
"validator_address": "lrQDkJ2fk7UAgNzRZfcwMKSYa2E=",
"timestamp": "2023-11-20T12:57:44.076519Z",
"signature": "Pb6G4bCg4wafmV89WNnzXxbSCknZUHnSQfSCE5QMFxPtSUIN4A7SK5m7yltqMJF5zkyenlFiEI4J3OZ4KCjCAw=="
},
{
"block_id_flag": 2,
"validator_address": "+R94nXSeM1Z49e/CXpyHT3M+h3k=",
"timestamp": "2023-11-20T12:57:44.057451Z",
"signature": "j3EasIHNYA6MxW/PiWyruzHsjVsBV9t11W6Qx800WMm/+P+CkfR+UZAp7MPTvKZEZFuh3GUsBtyfb/vA+jJWCw=="
}
]
}
},
"validator_set": {
"validators": [
{
"address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",
"pub_key": {
"ed25519": "dtn+SfD+4QLo0+t0hAoP6Q2sGjh0XEI3LWVG+doh3u0="
},
"voting_power": 100,
"proposer_priority": -200
},
{
"address": "lrQDkJ2fk7UAgNzRZfcwMKSYa2E=",
"pub_key": {
"ed25519": "UgN2JsjPy2WLh7dzJRBkUQtdgNoT4/uGj7kbIVqqHT8="
},
"voting_power": 100,
"proposer_priority": 100
},
{
"address": "+R94nXSeM1Z49e/CXpyHT3M+h3k=",
"pub_key": {
"ed25519": "5svW8261x+cZosp2xIhqzgt2tyuawrSDyHlpbgS3BC4="
},
"voting_power": 100,
"proposer_priority": 100
},
{
"address": "aCG1hw85Zz7Ylgpsy263IJVJEMA=",
"pub_key": {
"ed25519": "dtn+SfD+4QLo0+t0hAoP6Q2sGjh0XEI3LWVG+doh3u0="
},
"voting_power": 100,
"proposer_priority": -200
}
],
"proposer": {
"address": "VUz+QceJ8Nu7GbJuVItwsfVjybA=",
"pub_key": {
"ed25519": "0s8KDTgEcwmOBrHWvV7mtBlItJ3upgM1FJsciwREdy4="
},
"voting_power": 1,
"proposer_priority": -3
}
},
"trusted_height": {
"revision_height": 18
},
"trusted_validators": {
"validators": [
{
"address": "VUz+QceJ8Nu7GbJuVItwsfVjybA=",
"pub_key": {
"ed25519": "0s8KDTgEcwmOBrHWvV7mtBlItJ3upgM1FJsciwREdy4="
},
"voting_power": 1,
"proposer_priority": -3
},
{
"address": "i/A830FM7cfmA8yTn9n3xBg5XpU=",
"pub_key": {
"ed25519": "FCmIw7hSuiAoWk/2f4LuGQ+3zx5101xiqU8DoC5wGkg="
},
"voting_power": 1,
"proposer_priority": 1
},
{
"address": "2DrZF0roNnnvEy4NS2aY811ncKg=",
"pub_key": {
"ed25519": "MI9c6sphsWlx0RAHCYOjMRXMFkTUaEYwOiOKG/0tsMs="
},
"voting_power": 1,
"proposer_priority": 1
},
{
"address": "73aN0uOc5b/Zfq2Xcjl0kH2r+tw=",
"pub_key": {
"ed25519": "gWNcDup4mdnsuqET4QeFRzVb+FnSP4Vz3iNMj5wvWXk="
},
"voting_power": 1,
"proposer_priority": 1
}
],
"proposer": {
"address": "VUz+QceJ8Nu7GbJuVItwsfVjybA=",
"pub_key": {
"ed25519": "0s8KDTgEcwmOBrHWvV7mtBlItJ3upgM1FJsciwREdy4="
},
"voting_power": 1,
"proposer_priority": -3
}
}
}
+

Use the following command to submit evidence of light client attacks:

+
gaiad tx provider submit-consumer-misbehaviour [path/to/misbehaviour.json] --from node0 --home ../node0 --chain-id $CID
+
Example of misbehaviour.json
{
"client_id": "07-tendermint-0",
"header_1": {
"signed_header": {
"header": {
"version": {
"block": "11",
"app": "2"
},
"chain_id": "testchain2",
"height": "19",
"time": "2020-01-02T00:08:10Z",
"last_block_id": {
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"part_set_header": {
"total": 10000,
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
}
},
"last_commit_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",
"data_hash": "bW4ouLmLUycELqUKV91G5syFHHLlKL3qpu/e7v5moLg=",
"validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",
"next_validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",
"consensus_hash": "5eVmxB7Vfj/4zBDxhBeHiLj6pgKwfPH0JSF72BefHyQ=",
"app_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",
"last_results_hash": "CS4FhjAkftYAmGOhLu4RfSbNnQi1rcqrN/KrNdtHWjc=",
"evidence_hash": "c4ZdsI9J1YQokF04mrTKS5bkWjIGx6adQ6Xcc3LmBxQ=",
"proposer_address": "CbKqPquy50bcrY7JRdW7zXybSuA="
},
"commit": {
"height": "19",
"round": 1,
"block_id": {
"hash": "W2xVqzPw03ZQ1kAMpcpht9WohwMzsGnyKKNjPYKDF6U=",
"part_set_header": {
"total": 3,
"hash": "hwgKOc/jNqZj6lwNm97vSTq9wYt8Pj4MjmYTVMGDFDI="
}
},
"signatures": [
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"timestamp": "2020-01-02T00:08:10Z",
"signature": "PGTquCtnTNFFY5HfEFz9f9pA7PYqjtQfBwHq6cxF/Ux8OI6nVqyadD9a84Xm7fSm6mqdW+T6YVfqIKmIoRjJDQ=="
},
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",
"timestamp": "2020-01-02T00:08:10Z",
"signature": "0e39yoBorwORAH/K9qJ7D1N1Yr7CutMiQJ+oiIK39eMhuoK3UWzQyMGRLzDOIDupf8yD99mvGVVAlNIODlV3Dg=="
},
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",
"timestamp": "2020-01-02T00:08:10Z",
"signature": "lhc2tkwydag9D1iLQhdDCE8GgrHP94M1LbHFYMoL9tExaEq6RiFW/k71TQH5x96XQ9XYOznMIHKC2BDh4GlnAQ=="
},
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",
"timestamp": "2020-01-02T00:08:10Z",
"signature": "8xeSBf0nSFs/X/rQ9CZLzwkJJhQBLA2jKdPGP3MlULxm992XxrOsIYq47u1daxvSsn6ql5OVYjzBNU0qbPpvCA=="
}
]
}
},
"validator_set": {
"validators": [
{
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
{
"address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",
"pub_key": {
"ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",
"pub_key": {
"ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",
"pub_key": {
"ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="
},
"voting_power": "1",
"proposer_priority": "1"
}
],
"proposer": {
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
"total_voting_power": "0"
},
"trusted_height": {
"revision_number": "0",
"revision_height": "18"
},
"trusted_validators": {
"validators": [
{
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
{
"address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",
"pub_key": {
"ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",
"pub_key": {
"ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",
"pub_key": {
"ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="
},
"voting_power": "1",
"proposer_priority": "1"
}
],
"proposer": {
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
"total_voting_power": "0"
}
},
"header_2": {
"signed_header": {
"header": {
"version": {
"block": "11",
"app": "2"
},
"chain_id": "testchain2",
"height": "19",
"time": "2020-01-02T00:08:20Z",
"last_block_id": {
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"part_set_header": {
"total": 10000,
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
}
},
"last_commit_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",
"data_hash": "bW4ouLmLUycELqUKV91G5syFHHLlKL3qpu/e7v5moLg=",
"validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",
"next_validators_hash": "ImwBH++bKKkm2NDCwOxRn04P5GWWypgzeLVZWoc10+I=",
"consensus_hash": "5eVmxB7Vfj/4zBDxhBeHiLj6pgKwfPH0JSF72BefHyQ=",
"app_hash": "dPJh3vUG5ls8NeP/SBSEkIgTOzrkFOROqhKnuk2zRgc=",
"last_results_hash": "CS4FhjAkftYAmGOhLu4RfSbNnQi1rcqrN/KrNdtHWjc=",
"evidence_hash": "c4ZdsI9J1YQokF04mrTKS5bkWjIGx6adQ6Xcc3LmBxQ=",
"proposer_address": "CbKqPquy50bcrY7JRdW7zXybSuA="
},
"commit": {
"height": "19",
"round": 1,
"block_id": {
"hash": "IZM8NKS+8FHB7CBmgB8Nz7BRVVXiiyqMQDvHFUvgzxo=",
"part_set_header": {
"total": 3,
"hash": "hwgKOc/jNqZj6lwNm97vSTq9wYt8Pj4MjmYTVMGDFDI="
}
},
"signatures": [
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"timestamp": "2020-01-02T00:08:20Z",
"signature": "pLIEZ4WSAtnMsgryujheHSq4+YG3RqTfMn2ZxgEymr0wyi+BNlQAKRtRfesm0vfYxvjzc/jhGqtUqHtSIaCwCQ=="
},
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",
"timestamp": "2020-01-02T00:08:20Z",
"signature": "XG7iTe/spWyTUkT7XDzfLMpYqrdyqizE4/X4wl/W+1eaQp0WsCHYnvPU3x9NAnYfZzaKdonZiDWs7wacbZTcDg=="
},
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",
"timestamp": "2020-01-02T00:08:20Z",
"signature": "TqegK7ORuICSy++wVdPHt8fL2WfPlYsMPv1XW79wUdcjnQkezOM50OSqYaP4ua5frIZsn+sWteDrlqFTdkl3BA=="
},
{
"block_id_flag": "BLOCK_ID_FLAG_COMMIT",
"validator_address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",
"timestamp": "2020-01-02T00:08:20Z",
"signature": "dhvp3XlIaCxx5MFDs0TCkAPHSm0PS2EtJzYAx2c/7MWdLwUJFZrAUTeimQE2c9i9ro91cjZn/vI0/oFRXab6Aw=="
}
]
}
},
"validator_set": {
"validators": [
{
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
{
"address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",
"pub_key": {
"ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",
"pub_key": {
"ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",
"pub_key": {
"ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="
},
"voting_power": "1",
"proposer_priority": "1"
}
],
"proposer": {
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
"total_voting_power": "0"
},
"trusted_height": {
"revision_number": "0",
"revision_height": "18"
},
"trusted_validators": {
"validators": [
{
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
{
"address": "Ua+R3vfKH1LWhRg/k8PbA/uSLnc=",
"pub_key": {
"ed25519": "H+7myYFFaCBTAxPiYaTX4IZIRtaUu+rcJVp+doLxd8c="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "Uns+2wsfv6IYTpOnYfAnPplVzTE=",
"pub_key": {
"ed25519": "QMHyl6i2OjmMEh73VXS5QBdsQ1vQ2mU3XzKGAhnKqmc="
},
"voting_power": "1",
"proposer_priority": "1"
},
{
"address": "sS7FyKFPDEG7StI+4o3+6fZy1pY=",
"pub_key": {
"ed25519": "uSNKjObXRHsNslEdqdublnVDa4Vc2aoCpr0j+Fuvv5U="
},
"voting_power": "1",
"proposer_priority": "1"
}
],
"proposer": {
"address": "CbKqPquy50bcrY7JRdW7zXybSuA=",
"pub_key": {
"ed25519": "sUkpD9xhOgWna0dv4bSwI7N7CkyH6q1bBDPYhjRolaY="
},
"voting_power": "1",
"proposer_priority": "-3"
},
"total_voting_power": "0"
}
}
}
+

Report equivocation infractions with Hermes

+

Ensure you have a well-configured Hermes v1.7.3+ relayer effectively relaying packets between a consumer chain and a provider chain. +The following command demonstrates how to run a Hermes instance in evidence mode to detect misbehaviors on a consumer chain and automatically submit the evidence to the provider chain.

+
hermes evidence --chain <CONSUMER-CHAIN-ID>
+
tip

hermes evidence takes a --check-past-blocks option giving the possibility to look for older evidence (default is 100).

+ + \ No newline at end of file diff --git a/v5.0.0/features/slashing.html.html b/v5.0.0/features/slashing.html.html new file mode 100644 index 0000000000..01d58f2e95 --- /dev/null +++ b/v5.0.0/features/slashing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/introduction/overview.html b/v5.0.0/introduction/overview.html new file mode 100644 index 0000000000..22e669bcf2 --- /dev/null +++ b/v5.0.0/introduction/overview.html @@ -0,0 +1,33 @@ + + + + + +Overview | Interchain Security + + + + +
Version: v5.0.0

Overview

+
info

Replicated security (aka interchain security V1) is an open sourced IBC application which allows cosmos blockchains to lease their proof-of-stake security to one another.


Replicated security allows anyone to launch a "consumer" blockchain using the same validator set as the "provider" blockchain by creating a governance proposal. If the proposal is accepted, provider chain validators start validating the consumer chain as well. Consumer chains will therefore inherit the full security and decentralization of the provider.

+

Why Replicated Security?

+
    +
  • Full provider security. At launch, consumer chains are secured by the full validator set and market cap of the provider chain.
  • +
  • Independent block-space. Transactions on consumer chains do not compete with any other applications. This means that there will be no unexpected congestion, and performance will generally be much better than on a shared smart contract platform such as Ethereum.
  • +
  • Projects keep majority of gas fees. Depending on configuration, these fees either go to the project’s community DAO, or can be used in the protocol in other ways.
  • +
  • No validator search. Consumer chains do not have their own validator sets, and so do not need to find validators one by one. A governance vote will take place for a chain to get adopted by the provider validators which will encourage participation and signal strong buy-in into the project's long-term success.
  • +
  • Instant sovereignty. Consumers can run arbitrary app logic similar to standalone chains. At any time in the future, a consumer chain can elect to become a completely standalone chain, with its own validator set.
  • +
+

Core protocol

+
info

Protocol specification is available as ICS-028 in the IBC repository.

+

Once an IBC connection and proper channel is established between a provider and consumer chain, the provider will continually send validator set updates to the consumer over IBC. The consumer uses these validator set updates to update its own validator set in Comet. Thus, the provider validator set is effectively replicated on the consumer.

+

To ensure the security of the consumer chain, provider delegators cannot unbond their tokens until the unbonding periods of each consumer chain has passed. In practice this will not be noticeable to the provider delegators, since consumer chains will be configured to have a slightly shorter unbonding period than the provider.

+

Downtime Slashing

+

If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period.

+

Tokenomics and Rewards

+

Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance.

+ + \ No newline at end of file diff --git a/v5.0.0/introduction/overview.html.html b/v5.0.0/introduction/overview.html.html new file mode 100644 index 0000000000..f885f8b733 --- /dev/null +++ b/v5.0.0/introduction/overview.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/introduction/params.html b/v5.0.0/introduction/params.html new file mode 100644 index 0000000000..41105f4c6d --- /dev/null +++ b/v5.0.0/introduction/params.html @@ -0,0 +1,100 @@ + + + + + +Interchain Security Parameters | Interchain Security + + + + +
Version: v5.0.0

Interchain Security Parameters

+

The parameters necessary for Interchain Security (ICS) are defined in

+
    +
  • the Params structure in proto/interchain_security/ccv/provider/v1/provider.proto for the provider;
  • +
  • the Params structure in proto/interchain_security/ccv/consumer/v1/consumer.proto for the consumer.
  • +
+

Time-Based Parameters

+

ICS relies on the following time-based parameters.

+

ProviderUnbondingPeriod

+

ProviderUnbondingPeriod is the unbonding period on the provider chain as configured during chain genesis. This parameter can later be changed via governance.

+

ConsumerUnbondingPeriod

+

ConsumerUnbondingPeriod is the unbonding period on the consumer chain.

+
info

ConsumerUnbondingPeriod is set via the ConsumerAdditionProposal governance proposal to add a new consumer chain. +It is recommended that every consumer chain set and unbonding period shorter than ProviderUnbondingPeriod


Example:

ConsumerUnbondingPeriod = ProviderUnbondingPeriod - one day
+

Unbonding operations (such as undelegations) are completed on the provider only after the unbonding period elapses on every consumer.

+

TrustingPeriodFraction

+

TrustingPeriodFraction is used to calculate the TrustingPeriod of created IBC clients on both provider and consumer chains.

+

Setting TrustingPeriodFraction to 0.5 would result in the following:

+
TrustingPeriodFraction = 0.5
ProviderClientOnConsumerTrustingPeriod = ProviderUnbondingPeriod * 0.5
ConsumerClientOnProviderTrustingPeriod = ConsumerUnbondingPeriod * 0.5
+

Note that a light clients must be updated within the TrustingPeriod in order to avoid being frozen.

+

For more details, see the IBC specification of Tendermint clients.

+

CCVTimeoutPeriod

+

CCVTimeoutPeriod is the period used to compute the timeout timestamp when sending IBC packets.

+

For more details, see the IBC specification of Channel & Packet Semantics.

+
warning

If a sent packet is not relayed within this period, then the packet times out. The CCV channel used by the interchain security protocol is closed, and the corresponding consumer is removed.

+

CCVTimeoutPeriod may have different values on the provider and consumer chains.

+
    +
  • CCVTimeoutPeriod on the provider must be larger than ConsumerUnbondingPeriod
  • +
  • CCVTimeoutPeriod on the consumer is initial set via the ConsumerAdditionProposal
  • +
+

InitTimeoutPeriod

+

InitTimeoutPeriod is the maximum allowed duration for CCV channel initialization to execute.

+

For any consumer chain, if the CCV channel is not established within InitTimeoutPeriod then the consumer chain will be removed and therefore will not be secured by the provider chain.

+

The countdown starts when the spawn_time specified in the ConsumerAdditionProposal is reached.

+

VscTimeoutPeriod

+

VscTimeoutPeriod is the provider-side param that enables the provider to timeout VSC packets even when a consumer chain is not live. +If the VscTimeoutPeriod is ever reached for a consumer chain that chain will be considered not live and removed from interchain security.

+
tip

VscTimeoutPeriod MUST be larger than the ConsumerUnbondingPeriod.

+

BlocksPerDistributionTransmission

+

BlocksPerDistributionTransmission is the number of blocks between rewards transfers from the consumer to the provider.

+

TransferPeriodTimeout

+

TransferPeriodTimeout is the period used to compute the timeout timestamp when sending IBC transfer packets from a consumer to the provider.

+

If this timeout expires, then the transfer is attempted again after BlocksPerDistributionTransmission blocks.

+
    +
  • TransferPeriodTimeout on the consumer is initial set via the ConsumerAdditionProposal gov proposal to add the consumer
  • +
  • TransferPeriodTimeout should be smaller than BlocksPerDistributionTransmission x avg_block_time
  • +
+

Reward Distribution Parameters

+
tip

The following chain parameters dictate consumer chain distribution amount and frequency. +They are set at consumer genesis and BlocksPerDistributionTransmission, ConsumerRedistributionFraction +TransferTimeoutPeriod must be provided in every ConsumerChainAddition proposal.

+

ConsumerRedistributionFraction

+

ConsumerRedistributionFraction is the fraction of tokens allocated to the consumer redistribution address during distribution events. The fraction is a string representing a decimal number. For example "0.75" would represent 75%.

+
tip

Example:

With ConsumerRedistributionFraction set to "0.75" the consumer chain would send 75% of its block rewards and accumulated fees to the consumer redistribution address, and the remaining 25% to the provider chain every BlocksPerDistributionTransmission blocks.

+

BlocksPerDistributionTransmission

+

BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain.

+

TransferTimeoutPeriod

+

TransferTimeoutPeriod is the timeout period for consumer chain reward distribution IBC packets.

+

DistributionTransmissionChannel

+

DistributionTransmissionChannel is the provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.

+

ProviderFeePoolAddrStr

+

ProviderFeePoolAddrStr is the provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.

+

Slash Throttle Parameters

+

SlashMeterReplenishPeriod

+

SlashMeterReplenishPeriod exists on the provider such that once the slash meter becomes not-full, the slash meter is replenished after this period has elapsed.

+

The meter is replenished to an amount equal to the slash meter allowance for that block, or SlashMeterReplenishFraction * CurrentTotalVotingPower.

+

SlashMeterReplenishFraction

+

SlashMeterReplenishFraction exists on the provider as the portion (in range [0, 1]) of total voting power that is replenished to the slash meter when a replenishment occurs.

+

This param also serves as a maximum fraction of total voting power that the slash meter can hold. The param is set/persisted as a string, and converted to a sdk.Dec when used.

+

MaxThrottledPackets

+

MaxThrottledPackets exists on the provider as the maximum amount of throttled slash or vsc matured packets that can be queued from a single consumer before the provider chain halts, it should be set to a large value.

+

This param would allow provider binaries to panic deterministically in the event that packet throttling results in a large amount of state-bloat. In such a scenario, packet throttling could prevent a violation of safety caused by a malicious consumer, at the cost of provider liveness.

+
info

MaxThrottledPackets was deprecated in ICS versions >= v3.2.0 due to the implementation of ADR-008.

+

RetryDelayPeriod

+

RetryDelayPeriod exists on the consumer for ICS versions >= v3.2.0 (introduced by the implementation of ADR-008) and is the period at which the consumer retries to send a SlashPacket that was rejected by the provider.

+

Epoch Parameters

+

BlocksPerEpoch

+

BlocksPerEpoch exists on the provider for ICS versions >= 3.3.0 (introduced by the implementation of ADR-014) +and corresponds to the number of blocks that constitute an epoch. This param is set to 600 by default. Assuming we need 6 seconds to +commit a block, the duration of an epoch corresponds to 1 hour. This means that a VSCPacket would be sent to a consumer +chain once at the end of every epoch, so once every 600 blocks. This parameter can be adjusted via a governance proposal, +however careful consideration is needed so that BlocksPerEpoch is not too large. A large BlocksPerEpoch could lead to a delay +of VSCPackets and hence potentially lead to unbonding pausing. +For setting BlocksPerEpoch, we also need to consider potential slow chain upgrades that could delay the sending of a +VSCPacket, as well as potential increases in the time it takes to commit a block (e.g., from 6 seconds to 30 seconds).

+ + \ No newline at end of file diff --git a/v5.0.0/introduction/params.html.html b/v5.0.0/introduction/params.html.html new file mode 100644 index 0000000000..ba6ea043da --- /dev/null +++ b/v5.0.0/introduction/params.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/introduction/technical-specification.html b/v5.0.0/introduction/technical-specification.html new file mode 100644 index 0000000000..b6432aa8dc --- /dev/null +++ b/v5.0.0/introduction/technical-specification.html @@ -0,0 +1,17 @@ + + + + + +Technical Specification | Interchain Security + + + + +
Version: v5.0.0

Technical Specification

+

For a technical deep dive into the replicated security protocol, see the specification.

+ + \ No newline at end of file diff --git a/v5.0.0/introduction/technical-specification.html.html b/v5.0.0/introduction/technical-specification.html.html new file mode 100644 index 0000000000..eda66b203d --- /dev/null +++ b/v5.0.0/introduction/technical-specification.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/introduction/terminology.html b/v5.0.0/introduction/terminology.html new file mode 100644 index 0000000000..777daea2b0 --- /dev/null +++ b/v5.0.0/introduction/terminology.html @@ -0,0 +1,33 @@ + + + + + +Terminology | Interchain Security + + + + +
Version: v5.0.0

Terminology

+

You may have heard of one or multiple buzzwords thrown around in the cosmos and wider crypto ecosystem such shared security, interchain security, replicated security, cross chain validation, and mesh security. These terms will be clarified below, before diving into any introductions.

+

Shared Security

+

Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share its proof-of-stake security with another blockchain or off-chain process.

+

Interchain Security

+

Interchain Security is the Cosmos-specific category of Shared Security that uses IBC (Inter-Blockchain Communication), i.e. any shared security protocol built with IBC.

+

Replicated Security

+

A particular protocol/implementation of Interchain Security that fully replicates the security and decentralization of a validator set across multiple blockchains. Replicated security has also been referred to as "Cross Chain Validation" or "Interchain Security V1", a legacy term for the same protocol. That is, a "provider chain" such as the Cosmos Hub can share its exact validator set with multiple consumer chains by communicating changes in its validator set over IBC. Note this documentation is focused on explaining the concepts from replicated security.

+

Mesh security

+

A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see Replicated vs. Mesh Security on the Informal Blog.

+

Consumer Chain

+

Chain that is secured by the validator set of the provider, instead of its own. +Replicated security allows the provider chain validator set to validate blocks on the consumer chain.

+

Standalone Chain

+

Chain that is secured by its own validator set. This chain does not participate in replicated security.

+

Standalone chains may sometimes be called "sovereign" - the terms are synonymous.

+

Changeover Procedure

+

Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the changeover procedure and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain.

+ + \ No newline at end of file diff --git a/v5.0.0/introduction/terminology.html.html b/v5.0.0/introduction/terminology.html.html new file mode 100644 index 0000000000..a336beba1e --- /dev/null +++ b/v5.0.0/introduction/terminology.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/upgrading/migrate_v4_v5.html b/v5.0.0/upgrading/migrate_v4_v5.html new file mode 100644 index 0000000000..1e39b0576d --- /dev/null +++ b/v5.0.0/upgrading/migrate_v4_v5.html @@ -0,0 +1,128 @@ + + + + + +Upgrading to ICS v5.0.0 | Interchain Security + + + + +
Version: v5.0.0

Upgrading to ICS v5.0.0

+

This ICS version uses cosmos-sdk v0.50.x and ibc-go v8.x.

+

To migrate you application to cosmos-sdk v0.50.x please use this guide.

+

To migrate your application to ibc-go v8.x.y please use the following guides:

+ +

ICS specific changes are outlined below.

+

Pre-requisite version for this upgrade: v4.x.

+

Provider

+

Keeper initialization

+
// app.go

app.ProviderKeeper = ibcproviderkeeper.NewKeeper(
appCodec,
keys[providertypes.StoreKey],
app.GetSubspace(providertypes.ModuleName),
scopedIBCProviderKeeper,
app.IBCKeeper.ChannelKeeper,
- app.IBCKeeper.PortKeeper
+ app.IBCKeeper.PortKeeper,
app.IBCKeeper.ConnectionKeeper,
app.IBCKeeper.ClientKeeper,
app.StakingKeeper,
app.SlashingKeeper,
app.AccountKeeper,
app.DistrKeeper,
app.BankKeeper,
*app.GovKeeper,
+ authtypes.NewModuleAddress(govtypes.ModuleName).String(),
+ authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),
+ authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()),
authtypes.FeeCollectorName,
)
+
    +
  • +

    authority was added - requirement for executing MsgUpdateParams

    +
      +
    • uses x/gov module address by default
    • +
    +
  • +
  • +

    validatorAddressCodec & consensusAddressCodec were added - they must match the bech32 address codec used by x/auth, x/bank, x/staking

    +
  • +
+

Protocol changes

+

Revert AfterUnbondingInitiated

+

AfterUnbondingInitiated behavior was reverted to ICS@v1.2.0-multiden

+

The revert re-introduces an additional state check.

+

See this issue for more context and the actions taken.

+

Migration (v4 -> v5)

+

ConensusVersion was bumped to 5.

+

The migration allows storing the provider module params in the x/ccv/provider module store instead of relying on legacy x/param store.

+

There are no special requirements for executing this migration.

+

Additions

+

MsgUpdateParams transaction

+

x/gov module account is selected as the default authority.

+

It is available when using gov CLI commands:

+

Drafting a proposal:

+
interchain-security-pd tx gov draft-proposal
# select "other"
# find and select "/interchain_security.ccv.provider.v1.MsgUpdateParams"
+

Submitting a proposal:

+
interchain-security-pd tx gov submit-proposal <proposal-message.json>
+

Example proposal-message.json:

+
{
"messages": [
{
"@type": "/interchain_security.ccv.provider.v1.MsgUpdateParams",
"authority": "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn",
"params": {
"trusting_period_fraction": "0.66",
"ccv_timeout_period": "2419200s",
"init_timeout_period": "604800s",
"vsc_timeout_period": "3024000s",
"slash_meter_replenish_period": "3s",
"slash_meter_replenish_fraction": "1.0",
"consumer_reward_denom_registration_fee": {
"denom": "stake",
"amount": "10000000"
},
"blocks_per_epoch": "600"
}
}
],
"metadata": "ipfs://CID",
"deposit": "10000stake",
"title": "Update Provider params",
"summary": "Update Provider params",
"expedited": false
}
+

+

When updating parameters all parameters fields must be specified. Make sure you are only changing parameters that you are interested in.

+

To avoid accidentally changing parameters you can first check the current on-chain provider params using:

+
interchain-security-pd q provider params -o json

{
"template_client": {...},
"trusting_period_fraction": "0.66",
"ccv_timeout_period": "2419200s",
"init_timeout_period": "604800s",
"vsc_timeout_period": "3024000s",
"slash_meter_replenish_period": "3s",
"slash_meter_replenish_fraction": "1.0",
"consumer_reward_denom_registration_fee": {
"denom": "stake",
"amount": "10000000"
},
"blocks_per_epoch": "600"
}
+

Governance proposals

+

Submitting the following legacy proposals is still supported:

+

Consumer addition proposal

+
interchain-security-pd tx gov submit-legacy-proposal consumer-addition <proposal_file.json>
+

Consumer removal proposal

+
interchain-security-pd tx gov submit-legacy-proposal consumer-removal <proposal_file.json>
+

Consumer addition proposal

+
interchain-security-pd tx gov submit-legacy-proposal change-reward-denoms <proposal_file.json>
+

You may also submit proposal messages above using submit-proposal.

+

Consumer

+

Keeper initialization

+
// pre-initialize ConsumerKeeper to satsfy ibckeeper.NewKeeper
app.ConsumerKeeper = ibcconsumerkeeper.NewNonZeroKeeper(
appCodec,
keys[ibcconsumertypes.StoreKey],
app.GetSubspace(ibcconsumertypes.ModuleName),
)

app.IBCKeeper = ibckeeper.NewKeeper(
appCodec,
keys[ibchost.StoreKey],
app.GetSubspace(ibchost.ModuleName),
app.ConsumerKeeper,
app.UpgradeKeeper,
scopedIBCKeeper,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

// initialize the actual consumer keeper
app.ConsumerKeeper = ibcconsumerkeeper.NewKeeper(
appCodec,
keys[ibcconsumertypes.StoreKey],
app.GetSubspace(ibcconsumertypes.ModuleName),
scopedIBCConsumerKeeper,
app.IBCKeeper.ChannelKeeper,
- &app.IBCKeeper.PortKeeper,
+ app.IBCKeeper.PortKeeper,
app.IBCKeeper.ConnectionKeeper,
app.IBCKeeper.ClientKeeper,
app.SlashingKeeper,
app.BankKeeper,
app.AccountKeeper,
&app.TransferKeeper,
app.IBCKeeper,
authtypes.FeeCollectorName,

// make sure the authority address makes sense for your chain
// the exact module account may differ depending on your setup (x/gov, x/admin or custom module)
// for x/ccv/democracy using the x/gov module address is correct
// if you don't have a way of updating consumer params you may still use the line below as it will have no affect
+ authtypes.NewModuleAddress(govtypes.ModuleName).String(),

// add address codecs
+ authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),
+ authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()),
)
+
    +
  • +

    authority was added - requirement for executing MsgUpdateParams

    +
      +
    • make sure the authority address makes sense for your chain
    • +
    • the exact module account may differ depending on your setup (x/gov, x/admin or custom module)
    • +
    • for x/ccv/democracy using the x/gov module address is correct
    • +
    • if you don't have a way of updating consumer params you may use authtypes.NewModuleAddress(govtypes.ModuleName).String() (has no effect on functionality)
    • +
    +
  • +
  • +

    validatorAddressCodec & consensusAddressCodec were added - they must match the bech32 address codec used by x/auth, x/bank, x/staking

    +
  • +
+

Additions

+

MsgUpdateParams transaction

+

This functionality is not supported on x/ccv/consumer without additional configuration.

+
    +
  • if you are using x/ccv/democracy the feature is supported out of the box
  • +
  • if you are using custom logic for changing consumer params, please update your code by providing the appropriate authority module account during ConsumerKeeper initialization in app.go.
  • +
+

You must add "/interchain_security.ccv.consumer.v1.MsgUpdateParams" to your parameters whitelist to be able to change ccvconsumer parameters via governance.

+

It is available when using gov CLI commands:

+

Drafting a proposal:

+
interchain-security-cd tx gov draft-proposal
# select "other"
# find and select "/interchain_security.ccv.consumer.v1.MsgUpdateParams"
+

Submitting a proposal:

+
    +
  • this proposal cannot be executed on chains without access to x/gov or other modules for managing governance
  • +
+

interchain-security-cdd tx gov submit-proposal <proposal-message.json>

+

Example proposal-message.json.

+
{
"messages": [
{
"@type": "/interchain_security.ccv.consumer.v1.MsgUpdateParams",
"authority": "consumer10d07y265gmmuvt4z0w9aw880jnsr700jlh7295",
"params": {
"enabled": true,
"blocks_per_distribution_transmission": "20",
"distribution_transmission_channel": "channel-1",
"provider_fee_pool_addr_str": "",
"ccv_timeout_period": "2419200s",
"transfer_timeout_period": "3000s",
"consumer_redistribution_fraction": "0.75",
"historical_entries": "10000",
"unbonding_period": "1209600s",
"soft_opt_out_threshold": "0.05",
"reward_denoms": [],
"provider_reward_denoms": [],
"retry_delay_period": "3000s"
}
}
],
"metadata": "ipfs://CID",
"deposit": "1000uatom",
"title": "Update Consumer Params -- change transfer_timeout_period to 3000s",
"summary": "Test Update Consumer Params",
"expedited": false
}
+

When updating parameters all parameters fields must be specified. Make sure you are only changing parameters that you are interested in.

+

To avoid accidentally changing parameters you can first check the current on-chain consumer params using:

+
interchain-security-pd q ccvconsumer params -o json
+

Params Query

+

Consumer params query was added:

+
interchain-security-cd q ccvconsumer params -o json

{
"params": {
"enabled": true,
"blocks_per_distribution_transmission": "1000",
"distribution_transmission_channel": "",
"provider_fee_pool_addr_str": "",
"ccv_timeout_period": "2419200s",
"transfer_timeout_period": "3600s",
"consumer_redistribution_fraction": "0.75",
"historical_entries": "10000",
"unbonding_period": "1209600s",
"soft_opt_out_threshold": "0.05",
"reward_denoms": [],
"provider_reward_denoms": [],
"retry_delay_period": "3600s"
}
}
+

Migration (v2 -> v3)

+

ConensusVersion was bumped to 3.

+

The migration allows storing the consumer module params in the x/ccv/consumer module store instead of relying on legacy x/param store.

+

There are no special requirements for executing this migration.

+

Interface method changes

+

Consumer methods were changed to match the cosmos-sdk StakingKeeper interface. +You will not need to change your code, unless you are using the ConsumerKeeper inside custom tests or you have developed custom app functionality that relies on ConsumerKeeper.

+

Please check the list below if you are using any of the consumer methods:

+
type StakingKeeper interface {
UnbondingTime(ctx context.Context) (time.Duration, error)
GetValidatorByConsAddr(ctx context.Context, consAddr sdk.ConsAddress) (stakingtypes.Validator, error)
GetLastValidatorPower(ctx context.Context, operator sdk.ValAddress) (int64, error)
Jail(context.Context, sdk.ConsAddress) error // jail a validator
Slash(ctx context.Context, consAddr sdk.ConsAddress, infractionHeight, power int64, slashFactor math.LegacyDec) (math.Int, error)
SlashWithInfractionReason(ctx context.Context, consAddr sdk.ConsAddress, infractionHeight, power int64, slashFactor math.LegacyDec, infraction stakingtypes.Infraction) (math.Int, error)
Unjail(ctx context.Context, addr sdk.ConsAddress) error
GetValidator(ctx context.Context, addr sdk.ValAddress) (stakingtypes.Validator, error)
IterateLastValidatorPowers(ctx context.Context, cb func(addr sdk.ValAddress, power int64) (stop bool)) error
IterateValidators(ctx context.Context, f func(index int64, validator stakingtypes.ValidatorI) (stop bool)) error
Validator(ctx context.Context, addr sdk.ValAddress) (stakingtypes.ValidatorI, error)
IsValidatorJailed(ctx context.Context, addr sdk.ConsAddress) (bool, error)
ValidatorByConsAddr(ctx context.Context, consAddr sdk.ConsAddress) (stakingtypes.ValidatorI, error)
Delegation(ctx context.Context, addr sdk.AccAddress, valAddr sdk.ValAddress) (stakingtypes.DelegationI, error)
MaxValidators(ctx context.Context) (uint32, error)
}
+

The consumer implements the StakingKeeper interface shown above.

+

Democracy

+

Changes in Consumer also apply to Democracy.

+

Democracy x/staking, x/distribution and x/gov were updated to reflect changes in cosmos-sdk v0.50.x.

+

There were no notable changes arising to the module functionality aside from conforming to cosmos-sdk v0.50.x.

+

Note:

+

You must add "/interchain_security.ccv.consumer.v1.MsgUpdateParams" to your parameters whitelist to be able to change consumer parameters via governance.

+ + \ No newline at end of file diff --git a/v5.0.0/upgrading/migrate_v4_v5.html.html b/v5.0.0/upgrading/migrate_v4_v5.html.html new file mode 100644 index 0000000000..d3299c3c6f --- /dev/null +++ b/v5.0.0/upgrading/migrate_v4_v5.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/validators/changeover-procedure.html b/v5.0.0/validators/changeover-procedure.html new file mode 100644 index 0000000000..9e4e79bed5 --- /dev/null +++ b/v5.0.0/validators/changeover-procedure.html @@ -0,0 +1,62 @@ + + + + + +Validator Instructions for Changeover Procedure | Interchain Security + + + + +
Version: v5.0.0

Validator Instructions for Changeover Procedure

+

More details available in Changeover Procedure documentation.

+

A major difference between launching a new consumer chain vs. onboarding a standalone chain to ICS is that there is no consumer genesis available for the standalone chain. Since a standalone chain already exists, its state must be preserved once it transitions to being a consumer chain.

+

Timeline

+

Upgrading standalone chains can be best visualised using a timeline, such as the one available Excalidraw graphic by Stride.

+

There is some flexibility with regards to how the changeover procedure is executed, so please make sure to follow the guides provided by the team doing the changeover.

+

Standalone to consumer transition timeline

+

1. ConsumerAdditionProposal on provider chain

+

This step will add the standalone chain to the list of consumer chains secured by the provider. +This step dictates the spawn_time. After spawn_time the CCV state (initial validator set of the provider) will be available to the consumer.

+

To obtain it from the provider use:

+
gaiad q provider consumer-genesis stride-1 -o json > ccv-state.json
jq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' genesis.json ccv-state.json > ccv.json
+

Transformation of the exported consumer genesis state to the target version of the consumer might be needed in case the provider and consumer formats are incompatible. +Refer to the compatibility notes here to check if data transformation is needed for your case. +Instructions on how to transform the exported CCV genesis state (ccv-state.json in the example above) to the required target version can be found here

+

2. SoftwareUpgradeProposal on the standalone/consumer chain

+

This upgrade proposal will introduce ICS to the standalone chain, making it a consumer.

+

3. Assigning a consumer key

+

After spawn_time, make sure to assign a consumer key if you intend to use one.

+

Instructions are available here

+

4. Perform the software upgrade on standalone chain

+

Please use instructions provided by the standalone chain team and make sure to reach out if you are facing issues. +The upgrade preparation depends on your setup, so please make sure you prepare ahead of time.

+
danger

The ccv.json from step 1. must be made available on the machine running the standalone/consumer chain at standalone chain upgrade_height. This file contains the initial validator set and parameters required for normal ICS operation.

Usually, the file is placed in $NODE_HOME/config but this is not a strict requirement. The exact details are available in the upgrade code of the standalone/consumer chain.

+

Performing this upgrade will transition the standalone chain to be a consumer chain.

+

After 3 blocks, the standalone chain will stop using the "old" validator set and begin using the provider validator set.

+

FAQ

+

Can I reuse the same validator key for the consumer chain that I am already using on the standalone chain? Will I need to perform a AssignConsumerKey tx with this key before spawn time?

+

Validators must either assign a key or use the same key as on the provider.

+

If you are validating both the standalone and the provider, you can use your current standalone key with some caveats:

+
    +
  • you must submit an AssignConsumerKey tx with your current standalone validator key
  • +
  • it is best to submit AssignConsumerKey tx before spawn_time
  • +
  • if you do not submit the Tx, it is assumed that you will be re-using your provider key to validate the standalone/consumer chain
  • +
+

Can I continue using the same node that was validating the standalone chain?

+

Yes.

+

Please assign your consensus key as stated above.

+

Can I set up a new node to validate the standalone/consumer chain after it transitions to replicated security?

+

Yes.

+

If you are planning to do this please make sure that the node is synced with standalone network and to submit AssignConsumerKey tx before spawn_time.

+

What happens to the standalone validator set after it transitions to replicated security?

+

The standalone chain validators will stop being validators after the first 3 blocks are created while using replicated security. The standalone validators will become governors and still can receive delegations if the consumer chain is using the consumer-democracy module.

+

Governors DO NOT VALIDATE BLOCKS.

+

Instead, they can participate in the governance process and take on other chain-specific roles.

+

Credits

+

Thank you Stride team for providing detailed instructions about the changeover procedure.

+ + \ No newline at end of file diff --git a/v5.0.0/validators/changeover-procedure.html.html b/v5.0.0/validators/changeover-procedure.html.html new file mode 100644 index 0000000000..474847df1b --- /dev/null +++ b/v5.0.0/validators/changeover-procedure.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/validators/joining-neutron.html b/v5.0.0/validators/joining-neutron.html new file mode 100644 index 0000000000..e04bcf7795 --- /dev/null +++ b/v5.0.0/validators/joining-neutron.html @@ -0,0 +1,23 @@ + + + + + +Joining Neutron | Interchain Security + + + + +
Version: v5.0.0

Joining Neutron

+

Neutron is the first consumer chain to implement ICS.

+

You can find instructions on joining the mainnet here.

+

To join Neutron chain on the interchain security testnet check here

+

Resources

+
+ + \ No newline at end of file diff --git a/v5.0.0/validators/joining-neutron.html.html b/v5.0.0/validators/joining-neutron.html.html new file mode 100644 index 0000000000..f5be710e85 --- /dev/null +++ b/v5.0.0/validators/joining-neutron.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/validators/joining-stride.html b/v5.0.0/validators/joining-stride.html new file mode 100644 index 0000000000..7203f3bedc --- /dev/null +++ b/v5.0.0/validators/joining-stride.html @@ -0,0 +1,28 @@ + + + + + +Joining Stride | Interchain Security + + + + +
Version: v5.0.0

Joining Stride

+

Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.

+

stride-1 network (mainnet) will perform a software upgrade and at height 4616678 that will transition the network to using the Cosmos Hub's (cosmoshub-4) validator set.

+

You can find instructions about the Stride consumer chain launch and joining the mainnet here.

+

This Excalidraw graphic explains the timeline of Stride's changeover procedure.

+

Note

+

Stride re-uses an existing transfer channel to send consumer rewards to the provider chain, in order to preserve existing transfer IBC denom between stride-1 and cosmoshub-4.

+

Resources

+
+ + \ No newline at end of file diff --git a/v5.0.0/validators/joining-stride.html.html b/v5.0.0/validators/joining-stride.html.html new file mode 100644 index 0000000000..73bf158e9e --- /dev/null +++ b/v5.0.0/validators/joining-stride.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/validators/joining-testnet.html b/v5.0.0/validators/joining-testnet.html new file mode 100644 index 0000000000..68829292ef --- /dev/null +++ b/v5.0.0/validators/joining-testnet.html @@ -0,0 +1,63 @@ + + + + + +Joining Interchain Security testnet | Interchain Security + + + + +
Version: v5.0.0

Joining Interchain Security testnet

Introduction

+

This short guide will teach you how to join the Interchain Security testnet.

+

The experience gained in the testnet will prepare you for validating interchain secured chains.

+
tip

Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set.

For general information about running cosmos-sdk based chains check out the validator basics and Running a Node section of Cosmos SDK docs

+

Joining the provider chain

+
info

At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain.

+

A comprehensive guide is available here.

+

Initialization

+

First, initialize your $NODE_HOME using the provider chain binary.

+
NODE_MONIKER=<your_node>
CHAIN_ID=provider
NODE_HOME=<path_to_your_home>

gaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME
+

Add your key to the keyring - more details available here.

+

In this example we will use the test keyring-backend. This option is not safe to use in production.

+
gaiad keys add <key_moniker> --keyring-backend test

# save the address as variable for later use
MY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)
+

Before issuing any transactions, use the provider testnet faucet to add funds to your address.

+
curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider

# example output:
{
"address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",
"amount": "10000000uatom",
"chain": "provider",
"hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",
"status": "success"
}
+

Then, use the account associated with the keyring to issue a create-validator transaction which will register your validator on chain.

+
gaiad tx staking create-validator \
--amount=1000000uatom \
--pubkey=$(gaiad tendermint show-validator) \
--moniker="choose a moniker" \
--chain-id=$CHAIN_ID" \
--commission-rate="0.10" \
--commission-max-rate="0.20" \
--commission-max-change-rate="0.01" \
--min-self-delegation="1000000" \
--gas="auto" \
--gas-prices="0.0025uatom" \
--from=<key_moniker>
+
tip

Check this guide to edit your validator.

+

After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use statesync to catch up to the rest of the network.

+

You can use this script to modify your config.toml with the required statesync parameters.

+
# create the statesync script
$: cd $NODE_HOME
$: touch statesync.sh
$ chmod 700 statesync.sh # make executable
+

Paste the following instructions into the statesync.sh:

+
#!/bin/bash

SNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"

LATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \
BLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \
TRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)

sed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\1true| ; \
s|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\1\"$SNAP_RPC,$SNAP_RPC\"| ; \
s|^(trust_height[[:space:]]+=[[:space:]]+).*$|\1$BLOCK_HEIGHT| ; \
s|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\1\"$TRUST_HASH\"|" $NODE_HOME/config/config.toml
+

Then, you can execute the script:

+
$: ./statesync.sh # setup config.toml for statesync
+

Finally, copy the provider genesis and start your node:

+
$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/interchain-security/provider/provider-genesis.json
$: wget $GENESIS_URL -O genesis.json
$: genesis.json $NODE_HOME/config/genesis.json
# start the service
$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"
+

Additional scripts to setup your nodes are available here and here. The scripts will configure your node and create the required services - the scripts only work in linux environments.

+

Joining consumer chains

+
tip

Once you reach the active set on the provider chain, you will be required to validate all available consumer chains.

You can use the same consensus key on all consumer chains, or opt to use a different key on each consumer chain. +Check out this guide to learn more about key assignment in interchain security.

+

To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries.

+
info

When running the provider chain and consumers on the same machine please update the PORT numbers for each of them and make sure they do not overlap (otherwise the binaries will not start).

Important ports to re-configure:

    +
  • --rpc.laddr
  • +
  • --p2p.laddr
  • +
  • --api.address
  • +
  • --grpc.address
  • +
  • --grpc-web.address
  • +
+

Re-using consensus key

+

To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the priv_validator_key.json into the home directory of your consumer chain (<consumer_home>/config/priv_validator_key.json).

+

When you start the chain, the consensus key will be the same on the provider and the consumer chain.

+

Assigning consensus keys

+

Whenever you initialize a new node, it will be configured with a consensus key you can use.

+
# machine running consumer chain
consumerd init <node_moniker> --home <home_path> --chain-id consumer-1

# use the output of this command to get the consumer chain consensus key
consumerd tendermint show-validator
# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}
+

Then, let the provider know which key you will be using for the consumer chain:

+
# machine running the provider chain
gaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b sync -y -o json
+

After this step, you are ready to copy the consumer genesis into your nodes's /config folder, start your consumer chain node and catch up to the network.

+ + \ No newline at end of file diff --git a/v5.0.0/validators/joining-testnet.html.html b/v5.0.0/validators/joining-testnet.html.html new file mode 100644 index 0000000000..1a04b74b4e --- /dev/null +++ b/v5.0.0/validators/joining-testnet.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/validators/overview.html b/v5.0.0/validators/overview.html new file mode 100644 index 0000000000..fd55ed0733 --- /dev/null +++ b/v5.0.0/validators/overview.html @@ -0,0 +1,70 @@ + + + + + +Overview | Interchain Security + + + + +
Version: v5.0.0

Overview

+
tip

We advise that you join the Replicated Security testnet to gain hands-on experience with running consumer chains.

+

At present, replicated security requires all validators of the provider chain (ie. Cosmos Hub) to run validator nodes for all governance-approved consumer chains.

+

Once a ConsumerAdditionProposal passes, validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains.

+

Provider chain and consumer chains represent standalone chains that only share the validator set ie. the same validator operators are tasked with running all chains.

+
info

To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 180 validators for Cosmos Hub).

+

Startup sequence overview

+

Consumer chains cannot start and be secured by the validator set of the provider unless a ConsumerAdditionProposal is passed. +Each proposal contains defines a spawn_time - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider.

+
tip

Validators are required to run consumer chain binaries only after spawn_time has passed.

+

Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains.

+

The image below illustrates the startup sequence +startup

+

1. Consumer Chain init + 2. Genesis generation

+

Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ConsumerAdditionProposal

+

3. Submit Proposal

+

Consumer chain team (or their advocates) submits a ConsumerAdditionProposal. +The most important parameters for validators are:

+
    +
  • spawn_time - the time after which the consumer chain must be started
  • +
  • genesis_hash - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and spawn_time is reached
  • +
  • binary_hash - hash of the consumer chain binary used to validate the software builds
  • +
+

4. CCV Genesis state generation

+

After reaching spawn_time the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain genesis.json. The CCV validator set consists of the validator set on the provider at spawn_time.

+

The state can be queried on the provider chain (in this case the Cosmos Hub):

+
 gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json
+

This is used by the launch coordinator to create the final genesis.json that will be distributed to validators in step 5.

+

5. Updating the genesis file

+

Upon reaching the spawn_time the initial validator set state will become available on the provider chain. The initial validator set is included in the final genesis.json of the consumer chain.

+

6. Chain start

+
info

The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences.

+

The new genesis.json containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided genesis.json to start their consumer chain node.

+
tip

Please pay attention to any onboarding repositories provided by the consumer chain teams. +Recommendations are available in Consumer Onboarding Checklist. +Another comprehensive guide is available in the Interchain Security testnet repo.

+

7. Creating IBC connections

+

Finally, to fully establish interchain security an IBC relayer is used to establish connections and create the required channels.

+
warning

The relayer can establish the connection only after the consumer chain starts producing blocks.

+
hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> 
hermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1
hermes start
+

Downtime Infractions

+

At present, the consumer chain can report evidence about downtime infractions to the provider chain. The min_signed_per_window and signed_blocks_window can be different on each consumer chain and are subject to changes via consumer chain governance.

+
info

Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains.

To unjail, the validator must wait for the jailing period to elapse on the provider chain and submit an unjail transaction on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains.

More information is available in Downtime Slashing documentation

+

Double-signing Infractions

+

To learn more about equivocation handling in interchain security check out the Slashing documentation section.

+

Key assignment

+

Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use.

+

For more information check out the Key assignment overview and guide

+

References:

+
+ + \ No newline at end of file diff --git a/v5.0.0/validators/overview.html.html b/v5.0.0/validators/overview.html.html new file mode 100644 index 0000000000..7e362a57e8 --- /dev/null +++ b/v5.0.0/validators/overview.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/v5.0.0/validators/withdraw_rewards.html b/v5.0.0/validators/withdraw_rewards.html new file mode 100644 index 0000000000..9da0a7dad4 --- /dev/null +++ b/v5.0.0/validators/withdraw_rewards.html @@ -0,0 +1,31 @@ + + + + + +Withdrawing consumer chain validator rewards | Interchain Security + + + + +
Version: v5.0.0

Withdrawing consumer chain validator rewards

+

Here are example steps for withdrawing rewards from consumer chains in the provider chain

+
info

The examples used are from rs-testnet, the replicated security persistent testnet.

Validator operator address: cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 +Self-delegation address: cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

+

Prior to withdrawing rewards, query balances for self-delegation address:

+
gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

balances:
- amount: "1000000000000"
denom: uatom
pagination:
next_key: null
total: "0"
+

Querying validator rewards

+

Query rewards for the validator address:

+
gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6

rewards:
- amount: "158.069895000000000000"
denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD
- amount: "841842390516.072526500000000000"
denom: uatom
+

The ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD denom represents rewards from a consumer chain.

+

Withdrawing rewards and commission

+

1. Withdraw rewards

+
gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y

txhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A
+

2. Confirm withdrawal

+

After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:

+
gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

balances:
- amount: "216"
denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD
- amount: "2233766225342"
denom: uatom
pagination:
next_key: null
total: "0"
+ + \ No newline at end of file diff --git a/v5.0.0/validators/withdraw_rewards.html.html b/v5.0.0/validators/withdraw_rewards.html.html new file mode 100644 index 0000000000..7aad67f2ea --- /dev/null +++ b/v5.0.0/validators/withdraw_rewards.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/validators/changeover-procedure.html b/validators/changeover-procedure.html new file mode 100644 index 0000000000..2da5306530 --- /dev/null +++ b/validators/changeover-procedure.html @@ -0,0 +1,62 @@ + + + + + +Validator Instructions for Changeover Procedure | Interchain Security + + + + +
Version: main

Validator Instructions for Changeover Procedure

+

More details available in Changeover Procedure documentation.

+

A major difference between launching a new consumer chain vs. onboarding a standalone chain to ICS is that there is no consumer genesis available for the standalone chain. Since a standalone chain already exists, its state must be preserved once it transitions to being a consumer chain.

+

Timeline

+

Upgrading standalone chains can be best visualised using a timeline, such as the one available Excalidraw graphic by Stride.

+

There is some flexibility with regards to how the changeover procedure is executed, so please make sure to follow the guides provided by the team doing the changeover.

+

Standalone to consumer transition timeline

+

1. ConsumerAdditionProposal on provider chain

+

This step will add the standalone chain to the list of consumer chains secured by the provider. +This step dictates the spawn_time. After spawn_time the CCV state (initial validator set of the provider) will be available to the consumer.

+

To obtain it from the provider use:

+
gaiad q provider consumer-genesis stride-1 -o json > ccv-state.json
jq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' genesis.json ccv-state.json > ccv.json
+

Transformation of the exported consumer genesis state to the target version of the consumer might be needed in case the provider and consumer formats are incompatible. +Refer to the compatibility notes here to check if data transformation is needed for your case. +Instructions on how to transform the exported CCV genesis state (ccv-state.json in the example above) to the required target version can be found here

+

2. SoftwareUpgradeProposal on the standalone/consumer chain

+

This upgrade proposal will introduce ICS to the standalone chain, making it a consumer.

+

3. Assigning a consumer key

+

After spawn_time, make sure to assign a consumer key if you intend to use one.

+

Instructions are available here

+

4. Perform the software upgrade on standalone chain

+

Please use instructions provided by the standalone chain team and make sure to reach out if you are facing issues. +The upgrade preparation depends on your setup, so please make sure you prepare ahead of time.

+
danger

The ccv.json from step 1. must be made available on the machine running the standalone/consumer chain at standalone chain upgrade_height. This file contains the initial validator set and parameters required for normal ICS operation.

Usually, the file is placed in $NODE_HOME/config but this is not a strict requirement. The exact details are available in the upgrade code of the standalone/consumer chain.

+

Performing this upgrade will transition the standalone chain to be a consumer chain.

+

After 3 blocks, the standalone chain will stop using the "old" validator set and begin using the provider validator set.

+

FAQ

+

Can I reuse the same validator key for the consumer chain that I am already using on the standalone chain? Will I need to perform a AssignConsumerKey tx with this key before spawn time?

+

Validators must either assign a key or use the same key as on the provider.

+

If you are validating both the standalone and the provider, you can use your current standalone key with some caveats:

+
    +
  • you must submit an AssignConsumerKey tx with your current standalone validator key
  • +
  • it is best to submit AssignConsumerKey tx before spawn_time
  • +
  • if you do not submit the Tx, it is assumed that you will be re-using your provider key to validate the standalone/consumer chain
  • +
+

Can I continue using the same node that was validating the standalone chain?

+

Yes.

+

Please assign your consensus key as stated above.

+

Can I set up a new node to validate the standalone/consumer chain after it transitions to Interchain Security?

+

Yes.

+

If you are planning to do this please make sure that the node is synced with standalone network and to submit AssignConsumerKey tx before spawn_time.

+

What happens to the standalone validator set after it transitions to Interchain Security?

+

The standalone chain validators will stop being validators after the first 3 blocks are created while using Interchain Security. The standalone validators will become governors and still can receive delegations if the consumer chain is using the consumer-democracy module.

+

Governors DO NOT VALIDATE BLOCKS.

+

Instead, they can participate in the governance process and take on other chain-specific roles.

+

Credits

+

Thank you Stride team for providing detailed instructions about the changeover procedure.

+ + \ No newline at end of file diff --git a/validators/changeover-procedure.html.html b/validators/changeover-procedure.html.html new file mode 100644 index 0000000000..1eb6a09f55 --- /dev/null +++ b/validators/changeover-procedure.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/validators/joining-neutron.html b/validators/joining-neutron.html new file mode 100644 index 0000000000..c1173ee0d3 --- /dev/null +++ b/validators/joining-neutron.html @@ -0,0 +1,23 @@ + + + + + +Joining Neutron | Interchain Security + + + + +
Version: main

Joining Neutron

+

Neutron is the first consumer chain to implement ICS.

+

You can find instructions on joining the mainnet here.

+

To join Neutron chain on the interchain security testnet check here

+

Resources

+
+ + \ No newline at end of file diff --git a/validators/joining-neutron.html.html b/validators/joining-neutron.html.html new file mode 100644 index 0000000000..c7851ee040 --- /dev/null +++ b/validators/joining-neutron.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/validators/joining-stride.html b/validators/joining-stride.html new file mode 100644 index 0000000000..e3192e6dfe --- /dev/null +++ b/validators/joining-stride.html @@ -0,0 +1,28 @@ + + + + + +Joining Stride | Interchain Security + + + + +
Version: main

Joining Stride

+

Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using cosmoshub-4 validator set.

+

stride-1 network (mainnet) will perform a software upgrade and at height 4616678 that will transition the network to using the Cosmos Hub's (cosmoshub-4) validator set.

+

You can find instructions about the Stride consumer chain launch and joining the mainnet here.

+

This Excalidraw graphic explains the timeline of Stride's changeover procedure.

+

Note

+

Stride re-uses an existing transfer channel to send consumer rewards to the provider chain, in order to preserve existing transfer IBC denom between stride-1 and cosmoshub-4.

+

Resources

+
+ + \ No newline at end of file diff --git a/validators/joining-stride.html.html b/validators/joining-stride.html.html new file mode 100644 index 0000000000..43c0921273 --- /dev/null +++ b/validators/joining-stride.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/validators/joining-testnet.html b/validators/joining-testnet.html new file mode 100644 index 0000000000..a74ba03cc4 --- /dev/null +++ b/validators/joining-testnet.html @@ -0,0 +1,63 @@ + + + + + +Joining Interchain Security testnet | Interchain Security + + + + +
Version: main

Joining Interchain Security testnet

Introduction

+

This short guide will teach you how to join the Interchain Security testnet.

+

The experience gained in the testnet will prepare you for validating interchain secured chains.

+
tip

Provider and consumer chain represent distinct networks and infrastructures operated by the same validator set.

For general information about running cosmos-sdk based chains check out the validator basics and Running a Node section of Cosmos SDK docs

+

Joining the provider chain

+
info

At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain.

+

A comprehensive guide is available here.

+

Initialization

+

First, initialize your $NODE_HOME using the provider chain binary.

+
NODE_MONIKER=<your_node>
CHAIN_ID=provider
NODE_HOME=<path_to_your_home>

gaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME
+

Add your key to the keyring - more details available here.

+

In this example we will use the test keyring-backend. This option is not safe to use in production.

+
gaiad keys add <key_moniker> --keyring-backend test

# save the address as variable for later use
MY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test)
+

Before issuing any transactions, use the provider testnet faucet to add funds to your address.

+
curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider

# example output:
{
"address": "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz",
"amount": "10000000uatom",
"chain": "provider",
"hash": "10BFEC53C80C9B649B66549FD88A0B6BCF09E8FCE468A73B4C4243422E724985",
"status": "success"
}
+

Then, use the account associated with the keyring to issue a create-validator transaction which will register your validator on chain.

+
gaiad tx staking create-validator \
--amount=1000000uatom \
--pubkey=$(gaiad tendermint show-validator) \
--moniker="choose a moniker" \
--chain-id=$CHAIN_ID" \
--commission-rate="0.10" \
--commission-max-rate="0.20" \
--commission-max-change-rate="0.01" \
--min-self-delegation="1000000" \
--gas="auto" \
--gas-prices="0.0025uatom" \
--from=<key_moniker>
+
tip

Check this guide to edit your validator.

+

After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use statesync to catch up to the rest of the network.

+

You can use this script to modify your config.toml with the required statesync parameters.

+
# create the statesync script
$: cd $NODE_HOME
$: touch statesync.sh
$ chmod 700 statesync.sh # make executable
+

Paste the following instructions into the statesync.sh:

+
#!/bin/bash

SNAP_RPC="https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz:443"

LATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \
BLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \
TRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash)

sed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\1true| ; \
s|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\1\"$SNAP_RPC,$SNAP_RPC\"| ; \
s|^(trust_height[[:space:]]+=[[:space:]]+).*$|\1$BLOCK_HEIGHT| ; \
s|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\1\"$TRUST_HASH\"|" $NODE_HOME/config/config.toml
+

Then, you can execute the script:

+
$: ./statesync.sh # setup config.toml for statesync
+

Finally, copy the provider genesis and start your node:

+
$: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/interchain-security/provider/provider-genesis.json
$: wget $GENESIS_URL -O genesis.json
$: genesis.json $NODE_HOME/config/genesis.json
# start the service
$: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds="08ec17e86dac67b9da70deb20177655495a55407@provider-seed-01.rs-testnet.polypore.xyz:26656,4ea6e56300a2f37b90e58de5ee27d1c9065cf871@provider-seed-02.rs-testnet.polypore.xyz:26656"
+

Additional scripts to setup your nodes are available here and here. The scripts will configure your node and create the required services - the scripts only work in linux environments.

+

Joining consumer chains

+
tip

Once you reach the active set on the provider chain, you will be required to validate all available consumer chains.

We strongly recommend that you assign a separate key for each consumer chain. +Check out this guide to learn more about key assignment in interchain security.

+

To join consumer chains, simply replicate the steps above for each consumer using the correct consumer chain binaries.

+
info

When running the provider chain and consumers on the same machine please update the PORT numbers for each of them and make sure they do not overlap (otherwise the binaries will not start).

Important ports to re-configure:

    +
  • --rpc.laddr
  • +
  • --p2p.laddr
  • +
  • --api.address
  • +
  • --grpc.address
  • +
  • --grpc-web.address
  • +
+

Re-using consensus key

+

To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the priv_validator_key.json into the home directory of your consumer chain (<consumer_home>/config/priv_validator_key.json).

+

When you start the chain, the consensus key will be the same on the provider and the consumer chain.

+

Assigning consensus keys

+

Whenever you initialize a new node, it will be configured with a consensus key you can use.

+
# machine running consumer chain
consumerd init <node_moniker> --home <home_path> --chain-id consumer-1

# use the output of this command to get the consumer chain consensus key
consumerd tendermint show-validator
# output: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}
+

Then, let the provider know which key you will be using for the consumer chain:

+
# machine running the provider chain
gaiad tx provider assign-consensus-key consumer-1 '<consumer_pubkey>' --from <key_moniker> --home $NODE_HOME --gas 900000 -b sync -y -o json
+

After this step, you are ready to copy the consumer genesis into your nodes's /config folder, start your consumer chain node and catch up to the network.

+ + \ No newline at end of file diff --git a/validators/joining-testnet.html.html b/validators/joining-testnet.html.html new file mode 100644 index 0000000000..786380b744 --- /dev/null +++ b/validators/joining-testnet.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/validators/overview.html b/validators/overview.html new file mode 100644 index 0000000000..b29e0effd1 --- /dev/null +++ b/validators/overview.html @@ -0,0 +1,74 @@ + + + + + +Overview | Interchain Security + + + + +
Version: main

Overview

+
tip

We advise that you join the Interchain Security testnet to gain hands-on experience with running consumer chains.

+

At present, Interchain Security requires some or all the validators of the provider chain (ie. Cosmos Hub) to run validator nodes for a consumer chain. +Whether a validator has to run a validator node for a consumer chain depends on whether the consumer chain is a Top N or an +Opt-In chain and also on the power-shaping features. A validator can use the +has-to-validate query +to keep track of all the chains it has to validate.

+

Once a ConsumerAdditionProposal passes, relevant validators need to prepare to run the consumer chain binaries (these will be linked in their proposals) and set up validator nodes on governance-approved consumer chains.

+

Provider chain and consumer chains represent standalone chains that only share part of the validator set.

+
info

To validate a consumer chain and be eligible for rewards, validators are required to be in the active set of the provider chain (first 180 validators for Cosmos Hub).

+

Startup sequence overview

+

Consumer chains cannot start and be secured by the validator set of the provider unless a ConsumerAdditionProposal is passed. +Each proposal contains defines a spawn_time - the timestamp when the consumer chain genesis is finalized and the consumer chain clients get initialized on the provider.

+
tip

Validators are required to run consumer chain binaries only after spawn_time has passed.

+

Please note that any additional instructions pertaining to specific consumer chain launches will be available before spawn time. The chain start will be stewarded by the Cosmos Hub team and the teams developing their respective consumer chains.

+

The image below illustrates the startup sequence +startup

+

1. Consumer Chain init + 2. Genesis generation

+

Consumer chain team initializes the chain genesis.json and prepares binaries which will be listed in the ConsumerAdditionProposal

+

3. Submit Proposal

+

Consumer chain team (or their advocates) submits a ConsumerAdditionProposal. +The most important parameters for validators are:

+
    +
  • spawn_time - the time after which the consumer chain must be started
  • +
  • genesis_hash - hash of the pre-ccv genesis.json; the file does not contain any validator info -> the information is available only after the proposal is passed and spawn_time is reached
  • +
  • binary_hash - hash of the consumer chain binary used to validate the software builds
  • +
+

4. CCV Genesis state generation

+

After reaching spawn_time the provider chain will automatically create the CCV validator states that will be used to populate the corresponding fields in the consumer chain genesis.json. The CCV validator set consists of the validator set on the provider at spawn_time.

+

The state can be queried on the provider chain (in this case the Cosmos Hub):

+
 gaiad query provider consumer-genesis <consumer chain ID> -o json > ccvconsumer_genesis.json
+

This is used by the launch coordinator to create the final genesis.json that will be distributed to validators in step 5.

+

5. Updating the genesis file

+

Upon reaching the spawn_time the initial validator set state will become available on the provider chain. The initial validator set is included in the final genesis.json of the consumer chain.

+

6. Chain start

+
info

The consumer chain will start producing blocks as soon as 66.67% of the provider chain's voting power comes online (on the consumer chain). The relayer should be started after block production commences.

+

The new genesis.json containing the initial validator set will be distributed to validators by the consumer chain team (launch coordinator). Each validator should use the provided genesis.json to start their consumer chain node.

+
tip

Please pay attention to any onboarding repositories provided by the consumer chain teams. +Recommendations are available in Consumer Onboarding Checklist. +Another comprehensive guide is available in the Interchain Security testnet repo.

+

7. Creating IBC connections

+

Finally, to fully establish interchain security an IBC relayer is used to establish connections and create the required channels.

+
warning

The relayer can establish the connection only after the consumer chain starts producing blocks.

+
hermes create connection --a-chain <consumer chain ID> --a-client 07-tendermint-0 --b-client <client assigned by provider chain> 
hermes create channel --a-chain <consumer chain ID> --a-port consumer --b-port provider --order ordered --a-connection connection-0 --channel-version 1
hermes start
+

Downtime Infractions

+

At present, the consumer chain can report evidence about downtime infractions to the provider chain. The min_signed_per_window and signed_blocks_window can be different on each consumer chain and are subject to changes via consumer chain governance.

+
info

Causing a downtime infraction on any consumer chain will not incur a slash penalty. Instead, the offending validator will be jailed on the provider chain and consequently on all consumer chains.

To unjail, the validator must wait for the jailing period to elapse on the provider chain and submit an unjail transaction on the provider chain. After unjailing on the provider, the validator will be unjailed on all consumer chains.

More information is available in Downtime Slashing documentation

+

Double-signing Infractions

+

To learn more about equivocation handling in interchain security check out the Slashing documentation section.

+

Key assignment

+

Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use.

+

For more information check out the Key assignment overview and guide

+

References:

+
+ + \ No newline at end of file diff --git a/validators/overview.html.html b/validators/overview.html.html new file mode 100644 index 0000000000..c136df1ef8 --- /dev/null +++ b/validators/overview.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/validators/partial-set-security-for-validators.html b/validators/partial-set-security-for-validators.html new file mode 100644 index 0000000000..1e81a588d6 --- /dev/null +++ b/validators/partial-set-security-for-validators.html @@ -0,0 +1,113 @@ + + + + + +Partial Set Security | Interchain Security + + + + +
Version: main

Partial Set Security

+

Partial Set Security allows consumer chains to join as Opt-In or Top N. +Here, we show how a validator can opt in, opt out, or set a custom commission rate on a consumer chain, as well +as useful queries that a validator can use to figure out which chains it has to validate, etc.

+

Messages

+

How to opt in to a consumer chain?

+
warning

A validator is automatically opted in to a Top N chain if the validator belongs to the top N% of the validators on the provider chain.

+

In a Top N chain, a validator that does not belong to the top N% of the validators on the provider can still choose +to opt in to a consumer chain. In other words, validators can opt in, in both Opt-In and Top N chains.

+

A validator can opt in to a consumer chain by issuing the following message:

+
interchain-security-pd tx provider opt-in <consumer-chain-id> <optional consumer-pub-key>
+

where

+
    +
  • consumer-chain-id is the string identifier of the consumer chain the validator wants to opt in to;
  • +
  • consumer-pub-key corresponds to the public key the validator wants to use on the consumer chain, and it has the +following format {"@type":"/cosmos.crypto.ed25519.PubKey","key":"<key>"}.
  • +
+

A validator can opt in to an existing consumer chain that is already running, or to a proposed +consumer chain that is still being voted on. A validator can use the following command to retrieve the currently existing +consumer chains:

+
interchain-security-pd query provider list-consumer-chains
+

and this command to see the currently proposed consumer chains:

+
interchain-security-pd query provider list-proposed-consumer-chains
+
tip

By setting the consumer-pub-key, a validator can both opt in to a chain and assign a +public key on a consumer chain. Note that a validator can always assign +a new consumer key at a later stage. The key-assignment rules +still apply when setting consumer-pub-key when opting in.

+
info

A validator is only eligible for consumer rewards from a consumer chain if the validator is opted into that chain.

+

How to opt out from a consumer chain?

+

A validator can opt out from a consumer by issuing the following message:

+
interchain-security-pd tx provider opt-out <consumer-chain-id>
+

where

+
    +
  • consumer-chain-id is the string identifier of the consumer chain.
  • +
+
warning

A validator cannot opt out from a Top N chain if it belongs to the top N% validators of the provider.

+
warning

If a validator moves from the Top N to outside of the top N% of the validators on the provider, it will not +be automatically opted-out. The validator has to manually opt out.

+
warning

A validator can stop its node on a consumer chain only after opting out and confirming through the has-to-validate +query (see below) that it does +not have to validate the consumer chain any longer.

+
warning

If all validators opt out from an Opt-In chain, the chain will halt with a consensus failure upon receiving the VSCPacket with an empty validator set.

+

How to set specific per consumer chain commission rate?

+

A validator can choose to set a different commission rate on each of the consumer chains. +This can be done with the following command:

+
interchain-security-pd tx provider set-consumer-commission-rate <consumer-chain-id> <commission-rate>
+

where

+
    +
  • consumer-chain-id is the string identifier of the consumer chain;
  • +
  • comission-rate decimal in [minRate, 1] where minRate corresponds to the minimum commission rate set on the +provider chain (see min_commission_rate in interchain-security-pd query staking params).
  • +
+

If a validator does not set a commission rate on a consumer chain, the commission rate defaults to their commission rate on the provider chain.

+
tip

Validators can set their commission rate even for consumer chains that they are not currently opted in on, and the commission rate will be applied when they opt in. This is particularly useful for Top N chains, where validators might be opted in automatically, +so validators can set the commission rate in advance.

+
tip

If a validator opts out and then back in, this will not reset their commission rate back to the default. Instead, their +set commission rate still applies.

+

Queries

+

Partial Set Security introduces a number of queries to assist validators determine which consumer chains they have to +validate, their commission rate per chain, etc.

+

Which chains does a validator have to validate?

+

Naturally, a validator is aware of the Opt-In chains it has to validate because in order to validate an Opt-In chain, +a validator has to manually opt in to the chain. This is not the case for Top N chains where a validator might be required +to validate such a chain without explicitly opting in if it belongs to the top N% of the validators on the provider.

+

We introduce the following query:

+
interchain-security-pd query provider has-to-validate <provider-validator-address>
+

that can be used by validator with provider-validator-address address to retrieve the list of chains that it has to validate.

+
tip

As a validator, the list of chains returned by has-to-validate is the list of chains you should be validating to avoid +getting jailed for downtime.

+

How do you know how much voting power you need to have to be in the top N for a chain?

+

This can be seen as part of the list-consumer-chains query:

+
interchain-security-pd query provider list-consumer-chains
+

where the min_power_in_top_N field shows the minimum voting power required to be +automatically opted in to the chain.

+
tip

list-consumer-chains shows the minimal voting power right now, but +the automatic opt-in happens only when epochs end on the provider. +In consequence, a validators power might be large enough to be automatically opted in +during an epoch, but if their power is sufficiently decreased before the epoch ends, +they will not be opted in automatically.

+

How to retrieve all the opted-in validators on a consumer chain?

+

With the following query:

+
interchain-security-pd query provider consumer-opted-in-validators <consumer-chain-id>
+

we can see all the opted-in validators on consumer-chain-id that were manually or automatically opted in.

+

How to retrieve all the consumer validators on a consumer chain?

+

With the following query:

+
interchain-security-pd query provider consumer-validators <consumer-chain-id>
+

we can see all the consumer validators (i.e., validator set) of consumer-chain-id. The consumer validators are the +ones that are currently (or in the future, see warning) validating the consumer chain. A consumer validator is an opted-in +validator but not vice versa. For example, an opted-in validator V might not be a consumer validator because V is +denylisted or because V is removed due to a validator-set cap.

+
warning

The returned consumer validators from this query do not necessarily correspond to the validator set that is +validating the consumer chain at this exact moment. This is because the VSCPacket sent to a consumer chain might be +delayed and hence this query might return the validator set that the consumer chain would have at some future +point in time.

+

How can we see the commission rate a validator has set on a consumer chain?

+

Using the following query:

+
interchain-security-pd query provider validator-consumer-commission-rate <consumer-chain-id> <provider-validator-address>
+

we retrieve the commission rate set by validator with provider-validator-address address on consumer-chain-id.

+ + \ No newline at end of file diff --git a/validators/partial-set-security-for-validators.html.html b/validators/partial-set-security-for-validators.html.html new file mode 100644 index 0000000000..cdbc3c0d7d --- /dev/null +++ b/validators/partial-set-security-for-validators.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/validators/withdraw_rewards.html b/validators/withdraw_rewards.html new file mode 100644 index 0000000000..a05ea05346 --- /dev/null +++ b/validators/withdraw_rewards.html @@ -0,0 +1,36 @@ + + + + + +Consumer chain validator rewards | Interchain Security + + + + +
Version: main

Consumer chain validator rewards

+
warning

A validator can only receive rewards from a consumer chain if the validator has been validating the consumer chain +for some time. Specifically, the validator has to be a consumer validator of the consumer chain for at least +NumberOfEpochsToStartReceivingRewards * BlocksPerEpoch blocks (run interchain-security-pd query provider params for +the actual values of the NumberOfEpochsToStartReceivingRewards and BlocksPerEpoch params).

+

Withdrawing rewards

+

Here are example steps for withdrawing rewards from consumer chains in the provider chain

+
info

The examples used are from rs-testnet, the Interchain Security persistent testnet.

Validator operator address: cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 +Self-delegation address: cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

+

Prior to withdrawing rewards, query balances for self-delegation address:

+
gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

balances:
- amount: "1000000000000"
denom: uatom
pagination:
next_key: null
total: "0"
+

Querying validator rewards

+

Query rewards for the validator address:

+
gaiad q distribution rewards cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6

rewards:
- amount: "158.069895000000000000"
denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD
- amount: "841842390516.072526500000000000"
denom: uatom
+

The ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD denom represents rewards from a consumer chain.

+

Withdrawing rewards and commission

+

1. Withdraw rewards

+
gaiad tx distribution withdraw-rewards cosmosvaloper1e5yfpc8l6g4808fclmlyd38tjgxuwshnmjkrq6 --from cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf --commission --chain-id provider --gas auto --fees 500uatom -b block -y

txhash: A7E384FB1958211B43B7C06527FC7D4471FB6B491EE56FDEA9C5634D76FF1B9A
+

2. Confirm withdrawal

+

After withdrawing rewards self-delegation address balance to confirm rewards were withdrawn:

+
gaiad q bank balances cosmos1e5yfpc8l6g4808fclmlyd38tjgxuwshn7xzkvf

balances:
- amount: "216"
denom: ibc/2CB0E87E2A742166FEC0A18D6FBF0F6AD4AA1ADE694792C1BD6F5E99088D67FD
- amount: "2233766225342"
denom: uatom
pagination:
next_key: null
total: "0"
+ + \ No newline at end of file diff --git a/validators/withdraw_rewards.html.html b/validators/withdraw_rewards.html.html new file mode 100644 index 0000000000..28023f1da3 --- /dev/null +++ b/validators/withdraw_rewards.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file