diff --git a/.gitignore b/.gitignore index 9781f69ef5..26659679aa 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ docs/modules dist tools-stamp proto-tools-stamp +buf-stamp artifacts # Data - ideally these don't exist diff --git a/proto/cosmos/upgrade/v1beta1/upgrade.proto b/proto/cosmos/upgrade/v1beta1/upgrade.proto index b5f976bdef..858634b2b2 100644 --- a/proto/cosmos/upgrade/v1beta1/upgrade.proto +++ b/proto/cosmos/upgrade/v1beta1/upgrade.proto @@ -1,6 +1,7 @@ syntax = "proto3"; package cosmos.upgrade.v1beta1; +import "google/protobuf/any.proto"; import "gogoproto/gogo.proto"; import "google/protobuf/timestamp.proto"; @@ -32,6 +33,13 @@ message Plan { // Any application specific upgrade info to be included on-chain // such as a git commit that validators could automatically upgrade to string info = 4; + + // IBC-enabled chains can opt-in to including the upgraded client state in its upgrade plan + // This will make the chain commit to the correct upgraded (self) client state before the upgrade occurs, + // so that connecting chains can verify that the new upgraded client is valid by verifying a proof on the + // previous version of the chain. + // This will allow IBC connections to persist smoothly across planned chain upgrades + google.protobuf.Any upgraded_client_state = 5 [(gogoproto.moretags) = "yaml:\"upgraded_client_state\""];; } // SoftwareUpgradeProposal is a gov Content type for initiating a software diff --git a/proto/ibc/client/client.proto b/proto/ibc/client/client.proto index 563bd54607..f91ce9af2e 100644 --- a/proto/ibc/client/client.proto +++ b/proto/ibc/client/client.proto @@ -78,6 +78,18 @@ message MsgUpdateClient { string signer = 3; } +// MsgUpgradeClient defines an sdk.Msg to upgrade an IBC client to a new client state +message MsgUpgradeClient { + // client unique identifier + string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; + // upgraded client state + google.protobuf.Any client_state = 2 [(gogoproto.moretags) = "yaml:\"client_state\""]; + // proof that old chain committed to new client + bytes proof_upgrade = 3 [(gogoproto.moretags) = "yaml:\"proof_upgrade\""]; + // signer address + string signer = 4; +} + // MsgSubmitMisbehaviour defines an sdk.Msg type that submits Evidence for // light client misbehaviour. message MsgSubmitMisbehaviour { diff --git a/proto/ibc/commitment/commitment.proto b/proto/ibc/commitment/commitment.proto index eed9f7b904..50795f8301 100644 --- a/proto/ibc/commitment/commitment.proto +++ b/proto/ibc/commitment/commitment.proto @@ -49,13 +49,12 @@ message KeyPath { message Key { option (gogoproto.goproto_getters) = false; - bytes name = 1 [(gogoproto.customname) = "name"]; - KeyEncoding enc = 2 [(gogoproto.customname) = "enc"]; + bytes name = 1; + KeyEncoding enc = 2; } // KeyEncoding defines the encoding format of a key's bytes. enum KeyEncoding { - option (gogoproto.goproto_enum_stringer) = false; option (gogoproto.goproto_enum_prefix) = false; // URL encoding diff --git a/proto/ibc/tendermint/tendermint.proto b/proto/ibc/tendermint/tendermint.proto index da762135bb..ee15f4d2b5 100644 --- a/proto/ibc/tendermint/tendermint.proto +++ b/proto/ibc/tendermint/tendermint.proto @@ -39,12 +39,15 @@ message ClientState { // Proof specifications used in verifying counterparty state repeated ics23.ProofSpec proof_specs = 8 [(gogoproto.moretags) = "yaml:\"proof_specs\""]; + // Path at which next upgraded client will be committed + ibc.commitment.MerklePath upgrade_path = 9 [(gogoproto.moretags) = "yaml:\"upgrade_path\""]; + // This flag, when set to true, will allow governance to recover a client // which has expired - bool allow_update_after_expiry = 9 [(gogoproto.moretags) = "yaml:\"allow_update_after_expiry\""]; + bool allow_update_after_expiry = 10 [(gogoproto.moretags) = "yaml:\"allow_update_after_expiry\""]; // This flag, when set to true, will allow governance to unfreeze a client // whose chain has experienced a misbehaviour event - bool allow_update_after_misbehaviour = 10 [(gogoproto.moretags) = "yaml:\"allow_update_after_misbehaviour\""]; + bool allow_update_after_misbehaviour = 11 [(gogoproto.moretags) = "yaml:\"allow_update_after_misbehaviour\""]; } // ConsensusState defines the consensus state from Tendermint. diff --git a/x/ibc/02-client/handler.go b/x/ibc/02-client/handler.go index 68c665fc24..f824846001 100644 --- a/x/ibc/02-client/handler.go +++ b/x/ibc/02-client/handler.go @@ -65,6 +65,33 @@ func HandleMsgUpdateClient(ctx sdk.Context, k keeper.Keeper, msg *types.MsgUpdat }, nil } +// HandleMsgUpgradeClient defines the sdk.Handler for MsgUpgradeClient +func HandleMsgUpgradeClient(ctx sdk.Context, k keeper.Keeper, msg *types.MsgUpgradeClient) (*sdk.Result, error) { + upgradedClient, err := types.UnpackClientState(msg.ClientState) + if err != nil { + return nil, err + } + + if err := upgradedClient.Validate(); err != nil { + return nil, err + } + + if err = k.UpgradeClient(ctx, msg.ClientId, upgradedClient, msg.ProofUpgrade); err != nil { + return nil, err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + ) + + return &sdk.Result{ + Events: ctx.EventManager().Events().ToABCIEvents(), + }, nil +} + // HandleMsgSubmitMisbehaviour defines the Evidence module handler for submitting a // light client misbehaviour. func HandleMsgSubmitMisbehaviour(ctx sdk.Context, k keeper.Keeper, msg *types.MsgSubmitMisbehaviour) (*sdk.Result, error) { diff --git a/x/ibc/02-client/handler_test.go b/x/ibc/02-client/handler_test.go index 9b6f0ce412..265d2e9da2 100644 --- a/x/ibc/02-client/handler_test.go +++ b/x/ibc/02-client/handler_test.go @@ -1,13 +1,20 @@ package client_test import ( + "time" + sdk "github.com/cosmos/cosmos-sdk/types" distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + "github.com/cosmos/cosmos-sdk/x/ibc/exported" + solomachinetypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/solomachine/types" ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) func (suite *ClientTestSuite) TestNewClientUpdateProposalHandler() { @@ -73,3 +80,152 @@ func (suite *ClientTestSuite) TestNewClientUpdateProposalHandler() { } } + +func (suite *ClientTestSuite) TestUpgradeClient() { + var ( + clientA string + upgradedClient exported.ClientState + msg *clienttypes.MsgUpgradeClient + ) + + upgradeHeight := clienttypes.NewHeight(1, 1) + + cases := []struct { + name string + setup func() + expPass bool + }{ + { + name: "successful upgrade", + setup: func() { + + upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod+ibctesting.TrustingPeriod, ibctesting.MaxClockDrift, upgradeHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) + // zero custom fields and store in upgrade store + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), upgradedClient) + + // commit upgrade store changes and update clients + + suite.coordinator.CommitBlock(suite.chainB) + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, ibctesting.Tendermint) + suite.Require().NoError(err) + + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgrade, _ := suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight()) + + msg, err = clienttypes.NewMsgUpgradeClient(clientA, upgradedClient, proofUpgrade, suite.chainA.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + expPass: true, + }, + { + name: "successful upgrade to different client type", + setup: func() { + + // previous chain committed to the change + upgradedClient = ibctesting.NewSolomachine(suite.T(), suite.chainA.App.AppCodec(), clientA, "diversifier", 1).ClientState() + soloClient, _ := upgradedClient.(*solomachinetypes.ClientState) + // change sequence to be higher height than latest current client height + soloClient.Sequence = 100000000000 + // zero custom fields and store in upgrade store + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), soloClient) + + // commit upgrade store changes and update clients + + suite.coordinator.CommitBlock(suite.chainB) + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, ibctesting.Tendermint) + suite.Require().NoError(err) + + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgrade, _ := suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight()) + + msg, err = clienttypes.NewMsgUpgradeClient(clientA, upgradedClient, proofUpgrade, suite.chainA.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + expPass: true, + }, + { + name: "invalid upgrade: msg.ClientState does not contain valid clientstate", + setup: func() { + + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgrade, _ := suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight()) + + consState := ibctmtypes.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("app_hash")), []byte("next_vals_hash")) + consAny, err := clienttypes.PackConsensusState(consState) + suite.Require().NoError(err) + + msg = &types.MsgUpgradeClient{ClientId: clientA, ClientState: consAny, ProofUpgrade: proofUpgrade, Signer: suite.chainA.SenderAccount.GetAddress().String()} + }, + expPass: false, + }, + { + name: "invalid clientstate", + setup: func() { + + upgradedClient = ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod+ibctesting.TrustingPeriod, ibctesting.MaxClockDrift, upgradeHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) + // zero custom fields and store in upgrade store + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), upgradedClient) + + // commit upgrade store changes and update clients + + suite.coordinator.CommitBlock(suite.chainB) + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, ibctesting.Tendermint) + suite.Require().NoError(err) + + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgrade, _ := suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight()) + + msg, err = clienttypes.NewMsgUpgradeClient(clientA, upgradedClient, proofUpgrade, suite.chainA.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + expPass: false, + }, + { + name: "VerifyUpgrade fails", + setup: func() { + + upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod+ibctesting.TrustingPeriod, ibctesting.MaxClockDrift, upgradeHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) + // zero custom fields and store in upgrade store + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), upgradedClient) + + // commit upgrade store changes and update clients + + suite.coordinator.CommitBlock(suite.chainB) + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, ibctesting.Tendermint) + suite.Require().NoError(err) + + msg, err = clienttypes.NewMsgUpgradeClient(clientA, upgradedClient, nil, suite.chainA.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + expPass: false, + }, + } + + for _, tc := range cases { + tc := tc + clientA, _ = suite.coordinator.SetupClients(suite.chainA, suite.chainB, ibctesting.Tendermint) + + tc.setup() + + _, err := client.HandleMsgUpgradeClient( + suite.chainA.GetContext(), suite.chainA.App.IBCKeeper.ClientKeeper, msg, + ) + + if tc.expPass { + suite.Require().NoError(err, "upgrade handler failed on valid case: %s", tc.name) + newClient, ok := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(ok) + suite.Require().Equal(upgradedClient, newClient) + } else { + suite.Require().Error(err, "upgrade handler passed on invalid case: %s", tc.name) + } + } +} diff --git a/x/ibc/02-client/keeper/client.go b/x/ibc/02-client/keeper/client.go index bd96aaa750..4ad5fc7717 100644 --- a/x/ibc/02-client/keeper/client.go +++ b/x/ibc/02-client/keeper/client.go @@ -65,7 +65,7 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H consensusHeight = types.GetSelfHeight(ctx) } - k.Logger(ctx).Info(fmt.Sprintf("client %s updated height %d", clientID, consensusHeight)) + k.Logger(ctx).Info("client state updated", "client-id", clientID, "height", consensusHeight) // emitting events in the keeper emits for both begin block and handler client updates ctx.EventManager().EmitEvent( @@ -80,6 +80,41 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H return nil } +// UpgradeClient upgrades the client to a new client state if this new client was committed to +// by the old client at the specified upgrade height +func (k Keeper) UpgradeClient(ctx sdk.Context, clientID string, upgradedClient exported.ClientState, proofUpgrade []byte) error { + clientState, found := k.GetClientState(ctx, clientID) + if !found { + return sdkerrors.Wrapf(types.ErrClientNotFound, "cannot update client with ID %s", clientID) + } + + // prevent upgrade if current client is frozen + if clientState.IsFrozen() { + return sdkerrors.Wrapf(types.ErrClientFrozen, "cannot update client with ID %s", clientID) + } + + err := clientState.VerifyUpgrade(ctx, k.cdc, k.ClientStore(ctx, clientID), upgradedClient, proofUpgrade) + if err != nil { + return sdkerrors.Wrapf(err, "cannot upgrade client with ID: %s", clientID) + } + + k.SetClientState(ctx, clientID, upgradedClient) + + k.Logger(ctx).Info("client state upgraded", "client-id", clientID, "height", upgradedClient.GetLatestHeight()) + + // emitting events in the keeper emits for client upgrades + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeUpgradeClient, + sdk.NewAttribute(types.AttributeKeyClientID, clientID), + sdk.NewAttribute(types.AttributeKeyClientType, clientState.ClientType()), + sdk.NewAttribute(types.AttributeKeyConsensusHeight, upgradedClient.GetLatestHeight().String()), + ), + ) + + return nil +} + // CheckMisbehaviourAndUpdateState checks for client misbehaviour and freezes the // client if so. func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, misbehaviour exported.Misbehaviour) error { diff --git a/x/ibc/02-client/keeper/client_test.go b/x/ibc/02-client/keeper/client_test.go index cadb7cacd8..d6a74bf8ed 100644 --- a/x/ibc/02-client/keeper/client_test.go +++ b/x/ibc/02-client/keeper/client_test.go @@ -13,7 +13,11 @@ import ( localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types" commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" "github.com/cosmos/cosmos-sdk/x/ibc/exported" + solomachinetypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/solomachine/types" + ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing" ibctestingmock "github.com/cosmos/cosmos-sdk/x/ibc/testing/mock" + + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) func (suite *KeeperTestSuite) TestCreateClient() { @@ -32,11 +36,11 @@ func (suite *KeeperTestSuite) TestCreateClient() { i := i if tc.expPanic { suite.Require().Panics(func() { - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false) + clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) suite.keeper.CreateClient(suite.ctx, tc.clientID, clientState, suite.consensusState) }, "Msg %d didn't panic: %s", i, tc.msg) } else { - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false) + clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) if tc.expPass { suite.Require().NotNil(clientState, "valid test case %d failed: %s", i, tc.msg) } @@ -79,7 +83,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { expPass bool }{ {"valid update", func() error { - clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false) + clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) // store intermediate consensus state to check that trustedHeight does not need to be highest consensus state before header height @@ -97,7 +101,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { return err }, true}, {"valid past update", func() error { - clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false) + clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) suite.Require().NoError(err) @@ -130,7 +134,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { return nil }, false}, {"consensus state not found", func() error { - clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false) + clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) suite.keeper.SetClientState(suite.ctx, testClientID, clientState) updateHeader = createFutureUpdateFn(suite) @@ -144,7 +148,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { return nil }, false}, {"valid past update before client was frozen", func() error { - clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false) + clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) clientState.FrozenHeight = types.NewHeight(0, testClientHeight.EpochHeight-1) err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) suite.Require().NoError(err) @@ -164,7 +168,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { return nil }, true}, {"invalid header", func() error { - clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false) + clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) suite.Require().NoError(err) updateHeader = createPastUpdateFn(suite) @@ -232,6 +236,156 @@ func (suite *KeeperTestSuite) TestUpdateClientLocalhost() { suite.Require().Equal(localhostClient.GetLatestHeight().(types.Height).Increment(), clientState.GetLatestHeight()) } +func (suite *KeeperTestSuite) TestUpgradeClient() { + var ( + upgradedClient exported.ClientState + clientA string + proofUpgrade []byte + ) + + testCases := []struct { + name string + setup func() + expPass bool + }{ + { + name: "successful upgrade to a new tendermint client", + setup: func() { + + upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, upgradeHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) + // zero custom fields and store in upgrade store + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), upgradedClient) + + // commit upgrade store changes and update clients + + suite.coordinator.CommitBlock(suite.chainB) + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, ibctesting.Tendermint) + suite.Require().NoError(err) + + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight()) + }, + expPass: true, + }, + { + name: "successful upgrade to a solomachine client", + setup: func() { + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + // demonstrate that VerifyUpgrade allows for arbitrary changes to clienstate structure so long as + // previous chain committed to the change + upgradedClient = ibctesting.NewSolomachine(suite.T(), suite.cdc, clientA, "diversifier", 1).ClientState() + soloClient, _ := upgradedClient.(*solomachinetypes.ClientState) + // change sequence to be higher height than latest current client height + soloClient.Sequence = cs.GetLatestHeight().GetEpochHeight() + 100 + // zero custom fields and store in upgrade store + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), upgradedClient) + + suite.coordinator.CommitBlock(suite.chainB) + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, ibctesting.Tendermint) + suite.Require().NoError(err) + + cs, found = suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight()) + }, + expPass: true, + }, + { + name: "client state not found", + setup: func() { + + upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, upgradeHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) + // zero custom fields and store in upgrade store + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), upgradedClient) + + // commit upgrade store changes and update clients + + suite.coordinator.CommitBlock(suite.chainB) + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, ibctesting.Tendermint) + suite.Require().NoError(err) + + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight()) + + clientA = "wrongclientid" + }, + expPass: false, + }, + { + name: "client state frozen", + setup: func() { + + upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, upgradeHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) + // zero custom fields and store in upgrade store + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), upgradedClient) + + // commit upgrade store changes and update clients + + suite.coordinator.CommitBlock(suite.chainB) + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, ibctesting.Tendermint) + suite.Require().NoError(err) + + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight()) + + // set frozen client in store + tmClient, ok := cs.(*ibctmtypes.ClientState) + suite.Require().True(ok) + tmClient.FrozenHeight = types.NewHeight(0, 1) + suite.chainA.App.IBCKeeper.ClientKeeper.SetClientState(suite.chainA.GetContext(), clientA, tmClient) + }, + expPass: false, + }, + { + name: "tendermint client VerifyUpgrade fails", + setup: func() { + + upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, upgradeHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) + // zero custom fields and store in upgrade store + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), upgradedClient) + + // change upgradedClient client-specified parameters + upgradedClient = ibctmtypes.NewClientState("wrongchainID", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, upgradeHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, true, true) + + suite.coordinator.CommitBlock(suite.chainB) + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, ibctesting.Tendermint) + suite.Require().NoError(err) + + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight()) + }, + expPass: false, + }, + } + + for _, tc := range testCases { + tc := tc + clientA, _ = suite.coordinator.SetupClients(suite.chainA, suite.chainB, ibctesting.Tendermint) + + tc.setup() + + err := suite.chainA.App.IBCKeeper.ClientKeeper.UpgradeClient(suite.chainA.GetContext(), clientA, upgradedClient, proofUpgrade) + + if tc.expPass { + suite.Require().NoError(err, "verify upgrade failed on valid case: %s", tc.name) + } else { + suite.Require().Error(err, "verify upgrade passed on invalid case: %s", tc.name) + } + } + +} + func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { altPrivVal := ibctestingmock.NewPV() altPubKey, err := altPrivVal.GetPubKey() @@ -276,7 +430,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { }, func() error { suite.consensusState.NextValidatorsHash = bothValsHash - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false) + clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) return err @@ -293,7 +447,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { }, func() error { suite.consensusState.NextValidatorsHash = valsHash - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false) + clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) // store intermediate consensus state to check that trustedHeight does not need to be highest consensus state before header height @@ -320,7 +474,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { }, func() error { suite.consensusState.NextValidatorsHash = valsHash - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false) + clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) // store trusted consensus state for Header2 @@ -347,7 +501,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { }, func() error { suite.consensusState.NextValidatorsHash = valsHash - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false) + clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) // intermediate consensus state at height + 3 is not created return err @@ -364,7 +518,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { }, func() error { suite.consensusState.NextValidatorsHash = valsHash - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false) + clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) // intermediate consensus state at height + 3 is not created return err @@ -387,7 +541,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { }, func() error { suite.consensusState.NextValidatorsHash = bothValsHash - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false) + clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) clientState.FrozenHeight = types.NewHeight(0, 1) @@ -406,7 +560,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { ClientId: testClientID, }, func() error { - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false) + clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) if err != nil { return err } diff --git a/x/ibc/02-client/keeper/grpc_query_test.go b/x/ibc/02-client/keeper/grpc_query_test.go index d927dba242..bd3f0a4255 100644 --- a/x/ibc/02-client/keeper/grpc_query_test.go +++ b/x/ibc/02-client/keeper/grpc_query_test.go @@ -43,7 +43,7 @@ func (suite *KeeperTestSuite) TestQueryClientState() { { "success", func() { - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), false, false) + clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) suite.keeper.SetClientState(suite.ctx, testClientID, clientState) var err error @@ -209,7 +209,7 @@ func (suite *KeeperTestSuite) TestQueryConsensusState() { { "success latest height", func() { - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false) + clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) cs := ibctmtypes.NewConsensusState( suite.consensusState.Timestamp, commitmenttypes.NewMerkleRoot([]byte("hash1")), nil, ) diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index d9963a4f84..2f309d5b12 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -17,6 +17,7 @@ import ( commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" "github.com/cosmos/cosmos-sdk/x/ibc/exported" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) // Keeper represents a type that grants read and write permissions to any client @@ -249,6 +250,15 @@ func (k Keeper) ValidateSelfClient(ctx sdk.Context, clientState exported.ClientS return sdkerrors.Wrapf(types.ErrInvalidClient, "unbonding period must be greater than trusting period. unbonding period (%d) < trusting period (%d)", tmClient.UnbondingPeriod, tmClient.TrustingPeriod) } + + if tmClient.UpgradePath != nil { + // For now, SDK IBC implementation assumes that upgrade path (if defined) is defined by SDK upgrade module + expectedUpgradePath := fmt.Sprintf("/%s/%s", upgradetypes.StoreKey, upgradetypes.KeyUpgradedClient) + if tmClient.UpgradePath.String() != expectedUpgradePath { + return sdkerrors.Wrapf(types.ErrInvalidClient, "upgrade path must be the upgrade path defined by upgrade module. expected %s, got %s", + expectedUpgradePath, tmClient.UpgradePath) + } + } return nil } diff --git a/x/ibc/02-client/keeper/keeper_test.go b/x/ibc/02-client/keeper/keeper_test.go index d2c71c9a3b..f25513438a 100644 --- a/x/ibc/02-client/keeper/keeper_test.go +++ b/x/ibc/02-client/keeper/keeper_test.go @@ -41,8 +41,11 @@ const ( maxClockDrift time.Duration = time.Second * 10 ) -var testClientHeight = types.NewHeight(0, 5) -var testClientHeightEpoch1 = types.NewHeight(1, 5) +var ( + testClientHeight = types.NewHeight(0, 5) + testClientHeightEpoch1 = types.NewHeight(1, 5) + upgradeHeight = types.NewHeight(1, 1) +) type KeeperTestSuite struct { suite.Suite @@ -117,7 +120,7 @@ func TestKeeperTestSuite(t *testing.T) { } func (suite *KeeperTestSuite) TestSetClientState() { - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), false, false) + clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) suite.keeper.SetClientState(suite.ctx, testClientID, clientState) retrievedState, found := suite.keeper.GetClientState(suite.ctx, testClientID) @@ -137,6 +140,7 @@ func (suite *KeeperTestSuite) TestSetClientConsensusState() { } func (suite *KeeperTestSuite) TestValidateSelfClient() { + badUpgradePath := commitmenttypes.NewMerklePath([]string{"bad", "upgrade", "path"}) testCases := []struct { name string clientState exported.ClientState @@ -144,7 +148,12 @@ func (suite *KeeperTestSuite) TestValidateSelfClient() { }{ { "success", - ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false), + ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), + true, + }, + { + "success with nil UpgradePath", + ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), nil, false, false), true, }, { @@ -154,42 +163,47 @@ func (suite *KeeperTestSuite) TestValidateSelfClient() { }, { "frozen client", - &ibctmtypes.ClientState{testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false}, + &ibctmtypes.ClientState{testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false}, false, }, { "incorrect chainID", - ibctmtypes.NewClientState("gaiatestnet", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false), + ibctmtypes.NewClientState("gaiatestnet", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), false, }, { "invalid client height", - ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.NewHeight(0, testClientHeight.EpochHeight+10), commitmenttypes.GetSDKSpecs(), false, false), + ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.NewHeight(0, testClientHeight.EpochHeight+10), commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), false, }, { "invalid client epoch", - ibctmtypes.NewClientState(testChainIDEpoch1, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeightEpoch1, commitmenttypes.GetSDKSpecs(), false, false), + ibctmtypes.NewClientState(testChainIDEpoch1, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeightEpoch1, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), false, }, { "invalid proof specs", - ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, nil, false, false), + ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, nil, &ibctesting.UpgradePath, false, false), false, }, { "invalid trust level", - ibctmtypes.NewClientState(testChainID, ibctmtypes.Fraction{0, 1}, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false), + ibctmtypes.NewClientState(testChainID, ibctmtypes.Fraction{0, 1}, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), false, }, { "invalid unbonding period", - ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod+10, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false), + ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod+10, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), false, }, { "invalid trusting period", - ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, ubdPeriod+10, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false), + ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, ubdPeriod+10, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), + false, + }, + { + "invalid upgrade path", + ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &badUpgradePath, false, false), false, }, } @@ -212,9 +226,9 @@ func (suite KeeperTestSuite) TestGetAllClients() { testClientID2, testClientID3, testClientID, } expClients := []exported.ClientState{ - ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), false, false), - ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), false, false), - ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), false, false), + ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), + ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), + ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), } for i := range expClients { @@ -236,9 +250,9 @@ func (suite KeeperTestSuite) TestGetAllGenesisClients() { testClientID2, testClientID3, testClientID, } expClients := []exported.ClientState{ - ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), false, false), - ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), false, false), - ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), false, false), + ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), + ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), + ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), } expGenClients := make([]types.IdentifiedClientState, len(expClients)) @@ -286,7 +300,7 @@ func (suite KeeperTestSuite) TestGetConsensusState() { func (suite KeeperTestSuite) TestConsensusStateHelpers() { // initial setup - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), false, false) + clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) suite.keeper.SetClientState(suite.ctx, testClientID, clientState) suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight, suite.consensusState) diff --git a/x/ibc/02-client/types/client.go b/x/ibc/02-client/types/client.go index e2178e7d0e..8cf8e39bc7 100644 --- a/x/ibc/02-client/types/client.go +++ b/x/ibc/02-client/types/client.go @@ -34,12 +34,7 @@ func NewIdentifiedClientState(clientID string, clientState exported.ClientState) // UnpackInterfaces implements UnpackInterfacesMesssage.UnpackInterfaces func (ics IdentifiedClientState) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { - var clientState exported.ClientState - err := unpacker.UnpackAny(ics.ClientState, &clientState) - if err != nil { - return err - } - return nil + return unpacker.UnpackAny(ics.ClientState, new(exported.ClientState)) } // NewConsensusStateWithHeight creates a new ConsensusStateWithHeight instance @@ -62,10 +57,5 @@ func NewConsensusStateWithHeight(height Height, consensusState exported.Consensu // UnpackInterfaces implements UnpackInterfacesMesssage.UnpackInterfaces func (cswh ConsensusStateWithHeight) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { - var consensusState exported.ConsensusState - err := unpacker.UnpackAny(cswh.ConsensusState, &consensusState) - if err != nil { - return err - } - return nil + return unpacker.UnpackAny(cswh.ConsensusState, new(exported.ConsensusState)) } diff --git a/x/ibc/02-client/types/client.pb.go b/x/ibc/02-client/types/client.pb.go index 8744668c4c..0af624ec46 100644 --- a/x/ibc/02-client/types/client.pb.go +++ b/x/ibc/02-client/types/client.pb.go @@ -328,6 +328,79 @@ func (m *MsgUpdateClient) XXX_DiscardUnknown() { var xxx_messageInfo_MsgUpdateClient proto.InternalMessageInfo +// MsgUpgradeClient defines an sdk.Msg to upgrade an IBC client to a new client state +type MsgUpgradeClient struct { + // client unique identifier + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` + // upgraded client state + ClientState *types.Any `protobuf:"bytes,2,opt,name=client_state,json=clientState,proto3" json:"client_state,omitempty" yaml:"client_state"` + // proof that old chain committed to new client + ProofUpgrade []byte `protobuf:"bytes,3,opt,name=proof_upgrade,json=proofUpgrade,proto3" json:"proof_upgrade,omitempty" yaml:"proof_upgrade"` + // signer address + Signer string `protobuf:"bytes,4,opt,name=signer,proto3" json:"signer,omitempty"` +} + +func (m *MsgUpgradeClient) Reset() { *m = MsgUpgradeClient{} } +func (m *MsgUpgradeClient) String() string { return proto.CompactTextString(m) } +func (*MsgUpgradeClient) ProtoMessage() {} +func (*MsgUpgradeClient) Descriptor() ([]byte, []int) { + return fileDescriptor_226f80e576f20abd, []int{6} +} +func (m *MsgUpgradeClient) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpgradeClient) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpgradeClient.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpgradeClient) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpgradeClient.Merge(m, src) +} +func (m *MsgUpgradeClient) XXX_Size() int { + return m.Size() +} +func (m *MsgUpgradeClient) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpgradeClient.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpgradeClient proto.InternalMessageInfo + +func (m *MsgUpgradeClient) GetClientId() string { + if m != nil { + return m.ClientId + } + return "" +} + +func (m *MsgUpgradeClient) GetClientState() *types.Any { + if m != nil { + return m.ClientState + } + return nil +} + +func (m *MsgUpgradeClient) GetProofUpgrade() []byte { + if m != nil { + return m.ProofUpgrade + } + return nil +} + +func (m *MsgUpgradeClient) GetSigner() string { + if m != nil { + return m.Signer + } + return "" +} + // MsgSubmitMisbehaviour defines an sdk.Msg type that submits Evidence for // light client misbehaviour. type MsgSubmitMisbehaviour struct { @@ -343,7 +416,7 @@ func (m *MsgSubmitMisbehaviour) Reset() { *m = MsgSubmitMisbehaviour{} } func (m *MsgSubmitMisbehaviour) String() string { return proto.CompactTextString(m) } func (*MsgSubmitMisbehaviour) ProtoMessage() {} func (*MsgSubmitMisbehaviour) Descriptor() ([]byte, []int) { - return fileDescriptor_226f80e576f20abd, []int{6} + return fileDescriptor_226f80e576f20abd, []int{7} } func (m *MsgSubmitMisbehaviour) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -391,7 +464,7 @@ type Height struct { func (m *Height) Reset() { *m = Height{} } func (*Height) ProtoMessage() {} func (*Height) Descriptor() ([]byte, []int) { - return fileDescriptor_226f80e576f20abd, []int{7} + return fileDescriptor_226f80e576f20abd, []int{8} } func (m *Height) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -427,6 +500,7 @@ func init() { proto.RegisterType((*ClientUpdateProposal)(nil), "ibc.client.ClientUpdateProposal") proto.RegisterType((*MsgCreateClient)(nil), "ibc.client.MsgCreateClient") proto.RegisterType((*MsgUpdateClient)(nil), "ibc.client.MsgUpdateClient") + proto.RegisterType((*MsgUpgradeClient)(nil), "ibc.client.MsgUpgradeClient") proto.RegisterType((*MsgSubmitMisbehaviour)(nil), "ibc.client.MsgSubmitMisbehaviour") proto.RegisterType((*Height)(nil), "ibc.client.Height") } @@ -434,47 +508,50 @@ func init() { func init() { proto.RegisterFile("ibc/client/client.proto", fileDescriptor_226f80e576f20abd) } var fileDescriptor_226f80e576f20abd = []byte{ - // 632 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x55, 0xbd, 0x6e, 0xd4, 0x40, - 0x10, 0xbe, 0xbd, 0x3b, 0x4e, 0xb9, 0x75, 0x44, 0x22, 0x73, 0x97, 0x5c, 0x52, 0xd8, 0xa7, 0x15, - 0x45, 0x0a, 0x62, 0x87, 0xa3, 0x41, 0xd7, 0x71, 0x69, 0x88, 0x44, 0x50, 0xe4, 0x08, 0xf1, 0xd3, - 0x44, 0xfe, 0xd9, 0xd8, 0x2b, 0xce, 0x5e, 0xcb, 0xbb, 0x46, 0xdc, 0x1b, 0x20, 0x2a, 0x24, 0x28, - 0x28, 0x28, 0x52, 0xe5, 0x0d, 0xe8, 0x78, 0x80, 0x94, 0x29, 0xa9, 0x2c, 0x94, 0x34, 0xd4, 0xf7, - 0x04, 0xc8, 0xbb, 0x0e, 0x67, 0xe7, 0x8f, 0x28, 0x15, 0x95, 0x77, 0x66, 0x67, 0xbe, 0xf9, 0xe6, - 0x9b, 0x91, 0x17, 0x2e, 0x13, 0xc7, 0x35, 0xdd, 0x31, 0xc1, 0x11, 0x2f, 0x3e, 0x46, 0x9c, 0x50, - 0x4e, 0x55, 0x48, 0x1c, 0xd7, 0x90, 0x9e, 0xd5, 0x8e, 0x4f, 0x7d, 0x2a, 0xdc, 0x66, 0x7e, 0x92, - 0x11, 0xab, 0x2b, 0x3e, 0xa5, 0xfe, 0x18, 0x9b, 0xc2, 0x72, 0xd2, 0x7d, 0xd3, 0x8e, 0x26, 0xf2, - 0x0a, 0x7d, 0x03, 0xb0, 0xbb, 0xe5, 0xe1, 0x88, 0x93, 0x7d, 0x82, 0xbd, 0x4d, 0x81, 0xb2, 0xcb, - 0x6d, 0x8e, 0xd5, 0x87, 0xb0, 0x2d, 0x41, 0xf7, 0x88, 0xd7, 0x03, 0x7d, 0xb0, 0xd6, 0x1e, 0x75, - 0xa6, 0x99, 0xbe, 0x38, 0xb1, 0xc3, 0xf1, 0x10, 0xfd, 0xbd, 0x42, 0xd6, 0x9c, 0x3c, 0x6f, 0x79, - 0xea, 0x0e, 0x9c, 0x2f, 0xfc, 0x2c, 0x87, 0xe8, 0xd5, 0xfb, 0x60, 0x4d, 0x19, 0x74, 0x0c, 0x59, - 0xde, 0x38, 0x2b, 0x6f, 0x3c, 0x89, 0x26, 0xa3, 0xe5, 0x69, 0xa6, 0xdf, 0xab, 0x60, 0x89, 0x1c, - 0x64, 0x29, 0xee, 0x8c, 0x04, 0x3a, 0x04, 0xb0, 0xb7, 0x49, 0x23, 0x86, 0x23, 0x96, 0x32, 0xe1, - 0x7a, 0x49, 0x78, 0xf0, 0x14, 0x13, 0x3f, 0xe0, 0xea, 0x06, 0x6c, 0x05, 0xe2, 0x24, 0xe8, 0x29, - 0x03, 0xd5, 0x98, 0x29, 0x61, 0xc8, 0x98, 0x51, 0xf3, 0x28, 0xd3, 0x6b, 0x56, 0x11, 0xa7, 0xbe, - 0x82, 0x0b, 0xee, 0x19, 0xda, 0x0d, 0x38, 0xae, 0x4c, 0x33, 0xbd, 0x9b, 0x73, 0x44, 0xe7, 0xb2, - 0x90, 0x75, 0xd7, 0xad, 0xb0, 0x42, 0x3f, 0x00, 0xec, 0x4a, 0xf5, 0xaa, 0x74, 0xd9, 0x6d, 0x74, - 0x8c, 0xe1, 0xe2, 0xb9, 0x82, 0xac, 0x57, 0xef, 0x37, 0xd6, 0x94, 0xc1, 0xfd, 0x72, 0x8b, 0x57, - 0x09, 0x33, 0xd2, 0xf3, 0xa6, 0xa7, 0x99, 0xbe, 0x5c, 0xd4, 0x38, 0x87, 0x85, 0xac, 0x85, 0x2a, - 0x7b, 0x86, 0xbe, 0x03, 0xd8, 0x91, 0xf4, 0x5f, 0xc4, 0x9e, 0xcd, 0xf1, 0x4e, 0x42, 0x63, 0xca, - 0xec, 0xb1, 0xda, 0x81, 0x77, 0x38, 0xe1, 0x63, 0x2c, 0x99, 0x5b, 0xd2, 0x50, 0xfb, 0x50, 0xf1, - 0x30, 0x73, 0x13, 0x12, 0x73, 0x42, 0x23, 0xa1, 0x61, 0xdb, 0x2a, 0xbb, 0xaa, 0x5d, 0x37, 0x6e, - 0xd4, 0xf5, 0x83, 0x7c, 0x9c, 0xb6, 0x87, 0x93, 0x5e, 0xf3, 0xea, 0x99, 0x58, 0x45, 0xcc, 0xb0, - 0xf9, 0xe1, 0x40, 0xaf, 0xa1, 0xcf, 0x75, 0xb8, 0xb0, 0xcd, 0xfc, 0xcd, 0x04, 0xdb, 0x1c, 0xcb, - 0x06, 0xfe, 0x8b, 0xc5, 0x55, 0x5f, 0x5f, 0xdc, 0xb4, 0xc6, 0x35, 0xa0, 0xab, 0xd3, 0x4c, 0x5f, - 0xba, 0x74, 0x5a, 0x17, 0x56, 0x4d, 0x5d, 0x82, 0x2d, 0x46, 0xfc, 0xa8, 0xd0, 0xa9, 0x6d, 0x15, - 0xd6, 0x70, 0x2e, 0x57, 0xe4, 0x77, 0xae, 0xca, 0x17, 0x20, 0x54, 0x91, 0xa3, 0xbc, 0xbd, 0x2a, - 0xb3, 0x81, 0xd4, 0xff, 0x3d, 0x90, 0x12, 0xad, 0xc6, 0x15, 0xb4, 0x0e, 0x01, 0xec, 0x6e, 0x33, - 0x7f, 0x37, 0x75, 0x42, 0xc2, 0xb7, 0x09, 0x73, 0x70, 0x60, 0xbf, 0x23, 0x34, 0x4d, 0x6e, 0x43, - 0xee, 0x31, 0x9c, 0x0f, 0x4b, 0x10, 0xd7, 0x52, 0xac, 0x44, 0xde, 0x80, 0xe8, 0x47, 0x00, 0x5b, - 0xc5, 0x3f, 0x66, 0x08, 0xe7, 0x71, 0x4c, 0xdd, 0x60, 0x2f, 0x4a, 0x43, 0x07, 0x27, 0x82, 0x5c, - 0xb3, 0xbc, 0x03, 0xe5, 0x5b, 0x64, 0x29, 0xc2, 0x7c, 0x2e, 0xac, 0x59, 0x6e, 0xf1, 0x97, 0xaa, - 0x5f, 0x9e, 0x2b, 0x6f, 0xcf, 0x72, 0x65, 0x5d, 0x49, 0xe6, 0xeb, 0x81, 0x5e, 0x1b, 0x3d, 0x3b, - 0x3a, 0xd1, 0xc0, 0xf1, 0x89, 0x06, 0x7e, 0x9d, 0x68, 0xe0, 0xd3, 0xa9, 0x56, 0x3b, 0x3e, 0xd5, - 0x6a, 0x3f, 0x4f, 0xb5, 0xda, 0x9b, 0x81, 0x4f, 0x78, 0x90, 0x3a, 0x86, 0x4b, 0x43, 0xd3, 0xa5, - 0x2c, 0xa4, 0xac, 0xf8, 0xac, 0x33, 0xef, 0xad, 0xf9, 0xde, 0xcc, 0x1f, 0x8c, 0x8d, 0xc1, 0x7a, - 0xf1, 0x66, 0xf0, 0x49, 0x8c, 0x99, 0xd3, 0x12, 0xc2, 0x3c, 0xfa, 0x13, 0x00, 0x00, 0xff, 0xff, - 0xe9, 0x68, 0x4f, 0xc2, 0x4e, 0x06, 0x00, 0x00, + // 675 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x55, 0x3d, 0x6f, 0xd3, 0x4e, + 0x1c, 0xce, 0x25, 0xf9, 0x47, 0xcd, 0x25, 0x7f, 0x5a, 0x99, 0xa4, 0x4d, 0x3b, 0xc4, 0xd1, 0x89, + 0xa1, 0x03, 0xb5, 0x4b, 0x58, 0x50, 0x24, 0x06, 0xd2, 0x85, 0x4a, 0x14, 0x55, 0xae, 0x10, 0x2f, + 0x4b, 0xe5, 0x97, 0xab, 0x73, 0x22, 0xf1, 0x59, 0xbe, 0x33, 0x22, 0xdf, 0x00, 0x31, 0x21, 0xc1, + 0xc0, 0xc0, 0xd0, 0x89, 0x6f, 0xc0, 0xc6, 0x07, 0xe8, 0xd8, 0x91, 0xc9, 0x42, 0xed, 0xc2, 0xc4, + 0x90, 0x4f, 0x80, 0x7c, 0x77, 0x25, 0x76, 0xdb, 0x94, 0x2a, 0x53, 0x27, 0xdf, 0xef, 0xfd, 0xf9, + 0x3d, 0xcf, 0xe9, 0x0c, 0x57, 0x88, 0xe3, 0x9a, 0xee, 0x90, 0xe0, 0x80, 0xab, 0x8f, 0x11, 0x46, + 0x94, 0x53, 0x0d, 0x12, 0xc7, 0x35, 0xa4, 0x67, 0xad, 0xe1, 0x53, 0x9f, 0x0a, 0xb7, 0x99, 0x9e, + 0x64, 0xc6, 0xda, 0xaa, 0x4f, 0xa9, 0x3f, 0xc4, 0xa6, 0xb0, 0x9c, 0xf8, 0xc0, 0xb4, 0x83, 0xb1, + 0x0c, 0xa1, 0x2f, 0x00, 0x36, 0xb7, 0x3d, 0x1c, 0x70, 0x72, 0x40, 0xb0, 0xb7, 0x25, 0xba, 0xec, + 0x71, 0x9b, 0x63, 0xed, 0x1e, 0xac, 0xca, 0xa6, 0xfb, 0xc4, 0x6b, 0x81, 0x0e, 0x58, 0xaf, 0xf6, + 0x1b, 0x93, 0x44, 0x5f, 0x1a, 0xdb, 0xa3, 0x61, 0x0f, 0xfd, 0x0d, 0x21, 0x6b, 0x41, 0x9e, 0xb7, + 0x3d, 0x6d, 0x17, 0xd6, 0x95, 0x9f, 0xa5, 0x2d, 0x5a, 0xc5, 0x0e, 0x58, 0xaf, 0x75, 0x1b, 0x86, + 0x1c, 0x6f, 0x9c, 0x8d, 0x37, 0x1e, 0x05, 0xe3, 0xfe, 0xca, 0x24, 0xd1, 0x6f, 0xe7, 0x7a, 0x89, + 0x1a, 0x64, 0xd5, 0xdc, 0x29, 0x08, 0xf4, 0x15, 0xc0, 0xd6, 0x16, 0x0d, 0x18, 0x0e, 0x58, 0xcc, + 0x84, 0xeb, 0x39, 0xe1, 0x83, 0xc7, 0x98, 0xf8, 0x03, 0xae, 0x6d, 0xc2, 0xca, 0x40, 0x9c, 0x04, + 0xbc, 0x5a, 0x57, 0x33, 0xa6, 0x4c, 0x18, 0x32, 0xa7, 0x5f, 0x3e, 0x4a, 0xf4, 0x82, 0xa5, 0xf2, + 0xb4, 0x17, 0x70, 0xd1, 0x3d, 0xeb, 0x76, 0x0d, 0x8c, 0xab, 0x93, 0x44, 0x6f, 0xa6, 0x18, 0xd1, + 0xb9, 0x2a, 0x64, 0xdd, 0x72, 0x73, 0xa8, 0xd0, 0x77, 0x00, 0x9b, 0x92, 0xbd, 0x3c, 0x5c, 0x36, + 0x0f, 0x8f, 0x21, 0x5c, 0x3a, 0x37, 0x90, 0xb5, 0x8a, 0x9d, 0xd2, 0x7a, 0xad, 0x7b, 0x27, 0xbb, + 0xe2, 0x2c, 0x62, 0xfa, 0x7a, 0xba, 0xf4, 0x24, 0xd1, 0x57, 0xd4, 0x8c, 0x73, 0xbd, 0x90, 0xb5, + 0x98, 0x47, 0xcf, 0xd0, 0x37, 0x00, 0x1b, 0x12, 0xfe, 0xb3, 0xd0, 0xb3, 0x39, 0xde, 0x8d, 0x68, + 0x48, 0x99, 0x3d, 0xd4, 0x1a, 0xf0, 0x3f, 0x4e, 0xf8, 0x10, 0x4b, 0xe4, 0x96, 0x34, 0xb4, 0x0e, + 0xac, 0x79, 0x98, 0xb9, 0x11, 0x09, 0x39, 0xa1, 0x81, 0xe0, 0xb0, 0x6a, 0x65, 0x5d, 0xf9, 0xad, + 0x4b, 0xd7, 0xda, 0xfa, 0x6e, 0x2a, 0xa7, 0xed, 0xe1, 0xa8, 0x55, 0x9e, 0xad, 0x89, 0xa5, 0x72, + 0x7a, 0xe5, 0x77, 0x87, 0x7a, 0x01, 0x7d, 0x2c, 0xc2, 0xc5, 0x1d, 0xe6, 0x6f, 0x45, 0xd8, 0xe6, + 0x58, 0x2e, 0x70, 0x23, 0x2e, 0xae, 0xf6, 0xf2, 0xe2, 0x4d, 0x2b, 0x5d, 0xd1, 0x74, 0x6d, 0x92, + 0xe8, 0xcb, 0x97, 0xaa, 0x75, 0xe1, 0xaa, 0x69, 0xcb, 0xb0, 0xc2, 0x88, 0x1f, 0x28, 0x9e, 0xaa, + 0x96, 0xb2, 0x7a, 0x0b, 0x29, 0x23, 0xbf, 0x52, 0x56, 0x3e, 0x01, 0xc1, 0x8a, 0x94, 0x72, 0x7e, + 0x56, 0xa6, 0x82, 0x14, 0xff, 0x2d, 0x48, 0x06, 0x56, 0x69, 0x06, 0xac, 0xdf, 0x00, 0x2e, 0x09, + 0x58, 0x7e, 0x64, 0x7b, 0x37, 0x4a, 0xad, 0x87, 0xf0, 0xff, 0x30, 0xa2, 0xf4, 0x60, 0x3f, 0x96, + 0xd8, 0xc4, 0x0a, 0xf5, 0x7e, 0x6b, 0x92, 0xe8, 0x0d, 0x59, 0x9c, 0x0b, 0x23, 0xab, 0x2e, 0x6c, + 0xb5, 0xc9, 0x2c, 0x45, 0xd2, 0xd7, 0xab, 0xb9, 0xc3, 0xfc, 0xbd, 0xd8, 0x19, 0x11, 0xbe, 0x43, + 0x98, 0x83, 0x07, 0xf6, 0x1b, 0x42, 0xe3, 0x68, 0x9e, 0xad, 0x1f, 0xc0, 0xfa, 0x28, 0xd3, 0xe2, + 0x4a, 0x4d, 0x72, 0x99, 0xd7, 0x50, 0xe6, 0x3d, 0x80, 0x15, 0xf5, 0xa8, 0xf6, 0x60, 0x1d, 0x87, + 0xd4, 0x1d, 0xec, 0x07, 0xf1, 0xc8, 0xc1, 0x91, 0x00, 0x57, 0xce, 0xd2, 0x98, 0x8d, 0x22, 0xab, + 0x26, 0xcc, 0xa7, 0xc2, 0x9a, 0xd6, 0xaa, 0x67, 0xb9, 0x78, 0x79, 0xad, 0x8c, 0x9e, 0xd5, 0xca, + 0xb9, 0x12, 0xcc, 0xe7, 0x43, 0xbd, 0xd0, 0x7f, 0x72, 0x74, 0xd2, 0x06, 0xc7, 0x27, 0x6d, 0xf0, + 0xf3, 0xa4, 0x0d, 0x3e, 0x9c, 0xb6, 0x0b, 0xc7, 0xa7, 0xed, 0xc2, 0x8f, 0xd3, 0x76, 0xe1, 0x55, + 0xd7, 0x27, 0x7c, 0x10, 0x3b, 0x86, 0x4b, 0x47, 0xa6, 0x4b, 0xd9, 0x88, 0x32, 0xf5, 0xd9, 0x60, + 0xde, 0x6b, 0xf3, 0xad, 0x99, 0xfe, 0x21, 0x37, 0xbb, 0x1b, 0xea, 0x27, 0xc9, 0xc7, 0x21, 0x66, + 0x4e, 0x45, 0x10, 0x73, 0xff, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xba, 0xc4, 0xe6, 0x7d, 0x3f, + 0x07, 0x00, 0x00, } func (m *IdentifiedClientState) Marshal() (dAtA []byte, err error) { @@ -774,6 +851,62 @@ func (m *MsgUpdateClient) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *MsgUpgradeClient) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpgradeClient) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpgradeClient) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintClient(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x22 + } + if len(m.ProofUpgrade) > 0 { + i -= len(m.ProofUpgrade) + copy(dAtA[i:], m.ProofUpgrade) + i = encodeVarintClient(dAtA, i, uint64(len(m.ProofUpgrade))) + i-- + dAtA[i] = 0x1a + } + if m.ClientState != nil { + { + size, err := m.ClientState.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintClient(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.ClientId) > 0 { + i -= len(m.ClientId) + copy(dAtA[i:], m.ClientId) + i = encodeVarintClient(dAtA, i, uint64(len(m.ClientId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *MsgSubmitMisbehaviour) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -989,6 +1122,31 @@ func (m *MsgUpdateClient) Size() (n int) { return n } +func (m *MsgUpgradeClient) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ClientId) + if l > 0 { + n += 1 + l + sovClient(uint64(l)) + } + if m.ClientState != nil { + l = m.ClientState.Size() + n += 1 + l + sovClient(uint64(l)) + } + l = len(m.ProofUpgrade) + if l > 0 { + n += 1 + l + sovClient(uint64(l)) + } + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovClient(uint64(l)) + } + return n +} + func (m *MsgSubmitMisbehaviour) Size() (n int) { if m == nil { return 0 @@ -1920,6 +2078,193 @@ func (m *MsgUpdateClient) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgUpgradeClient) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpgradeClient: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpgradeClient: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ClientId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ClientId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ClientState", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ClientState == nil { + m.ClientState = &types.Any{} + } + if err := m.ClientState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofUpgrade", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProofUpgrade = append(m.ProofUpgrade[:0], dAtA[iNdEx:postIndex]...) + if m.ProofUpgrade == nil { + m.ProofUpgrade = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipClient(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthClient + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthClient + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *MsgSubmitMisbehaviour) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/ibc/02-client/types/codec_test.go b/x/ibc/02-client/types/codec_test.go index 98ad6e4763..ffeec83707 100644 --- a/x/ibc/02-client/types/codec_test.go +++ b/x/ibc/02-client/types/codec_test.go @@ -30,7 +30,7 @@ func (suite *TypesTestSuite) TestPackClientState() { }, { "tendermint client", - ibctmtypes.NewClientState(chainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), false, false), + ibctmtypes.NewClientState(chainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), true, }, { diff --git a/x/ibc/02-client/types/errors.go b/x/ibc/02-client/types/errors.go index fe9099eaec..e90d5f8954 100644 --- a/x/ibc/02-client/types/errors.go +++ b/x/ibc/02-client/types/errors.go @@ -28,4 +28,5 @@ var ( ErrSelfConsensusStateNotFound = sdkerrors.Register(SubModuleName, 21, "self consensus state not found") ErrUpdateClientFailed = sdkerrors.Register(SubModuleName, 22, "unable to update light client") ErrInvalidUpdateClientProposal = sdkerrors.Register(SubModuleName, 23, "invalid update client proposal") + ErrInvalidUpgradeClient = sdkerrors.Register(SubModuleName, 24, "invalid client upgrade") ) diff --git a/x/ibc/02-client/types/events.go b/x/ibc/02-client/types/events.go index 839ccb5084..436fe02742 100644 --- a/x/ibc/02-client/types/events.go +++ b/x/ibc/02-client/types/events.go @@ -17,6 +17,7 @@ const ( var ( EventTypeCreateClient = "create_client" EventTypeUpdateClient = "update_client" + EventTypeUpgradeClient = "upgrade_client" EventTypeSubmitMisbehaviour = "client_misbehaviour" EventTypeUpdateClientProposal = "update_client_proposal" diff --git a/x/ibc/02-client/types/genesis_test.go b/x/ibc/02-client/types/genesis_test.go index 8d14eccb79..b3618c9316 100644 --- a/x/ibc/02-client/types/genesis_test.go +++ b/x/ibc/02-client/types/genesis_test.go @@ -72,7 +72,7 @@ func TestValidateGenesis(t *testing.T) { genState: types.NewGenesisState( []types.IdentifiedClientState{ types.NewIdentifiedClientState( - clientID, ibctmtypes.NewClientState(chainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), false, false), + clientID, ibctmtypes.NewClientState(chainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), ), types.NewIdentifiedClientState( exported.Localhost, localhosttypes.NewClientState("chainID", clientHeight), @@ -100,7 +100,7 @@ func TestValidateGenesis(t *testing.T) { genState: types.NewGenesisState( []types.IdentifiedClientState{ types.NewIdentifiedClientState( - "/~@$*", ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), false, false), + "/~@$*", ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), ), types.NewIdentifiedClientState( exported.Localhost, localhosttypes.NewClientState("chainID", clientHeight), @@ -128,7 +128,7 @@ func TestValidateGenesis(t *testing.T) { genState: types.NewGenesisState( []types.IdentifiedClientState{ types.NewIdentifiedClientState( - clientID, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), false, false), + clientID, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), ), types.NewIdentifiedClientState(exported.Localhost, localhosttypes.NewClientState("chaindID", types.ZeroHeight())), }, @@ -142,7 +142,7 @@ func TestValidateGenesis(t *testing.T) { genState: types.NewGenesisState( []types.IdentifiedClientState{ types.NewIdentifiedClientState( - clientID, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), false, false), + clientID, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), ), types.NewIdentifiedClientState( exported.Localhost, localhosttypes.NewClientState("chaindID", clientHeight), @@ -170,7 +170,7 @@ func TestValidateGenesis(t *testing.T) { genState: types.NewGenesisState( []types.IdentifiedClientState{ types.NewIdentifiedClientState( - clientID, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), false, false), + clientID, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), ), types.NewIdentifiedClientState( exported.Localhost, localhosttypes.NewClientState("chaindID", clientHeight), diff --git a/x/ibc/02-client/types/msgs.go b/x/ibc/02-client/types/msgs.go index 46c28289c5..c33a35bf4e 100644 --- a/x/ibc/02-client/types/msgs.go +++ b/x/ibc/02-client/types/msgs.go @@ -12,6 +12,7 @@ import ( const ( TypeMsgCreateClient string = "create_client" TypeMsgUpdateClient string = "update_client" + TypeMsgUpgradeClient string = "upgrade_client" TypeMsgSubmitMisbehaviour string = "submit_misbehaviour" ) @@ -19,10 +20,12 @@ var ( _ sdk.Msg = &MsgCreateClient{} _ sdk.Msg = &MsgUpdateClient{} _ sdk.Msg = &MsgSubmitMisbehaviour{} + _ sdk.Msg = &MsgUpgradeClient{} _ codectypes.UnpackInterfacesMessage = MsgCreateClient{} _ codectypes.UnpackInterfacesMessage = MsgUpdateClient{} _ codectypes.UnpackInterfacesMessage = MsgSubmitMisbehaviour{} + _ codectypes.UnpackInterfacesMessage = MsgUpgradeClient{} ) // NewMsgCreateClient creates a new MsgCreateClient instance @@ -107,12 +110,7 @@ func (msg MsgCreateClient) UnpackInterfaces(unpacker codectypes.AnyUnpacker) err } var consensusState exported.ConsensusState - err = unpacker.UnpackAny(msg.ConsensusState, &consensusState) - if err != nil { - return err - } - - return nil + return unpacker.UnpackAny(msg.ConsensusState, &consensusState) } // NewMsgUpdateClient creates a new MsgUpdateClient instance @@ -175,12 +173,72 @@ func (msg MsgUpdateClient) GetSigners() []sdk.AccAddress { // UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces func (msg MsgUpdateClient) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { var header exported.Header - err := unpacker.UnpackAny(msg.Header, &header) + return unpacker.UnpackAny(msg.Header, &header) +} + +// NewMsgUpgradeClient creates a new MsgUpgradeClient instance +// nolint: interfacer +func NewMsgUpgradeClient(clientID string, clientState exported.ClientState, proofUpgrade []byte, signer sdk.AccAddress) (*MsgUpgradeClient, error) { + anyClient, err := PackClientState(clientState) + if err != nil { + return nil, err + } + + return &MsgUpgradeClient{ + ClientId: clientID, + ClientState: anyClient, + ProofUpgrade: proofUpgrade, + Signer: signer.String(), + }, nil +} + +// Route implements sdk.Msg +func (msg MsgUpgradeClient) Route() string { + return host.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgUpgradeClient) Type() string { + return TypeMsgUpgradeClient +} + +// ValidateBasic implements sdk.Msg +func (msg MsgUpgradeClient) ValidateBasic() error { + clientState, err := UnpackClientState(msg.ClientState) if err != nil { return err } + if err := clientState.Validate(); err != nil { + return err + } + if len(msg.ProofUpgrade) == 0 { + return sdkerrors.Wrap(ErrInvalidUpgradeClient, "proof of upgrade cannot be empty") + } + _, err = sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err) + } + return host.ClientIdentifierValidator(msg.ClientId) +} - return nil +// GetSignBytes implements sdk.Msg +func (msg MsgUpgradeClient) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgUpgradeClient) GetSigners() []sdk.AccAddress { + accAddr, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + panic(err) + } + return []sdk.AccAddress{accAddr} +} + +// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces +func (msg MsgUpgradeClient) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { + var clientState exported.ClientState + return unpacker.UnpackAny(msg.ClientState, &clientState) } // NewMsgSubmitMisbehaviour creates a new MsgSubmitMisbehaviour instance. @@ -247,10 +305,5 @@ func (msg MsgSubmitMisbehaviour) GetSigners() []sdk.AccAddress { // UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces func (msg MsgSubmitMisbehaviour) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { var misbehaviour exported.Misbehaviour - err := unpacker.UnpackAny(msg.Misbehaviour, &misbehaviour) - if err != nil { - return err - } - - return nil + return unpacker.UnpackAny(msg.Misbehaviour, &misbehaviour) } diff --git a/x/ibc/02-client/types/msgs_test.go b/x/ibc/02-client/types/msgs_test.go index 3f29b69f2c..4dddc52f6a 100644 --- a/x/ibc/02-client/types/msgs_test.go +++ b/x/ibc/02-client/types/msgs_test.go @@ -56,7 +56,7 @@ func (suite *TypesTestSuite) TestMarshalMsgCreateClient() { }, { "tendermint client", func() { - tendermintClient := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), false, false) + tendermintClient := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) msg, err = types.NewMsgCreateClient("tendermint", tendermintClient, suite.chainA.CreateTMClientHeader().ConsensusState(), suite.chainA.SenderAccount.GetAddress()) suite.Require().NoError(err) }, @@ -108,7 +108,7 @@ func (suite *TypesTestSuite) TestMsgCreateClient_ValidateBasic() { { "valid - tendermint client", func() { - tendermintClient := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), false, false) + tendermintClient := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) msg, err = types.NewMsgCreateClient("tendermint", tendermintClient, suite.chainA.CreateTMClientHeader().ConsensusState(), suite.chainA.SenderAccount.GetAddress()) suite.Require().NoError(err) }, @@ -132,7 +132,7 @@ func (suite *TypesTestSuite) TestMsgCreateClient_ValidateBasic() { { "failed to unpack consensus state", func() { - tendermintClient := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), false, false) + tendermintClient := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) msg, err = types.NewMsgCreateClient("tendermint", tendermintClient, suite.chainA.CreateTMClientHeader().ConsensusState(), suite.chainA.SenderAccount.GetAddress()) suite.Require().NoError(err) msg.ConsensusState = nil @@ -333,6 +333,133 @@ func (suite *TypesTestSuite) TestMsgUpdateClient_ValidateBasic() { } } +func (suite *TypesTestSuite) TestMarshalMsgUpgradeClient() { + var ( + msg *types.MsgUpgradeClient + err error + ) + + testCases := []struct { + name string + malleate func() + }{ + { + "client upgrades to new tendermint client", + func() { + tendermintClient := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) + msg, err = types.NewMsgUpgradeClient("clientid", tendermintClient, []byte("proofUpgrade"), suite.chainA.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + }, + { + "client upgrades to new solomachine client", + func() { + soloMachine := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachine", "", 1) + msg, err = types.NewMsgUpgradeClient("clientid", soloMachine.ClientState(), []byte("proofUpgrade"), suite.chainA.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() + + tc.malleate() + + cdc := suite.chainA.App.AppCodec() + + // marshal message + bz, err := cdc.MarshalJSON(msg) + suite.Require().NoError(err) + + // unmarshal message + newMsg := &types.MsgUpgradeClient{} + err = cdc.UnmarshalJSON(bz, newMsg) + suite.Require().NoError(err) + + suite.Require().True(proto.Equal(msg, newMsg)) + }) + } +} + +func (suite *TypesTestSuite) TestMsgUpgradeClient_ValidateBasic() { + cases := []struct { + name string + malleate func(*types.MsgUpgradeClient) + expPass bool + }{ + { + name: "success", + malleate: func(msg *types.MsgUpgradeClient) {}, + expPass: true, + }, + { + name: "client id empty", + malleate: func(msg *types.MsgUpgradeClient) { + msg.ClientId = "" + }, + expPass: false, + }, + { + name: "invalid client id", + malleate: func(msg *types.MsgUpgradeClient) { + msg.ClientId = "invalid~chain/id" + }, + expPass: false, + }, + { + name: "unpacking clientstate fails", + malleate: func(msg *types.MsgUpgradeClient) { + msg.ClientState = nil + }, + expPass: false, + }, + { + name: "invalid client state", + malleate: func(msg *types.MsgUpgradeClient) { + cs := &ibctmtypes.ClientState{} + var err error + msg.ClientState, err = types.PackClientState(cs) + suite.Require().NoError(err) + }, + expPass: false, + }, + { + name: "empty proof", + malleate: func(msg *types.MsgUpgradeClient) { + msg.ProofUpgrade = nil + }, + expPass: false, + }, + { + name: "empty signer", + malleate: func(msg *types.MsgUpgradeClient) { + msg.Signer = " " + }, + expPass: false, + }, + } + + for _, tc := range cases { + tc := tc + + clientState := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false) + msg, _ := types.NewMsgUpgradeClient("testclientid", clientState, []byte("proofUpgrade"), suite.chainA.SenderAccount.GetAddress()) + + tc.malleate(msg) + err := msg.ValidateBasic() + if tc.expPass { + suite.Require().NoError(err, "valid case %s failed", tc.name) + } else { + suite.Require().Error(err, "invalid case %s passed", tc.name) + } + } + +} + // tests that different misbehaviours within MsgSubmitMisbehaviour can be marshaled // and unmarshaled. func (suite *TypesTestSuite) TestMarshalMsgSubmitMisbehaviour() { diff --git a/x/ibc/03-connection/types/msgs_test.go b/x/ibc/03-connection/types/msgs_test.go index 3d7f4c4d20..60c1d9e384 100644 --- a/x/ibc/03-connection/types/msgs_test.go +++ b/x/ibc/03-connection/types/msgs_test.go @@ -107,7 +107,7 @@ func (suite *MsgTestSuite) TestNewMsgConnectionOpenTry() { signer, _ := sdk.AccAddressFromBech32("cosmos1ckgw5d7jfj7wwxjzs9fdrdev9vc8dzcw3n2lht") clientState := ibctmtypes.NewClientState( - chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), false, false, + chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false, ) // Pack consensus state into any to test unpacking error @@ -119,7 +119,7 @@ func (suite *MsgTestSuite) TestNewMsgConnectionOpenTry() { // invalidClientState fails validateBasic invalidClient := ibctmtypes.NewClientState( - chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clienttypes.ZeroHeight(), commitmenttypes.GetSDKSpecs(), false, false, + chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clienttypes.ZeroHeight(), commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false, ) testMsgs := []*types.MsgConnectionOpenTry{ @@ -179,7 +179,7 @@ func (suite *MsgTestSuite) TestNewMsgConnectionOpenTry() { func (suite *MsgTestSuite) TestNewMsgConnectionOpenAck() { signer, _ := sdk.AccAddressFromBech32("cosmos1ckgw5d7jfj7wwxjzs9fdrdev9vc8dzcw3n2lht") clientState := ibctmtypes.NewClientState( - chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), false, false, + chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false, ) // Pack consensus state into any to test unpacking error @@ -190,7 +190,7 @@ func (suite *MsgTestSuite) TestNewMsgConnectionOpenAck() { // invalidClientState fails validateBasic invalidClient := ibctmtypes.NewClientState( - chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clienttypes.ZeroHeight(), commitmenttypes.GetSDKSpecs(), false, false, + chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clienttypes.ZeroHeight(), commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false, ) testMsgs := []*types.MsgConnectionOpenAck{ diff --git a/x/ibc/07-tendermint/client/cli/tx.go b/x/ibc/07-tendermint/client/cli/tx.go index 607afbe9a7..4e71e26a5d 100644 --- a/x/ibc/07-tendermint/client/cli/tx.go +++ b/x/ibc/07-tendermint/client/cli/tx.go @@ -25,6 +25,7 @@ import ( const ( flagTrustLevel = "trust-level" flagProofSpecs = "proof-specs" + flagUpgradePath = "upgrade-path" flagAllowUpdateAfterExpiry = "allow_update_after_expiry" flagAllowUpdateAfterMisbehaviour = "allow_update_after_misbehaviour" ) @@ -37,8 +38,10 @@ func NewCreateClientCmd() *cobra.Command { Short: "create new tendermint client", Long: `Create a new tendermint IBC client. - 'trust-level' flag can be a fraction (eg: '1/3') or 'default' - - 'proof-specs' flag can be JSON input, a path to a .json file or 'default'`, - Example: fmt.Sprintf("%s tx ibc %s create [client-id] [path/to/consensus_state.json] [trusting_period] [unbonding_period] [max_clock_drift] --trust-level default --proof-specs [path/to/proof-specs.json] --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), + - 'proof-specs' flag can be JSON input, a path to a .json file or 'default' + - 'upgrade-path' flag is a string specifying the upgrade path for this chain where a future upgraded client will be stored. The path represents a keypath for the store with each key separated by a '/'. Any slash within a key must be escaped. + e.g. 'upgrade/upgradedClient'`, + Example: fmt.Sprintf("%s tx ibc %s create [client-id] [path/to/consensus_state.json] [trusting_period] [unbonding_period] [max_clock_drift] --trust-level default --proof-specs [path/to/proof-specs.json] --upgrade-path upgrade/upgradedClient --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), Args: cobra.ExactArgs(5), RunE: func(cmd *cobra.Command, args []string) error { clientCtx := client.GetClientContextFromCmd(cmd) @@ -116,15 +119,24 @@ func NewCreateClientCmd() *cobra.Command { allowUpdateAfterExpiry, _ := cmd.Flags().GetBool(flagAllowUpdateAfterExpiry) allowUpdateAfterMisbehaviour, _ := cmd.Flags().GetBool(flagAllowUpdateAfterMisbehaviour) + upgradePath, _ := cmd.Flags().GetString(flagUpgradePath) + keyPath := strings.Split(upgradePath, "/") + if keyPath[0] == upgradePath { + return fmt.Errorf("invalid merkle path %s", upgradePath) + } + + merklePath := commitmenttypes.NewMerklePath(keyPath) + // validate header if err := header.ValidateBasic(); err != nil { return err } height := header.GetHeight().(clienttypes.Height) + clientState := types.NewClientState( header.GetHeader().GetChainID(), trustLevel, trustingPeriod, ubdPeriod, maxClockDrift, - height, specs, allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour, + height, specs, &merklePath, allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour, ) consensusState := header.ConsensusState() diff --git a/x/ibc/07-tendermint/types/client_state.go b/x/ibc/07-tendermint/types/client_state.go index aa073b2daf..6e03675b3a 100644 --- a/x/ibc/07-tendermint/types/client_state.go +++ b/x/ibc/07-tendermint/types/client_state.go @@ -28,7 +28,7 @@ func NewClientState( chainID string, trustLevel Fraction, trustingPeriod, ubdPeriod, maxClockDrift time.Duration, latestHeight clienttypes.Height, specs []*ics23.ProofSpec, - allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour bool, + upgradePath *commitmenttypes.MerklePath, allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour bool, ) *ClientState { return &ClientState{ ChainId: chainID, @@ -39,6 +39,7 @@ func NewClientState( LatestHeight: latestHeight, FrozenHeight: clienttypes.ZeroHeight(), ProofSpecs: specs, + UpgradePath: upgradePath, AllowUpdateAfterExpiry: allowUpdateAfterExpiry, AllowUpdateAfterMisbehaviour: allowUpdateAfterMisbehaviour, } @@ -121,6 +122,20 @@ func (cs ClientState) GetProofSpecs() []*ics23.ProofSpec { return cs.ProofSpecs } +// ZeroCustomFields returns a ClientState that is a copy of the current ClientState +// with all client customizable fields zeroed out +func (cs ClientState) ZeroCustomFields() exported.ClientState { + // copy over all chain-specified fields + // and leave custom fields empty + return &ClientState{ + ChainId: cs.ChainId, + UnbondingPeriod: cs.UnbondingPeriod, + LatestHeight: cs.LatestHeight, + ProofSpecs: cs.ProofSpecs, + UpgradePath: cs.UpgradePath, + } +} + // VerifyClientState verifies a proof of the client state of the running chain // stored on the target machine func (cs ClientState) VerifyClientState( diff --git a/x/ibc/07-tendermint/types/client_state_test.go b/x/ibc/07-tendermint/types/client_state_test.go index 5c8adab9ac..ac071e4979 100644 --- a/x/ibc/07-tendermint/types/client_state_test.go +++ b/x/ibc/07-tendermint/types/client_state_test.go @@ -32,52 +32,57 @@ func (suite *TendermintTestSuite) TestValidate() { }{ { name: "valid client", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), + expPass: true, + }, + { + name: "valid client with nil upgrade path", + clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), nil, false, false), expPass: true, }, { name: "invalid chainID", - clientState: types.NewClientState(" ", types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + clientState: types.NewClientState(" ", types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), expPass: false, }, { name: "invalid trust level", - clientState: types.NewClientState(chainID, types.Fraction{Numerator: 0, Denominator: 1}, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + clientState: types.NewClientState(chainID, types.Fraction{Numerator: 0, Denominator: 1}, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), expPass: false, }, { name: "invalid trusting period", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, 0, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + clientState: types.NewClientState(chainID, types.DefaultTrustLevel, 0, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), expPass: false, }, { name: "invalid unbonding period", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, 0, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, 0, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), expPass: false, }, { name: "invalid max clock drift", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, 0, height, commitmenttypes.GetSDKSpecs(), false, false), + clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, 0, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), expPass: false, }, { name: "invalid height", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.ZeroHeight(), commitmenttypes.GetSDKSpecs(), false, false), + clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.ZeroHeight(), commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), expPass: false, }, { name: "trusting period not less than unbonding period", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + clientState: types.NewClientState(chainID, types.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), expPass: false, }, { name: "proof specs is nil", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, height, nil, false, false), + clientState: types.NewClientState(chainID, types.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, height, nil, &upgradePath, false, false), expPass: false, }, { name: "proof specs contains nil", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, height, []*ics23.ProofSpec{ics23.TendermintSpec, nil}, false, false), + clientState: types.NewClientState(chainID, types.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, height, []*ics23.ProofSpec{ics23.TendermintSpec, nil}, &upgradePath, false, false), expPass: false, }, } @@ -113,7 +118,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { // }, { name: "ApplyPrefix failed", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), consensusState: types.ConsensusState{ Root: commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), }, @@ -122,7 +127,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { }, { name: "latest client height < height", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), consensusState: types.ConsensusState{ Root: commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), }, @@ -140,7 +145,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { }, { name: "proof verification failed", - clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), consensusState: types.ConsensusState{ Root: commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), NextValidatorsHash: suite.valsHash, diff --git a/x/ibc/07-tendermint/types/misbehaviour_handle_test.go b/x/ibc/07-tendermint/types/misbehaviour_handle_test.go index 604a56ec46..54bbefae25 100644 --- a/x/ibc/07-tendermint/types/misbehaviour_handle_test.go +++ b/x/ibc/07-tendermint/types/misbehaviour_handle_test.go @@ -53,7 +53,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }{ { "valid misbehavior misbehaviour", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), @@ -69,7 +69,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "valid misbehavior at height greater than last consensusState", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), heightMinus1, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), @@ -85,7 +85,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "valid misbehaviour with different trusted heights", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), heightMinus1, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), @@ -101,7 +101,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "valid misbehaviour at a previous epoch", - types.NewClientState(chainIDEpoch1, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(1, 1), commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainIDEpoch1, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(1, 1), commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), heightMinus1, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), @@ -117,7 +117,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "valid misbehaviour at a future epoch", - types.NewClientState(chainIDEpoch0, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainIDEpoch0, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), heightMinus1, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), @@ -133,7 +133,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "valid misbehaviour with trusted heights at a previous epoch", - types.NewClientState(chainIDEpoch1, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(1, 1), commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainIDEpoch1, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(1, 1), commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), heightMinus1, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), @@ -149,7 +149,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "consensus state's valset hash different from misbehaviour should still pass", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), height, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), @@ -165,7 +165,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "invalid misbehavior misbehaviour from different chain", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), @@ -181,7 +181,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "invalid misbehavior misbehaviour with trusted height different from trusted consensus state", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), heightMinus1, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), @@ -197,7 +197,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "invalid misbehavior misbehaviour with trusted validators different from trusted consensus state", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), heightMinus1, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), @@ -229,7 +229,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "trusted consensus state does not exist", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), nil, // consensus state for trusted height - 1 does not exist in store clienttypes.Height{}, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), @@ -245,7 +245,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "invalid tendermint misbehaviour", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), @@ -256,7 +256,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "rejected misbehaviour due to expired age duration", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), @@ -272,7 +272,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "rejected misbehaviour due to expired block duration", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(0, uint64(epochHeight+simapp.DefaultConsensusParams.Evidence.MaxAgeNumBlocks+1)), commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(0, uint64(epochHeight+simapp.DefaultConsensusParams.Evidence.MaxAgeNumBlocks+1)), commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), @@ -288,7 +288,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "provided height > header height", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), @@ -304,7 +304,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "unbonding period expired", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(time.Time{}, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), heightMinus1, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), @@ -320,7 +320,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "trusted validators is incorrect for given consensus state", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), @@ -336,7 +336,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "first valset has too much change", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), @@ -352,7 +352,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "second valset has too much change", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), @@ -368,7 +368,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "both valsets have too much change", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false), + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false), types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), diff --git a/x/ibc/07-tendermint/types/tendermint.pb.go b/x/ibc/07-tendermint/types/tendermint.pb.go index d9c25b4c45..b32670e173 100644 --- a/x/ibc/07-tendermint/types/tendermint.pb.go +++ b/x/ibc/07-tendermint/types/tendermint.pb.go @@ -51,12 +51,14 @@ type ClientState struct { LatestHeight types.Height `protobuf:"bytes,7,opt,name=latest_height,json=latestHeight,proto3" json:"latest_height" yaml:"latest_height"` // Proof specifications used in verifying counterparty state ProofSpecs []*_go.ProofSpec `protobuf:"bytes,8,rep,name=proof_specs,json=proofSpecs,proto3" json:"proof_specs,omitempty" yaml:"proof_specs"` + // Path at which next upgraded client will be committed + UpgradePath *types1.MerklePath `protobuf:"bytes,9,opt,name=upgrade_path,json=upgradePath,proto3" json:"upgrade_path,omitempty" yaml:"upgrade_path"` // This flag, when set to true, will allow governance to recover a client // which has expired - AllowUpdateAfterExpiry bool `protobuf:"varint,9,opt,name=allow_update_after_expiry,json=allowUpdateAfterExpiry,proto3" json:"allow_update_after_expiry,omitempty" yaml:"allow_update_after_expiry"` + AllowUpdateAfterExpiry bool `protobuf:"varint,10,opt,name=allow_update_after_expiry,json=allowUpdateAfterExpiry,proto3" json:"allow_update_after_expiry,omitempty" yaml:"allow_update_after_expiry"` // This flag, when set to true, will allow governance to unfreeze a client // whose chain has experienced a misbehaviour event - AllowUpdateAfterMisbehaviour bool `protobuf:"varint,10,opt,name=allow_update_after_misbehaviour,json=allowUpdateAfterMisbehaviour,proto3" json:"allow_update_after_misbehaviour,omitempty" yaml:"allow_update_after_misbehaviour"` + AllowUpdateAfterMisbehaviour bool `protobuf:"varint,11,opt,name=allow_update_after_misbehaviour,json=allowUpdateAfterMisbehaviour,proto3" json:"allow_update_after_misbehaviour,omitempty" yaml:"allow_update_after_misbehaviour"` } func (m *ClientState) Reset() { *m = ClientState{} } @@ -313,72 +315,74 @@ func init() { func init() { proto.RegisterFile("ibc/tendermint/tendermint.proto", fileDescriptor_76a953d5a747dd66) } var fileDescriptor_76a953d5a747dd66 = []byte{ - // 1034 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0x4f, 0x6f, 0xe3, 0xc4, - 0x1b, 0xae, 0xdb, 0xfe, 0xda, 0x74, 0x92, 0xfe, 0xf9, 0xcd, 0x96, 0xae, 0x5b, 0xba, 0x71, 0x34, - 0x20, 0x54, 0x21, 0xad, 0x4d, 0xb3, 0x2b, 0x90, 0x7a, 0xc3, 0x5d, 0x50, 0x8b, 0x58, 0xa9, 0xb8, - 0x14, 0x10, 0x12, 0xb2, 0x1c, 0x7b, 0x92, 0x8c, 0x6a, 0x7b, 0x8c, 0x67, 0x52, 0x52, 0x3e, 0x01, - 0x48, 0x1c, 0x56, 0x9c, 0xf6, 0xc0, 0x01, 0xbe, 0xcd, 0x1e, 0x7b, 0xe4, 0x64, 0x50, 0xfb, 0x0d, - 0x72, 0xe4, 0x84, 0x3c, 0x33, 0xfe, 0x93, 0xb4, 0xd5, 0x2e, 0x97, 0x64, 0xe6, 0x7d, 0xde, 0xe7, - 0x79, 0xe2, 0x77, 0xde, 0x79, 0x1d, 0x60, 0x90, 0x9e, 0x6f, 0x71, 0x1c, 0x07, 0x38, 0x8d, 0x48, - 0xcc, 0x6b, 0x4b, 0x33, 0x49, 0x29, 0xa7, 0x70, 0x8d, 0xf4, 0x7c, 0xb3, 0x8a, 0xee, 0x74, 0xea, - 0xc9, 0x97, 0x09, 0x66, 0xd6, 0x85, 0x17, 0x92, 0xc0, 0xe3, 0x34, 0x95, 0x8c, 0x9d, 0xdd, 0x5b, - 0x19, 0xe2, 0x53, 0xa1, 0x0f, 0x7c, 0x1a, 0xf7, 0x09, 0xb5, 0x92, 0x94, 0xd2, 0x7e, 0x11, 0x6c, - 0x0f, 0x28, 0x1d, 0x84, 0xd8, 0x12, 0xbb, 0xde, 0xa8, 0x6f, 0x05, 0xa3, 0xd4, 0xe3, 0x84, 0xc6, - 0x0a, 0x37, 0x66, 0x71, 0x4e, 0x22, 0xcc, 0xb8, 0x17, 0x25, 0x2a, 0xe1, 0x61, 0xfe, 0x18, 0x7e, - 0x48, 0x70, 0xcc, 0xd5, 0x57, 0xc1, 0x14, 0x00, 0x8d, 0x22, 0xc2, 0x23, 0x01, 0x96, 0x4b, 0x95, - 0xb0, 0x39, 0xa0, 0x03, 0x2a, 0x96, 0x56, 0xbe, 0x92, 0x51, 0xf4, 0xcb, 0x32, 0x68, 0x1e, 0x0a, - 0x9d, 0x53, 0xee, 0x71, 0x0c, 0xb7, 0x41, 0xc3, 0x1f, 0x7a, 0x24, 0x76, 0x49, 0xa0, 0x6b, 0x1d, - 0x6d, 0x6f, 0xc5, 0x59, 0x16, 0xfb, 0xe3, 0x00, 0x9e, 0x81, 0x26, 0x4f, 0x47, 0x8c, 0xbb, 0x21, - 0xbe, 0xc0, 0xa1, 0x3e, 0xdf, 0xd1, 0xf6, 0x9a, 0x5d, 0xdd, 0x9c, 0x2e, 0x9b, 0xf9, 0x69, 0xea, - 0xf9, 0xf9, 0x03, 0xd9, 0x3b, 0xaf, 0x32, 0x63, 0x6e, 0x92, 0x19, 0xf0, 0xd2, 0x8b, 0xc2, 0x03, - 0x54, 0xa3, 0x22, 0x07, 0x88, 0xdd, 0xe7, 0xf9, 0x06, 0xf6, 0xc1, 0xba, 0xd8, 0x91, 0x78, 0xe0, - 0x26, 0x38, 0x25, 0x34, 0xd0, 0x17, 0x84, 0xf4, 0xb6, 0x29, 0x8b, 0x61, 0x16, 0xc5, 0x30, 0x9f, - 0xa9, 0x62, 0xd9, 0x48, 0x69, 0x6f, 0xd5, 0xb4, 0x2b, 0x3e, 0x7a, 0xf9, 0x97, 0xa1, 0x39, 0x6b, - 0x45, 0xf4, 0x44, 0x04, 0x21, 0x01, 0x1b, 0xa3, 0xb8, 0x47, 0xe3, 0xa0, 0x66, 0xb4, 0xf8, 0x3a, - 0xa3, 0x77, 0x94, 0xd1, 0x43, 0x69, 0x34, 0x2b, 0x20, 0x9d, 0xd6, 0xcb, 0xb0, 0xb2, 0xc2, 0x60, - 0x3d, 0xf2, 0xc6, 0xae, 0x1f, 0x52, 0xff, 0xdc, 0x0d, 0x52, 0xd2, 0xe7, 0xfa, 0xff, 0xfe, 0xe3, - 0x23, 0xcd, 0xf0, 0xa5, 0xd1, 0x6a, 0xe4, 0x8d, 0x0f, 0xf3, 0xe0, 0xb3, 0x3c, 0x06, 0xcf, 0xc0, - 0x6a, 0x3f, 0xa5, 0x3f, 0xe2, 0xd8, 0x1d, 0x62, 0x32, 0x18, 0x72, 0x7d, 0x49, 0x98, 0x40, 0x71, - 0x24, 0xaa, 0x39, 0x8e, 0x04, 0x62, 0xef, 0x2a, 0xf5, 0x4d, 0xa9, 0x3e, 0x45, 0x43, 0x4e, 0x4b, - 0xee, 0x65, 0x6e, 0x2e, 0x1b, 0x7a, 0x1c, 0x33, 0x5e, 0xc8, 0x2e, 0xbf, 0xa9, 0xec, 0x14, 0x0d, - 0x39, 0x2d, 0xb9, 0x57, 0xb2, 0xc7, 0xa0, 0x29, 0xae, 0x82, 0xcb, 0x12, 0xec, 0x33, 0xbd, 0xd1, - 0x59, 0xd8, 0x6b, 0x76, 0x37, 0x4c, 0xe2, 0xb3, 0xee, 0x13, 0xf3, 0x24, 0x47, 0x4e, 0x13, 0xec, - 0xdb, 0x5b, 0x55, 0xcb, 0xd4, 0xd2, 0x91, 0x03, 0x92, 0x22, 0x85, 0x41, 0x17, 0x6c, 0x7b, 0x61, - 0x48, 0x7f, 0x70, 0x47, 0x49, 0xe0, 0x71, 0xec, 0x7a, 0x7d, 0x8e, 0x53, 0x17, 0x8f, 0x13, 0x92, - 0x5e, 0xea, 0x2b, 0x1d, 0x6d, 0xaf, 0x61, 0xbf, 0x3b, 0xc9, 0x8c, 0x8e, 0x94, 0xb9, 0x37, 0x15, - 0x39, 0x5b, 0x02, 0x3b, 0x13, 0xd0, 0xc7, 0x39, 0xf2, 0x89, 0x00, 0xe0, 0xf7, 0xc0, 0xb8, 0x83, - 0x15, 0x11, 0xd6, 0xc3, 0x43, 0xef, 0x82, 0xd0, 0x51, 0xaa, 0x03, 0x61, 0xf3, 0xfe, 0x24, 0x33, - 0xde, 0xbb, 0xd7, 0xa6, 0x4e, 0x40, 0xce, 0xee, 0xac, 0xd9, 0xf3, 0x1a, 0x7c, 0xb0, 0xf8, 0xd3, - 0xef, 0xc6, 0x1c, 0xfa, 0x6d, 0x1e, 0xac, 0x1d, 0xd2, 0x98, 0xe1, 0x98, 0x8d, 0x98, 0xbc, 0x91, - 0x36, 0x58, 0x29, 0x87, 0x80, 0xb8, 0x92, 0xcd, 0xee, 0xce, 0xad, 0x36, 0xfa, 0xb2, 0xc8, 0xb0, - 0x1b, 0xf9, 0x91, 0xbc, 0xc8, 0xbb, 0xa5, 0xa2, 0xc1, 0xa7, 0x60, 0x31, 0xa5, 0x94, 0xab, 0x3b, - 0xbb, 0x23, 0x4f, 0xb2, 0x1a, 0x10, 0xcf, 0x71, 0x7a, 0x1e, 0x62, 0x87, 0x52, 0x6e, 0x2f, 0xe6, - 0x74, 0x47, 0x64, 0xc3, 0x9f, 0x35, 0xb0, 0x19, 0xe3, 0x31, 0x77, 0xcb, 0xc1, 0xc7, 0xdc, 0xa1, - 0xc7, 0x86, 0xe2, 0x7e, 0xb6, 0xec, 0xaf, 0x27, 0x99, 0xf1, 0xb6, 0x7c, 0xf6, 0xbb, 0xb2, 0xd0, - 0x3f, 0x99, 0xf1, 0x74, 0x40, 0xf8, 0x70, 0xd4, 0xcb, 0xbd, 0xee, 0x9e, 0xbd, 0x56, 0x48, 0x7a, - 0xcc, 0xea, 0x5d, 0x72, 0xcc, 0xcc, 0x23, 0x3c, 0xb6, 0xf3, 0x85, 0x03, 0x73, 0xb9, 0xaf, 0x4a, - 0xb5, 0x23, 0x8f, 0x0d, 0x55, 0x79, 0xfe, 0x98, 0x07, 0xad, 0x7a, 0xd5, 0xe0, 0x3e, 0x58, 0x91, - 0x1d, 0x59, 0xce, 0x2b, 0x7b, 0x73, 0x92, 0x19, 0x1b, 0xf2, 0x67, 0x95, 0x10, 0x72, 0x1a, 0x72, - 0x7d, 0x1c, 0x40, 0xb3, 0x36, 0xe1, 0xe6, 0x05, 0xe3, 0xc1, 0x24, 0x33, 0xd6, 0x15, 0x43, 0x21, - 0xa8, 0x1a, 0x7b, 0x5f, 0x80, 0xc6, 0x10, 0x7b, 0x01, 0x4e, 0xdd, 0x7d, 0x35, 0x98, 0xb6, 0x66, - 0x67, 0xde, 0x91, 0xc0, 0xed, 0xf6, 0x75, 0x66, 0x2c, 0xcb, 0xf5, 0x7e, 0x25, 0x59, 0x90, 0x91, - 0xb3, 0x2c, 0x97, 0xfb, 0x35, 0xc9, 0xae, 0x1a, 0x41, 0x6f, 0x20, 0xd9, 0xbd, 0x25, 0xd9, 0x2d, - 0x25, 0xbb, 0x07, 0x8d, 0xbc, 0x3e, 0x2f, 0xf3, 0x1a, 0xfd, 0xba, 0x00, 0x96, 0x24, 0x03, 0x7a, - 0x60, 0x95, 0x91, 0x41, 0x8c, 0x03, 0x57, 0xa6, 0xa9, 0xf6, 0x69, 0xd7, 0x8d, 0xe4, 0x2b, 0xeb, - 0x54, 0xa4, 0x29, 0xd3, 0xdd, 0xab, 0xcc, 0xd0, 0xaa, 0x5b, 0x3d, 0x25, 0x81, 0x9c, 0x16, 0xab, - 0xe5, 0xc2, 0xef, 0xc0, 0x6a, 0x79, 0xee, 0x2e, 0xc3, 0x45, 0x8b, 0xdd, 0x61, 0x51, 0x1e, 0xe8, - 0x29, 0xe6, 0xb6, 0x5e, 0xc9, 0x4f, 0xd1, 0x91, 0xd3, 0xba, 0xa8, 0xe5, 0xc1, 0x6f, 0x80, 0x1c, - 0xe3, 0xc2, 0x5f, 0x0c, 0xa3, 0x85, 0x7b, 0x87, 0xd1, 0x23, 0x35, 0x8c, 0xde, 0xaa, 0xbd, 0x14, - 0x4a, 0x1e, 0x72, 0x56, 0x55, 0x40, 0x8d, 0xa3, 0x10, 0xc0, 0x22, 0xa3, 0x6a, 0x5c, 0x75, 0x1a, - 0xaf, 0xfb, 0xf5, 0x8f, 0x26, 0x99, 0xb1, 0x3d, 0xed, 0x52, 0x69, 0x20, 0xe7, 0xff, 0x2a, 0x58, - 0xb5, 0x30, 0xfa, 0x0c, 0x34, 0x8a, 0x17, 0x23, 0xdc, 0x05, 0x2b, 0xf1, 0x28, 0xc2, 0x69, 0x8e, - 0x88, 0x13, 0x59, 0x70, 0xaa, 0x00, 0xec, 0x80, 0x66, 0x80, 0x63, 0x1a, 0x91, 0x58, 0xe0, 0xf3, - 0x02, 0xaf, 0x87, 0xec, 0x93, 0x57, 0xd7, 0x6d, 0xed, 0xea, 0xba, 0xad, 0xfd, 0x7d, 0xdd, 0xd6, - 0x5e, 0xdc, 0xb4, 0xe7, 0xae, 0x6e, 0xda, 0x73, 0x7f, 0xde, 0xb4, 0xe7, 0xbe, 0xfd, 0xb0, 0x76, - 0xdd, 0x7c, 0xca, 0x22, 0xca, 0xd4, 0xd7, 0x63, 0x16, 0x9c, 0x5b, 0x63, 0x2b, 0xff, 0x8b, 0xf0, - 0xc1, 0x47, 0x8f, 0x67, 0xff, 0xb6, 0xf4, 0x96, 0xc4, 0x1c, 0x79, 0xf2, 0x6f, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xf9, 0x7c, 0x92, 0x83, 0x24, 0x09, 0x00, 0x00, + // 1067 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0xcf, 0x6f, 0xe3, 0x44, + 0x14, 0x6e, 0xda, 0xd2, 0xa6, 0x93, 0xf4, 0x07, 0xd3, 0xd2, 0xba, 0x25, 0x1b, 0x47, 0x06, 0xa1, + 0x0a, 0x69, 0x1d, 0x9a, 0x5d, 0x81, 0xd4, 0x1b, 0xee, 0x82, 0x5a, 0xc4, 0x4a, 0xc5, 0xa5, 0x0b, + 0x42, 0x42, 0xd6, 0xc4, 0x9e, 0xc4, 0xa3, 0xda, 0x1e, 0xe3, 0x99, 0x94, 0x94, 0xbf, 0x00, 0x6e, + 0x2b, 0x4e, 0x7b, 0xe0, 0x00, 0xff, 0xcd, 0x1e, 0x7b, 0xe4, 0x64, 0x50, 0xcb, 0x5f, 0x90, 0x23, + 0x27, 0xe4, 0x99, 0xf1, 0x8f, 0x64, 0x5b, 0xed, 0x72, 0x69, 0x67, 0xde, 0xf7, 0xbe, 0xef, 0xb3, + 0xdf, 0xbc, 0x79, 0x0e, 0xd0, 0x49, 0xdf, 0xed, 0x72, 0x1c, 0x79, 0x38, 0x09, 0x49, 0xc4, 0x2b, + 0x4b, 0x33, 0x4e, 0x28, 0xa7, 0x70, 0x8d, 0xf4, 0x5d, 0xb3, 0x8c, 0xee, 0x75, 0xaa, 0xc9, 0x57, + 0x31, 0x66, 0xdd, 0x4b, 0x14, 0x10, 0x0f, 0x71, 0x9a, 0x48, 0xc6, 0x5e, 0xeb, 0x95, 0x0c, 0xf1, + 0x57, 0xa1, 0x9b, 0x2e, 0x8d, 0x06, 0x84, 0x76, 0xe3, 0x84, 0xd2, 0x41, 0x1e, 0x6c, 0x0f, 0x29, + 0x1d, 0x06, 0xb8, 0x2b, 0x76, 0xfd, 0xd1, 0xa0, 0xeb, 0x8d, 0x12, 0xc4, 0x09, 0x8d, 0x14, 0xae, + 0xcf, 0xe2, 0x9c, 0x84, 0x98, 0x71, 0x14, 0xc6, 0x2a, 0x61, 0x27, 0x7b, 0x0d, 0x37, 0x20, 0x38, + 0xe2, 0xea, 0x5f, 0xce, 0x14, 0x00, 0x0d, 0x43, 0xc2, 0x43, 0x01, 0x16, 0x4b, 0x95, 0xb0, 0x35, + 0xa4, 0x43, 0x2a, 0x96, 0xdd, 0x6c, 0x25, 0xa3, 0xc6, 0x3f, 0xcb, 0xa0, 0x71, 0x24, 0x74, 0xce, + 0x38, 0xe2, 0x18, 0xee, 0x82, 0xba, 0xeb, 0x23, 0x12, 0x39, 0xc4, 0xd3, 0x6a, 0x9d, 0xda, 0xfe, + 0x8a, 0xbd, 0x2c, 0xf6, 0x27, 0x1e, 0x3c, 0x07, 0x0d, 0x9e, 0x8c, 0x18, 0x77, 0x02, 0x7c, 0x89, + 0x03, 0x6d, 0xbe, 0x53, 0xdb, 0x6f, 0xf4, 0x34, 0x73, 0xba, 0x6c, 0xe6, 0xe7, 0x09, 0x72, 0xb3, + 0x17, 0xb2, 0xf6, 0x5e, 0xa6, 0xfa, 0xdc, 0x24, 0xd5, 0xe1, 0x15, 0x0a, 0x83, 0x43, 0xa3, 0x42, + 0x35, 0x6c, 0x20, 0x76, 0x5f, 0x66, 0x1b, 0x38, 0x00, 0xeb, 0x62, 0x47, 0xa2, 0xa1, 0x13, 0xe3, + 0x84, 0x50, 0x4f, 0x5b, 0x10, 0xd2, 0xbb, 0xa6, 0x2c, 0x86, 0x99, 0x17, 0xc3, 0x7c, 0xa2, 0x8a, + 0x65, 0x19, 0x4a, 0x7b, 0xbb, 0xa2, 0x5d, 0xf2, 0x8d, 0x17, 0x7f, 0xe9, 0x35, 0x7b, 0x2d, 0x8f, + 0x9e, 0x8a, 0x20, 0x24, 0x60, 0x63, 0x14, 0xf5, 0x69, 0xe4, 0x55, 0x8c, 0x16, 0x5f, 0x67, 0xf4, + 0x9e, 0x32, 0xda, 0x91, 0x46, 0xb3, 0x02, 0xd2, 0x69, 0xbd, 0x08, 0x2b, 0x2b, 0x0c, 0xd6, 0x43, + 0x34, 0x76, 0xdc, 0x80, 0xba, 0x17, 0x8e, 0x97, 0x90, 0x01, 0xd7, 0xde, 0xfa, 0x9f, 0xaf, 0x34, + 0xc3, 0x97, 0x46, 0xab, 0x21, 0x1a, 0x1f, 0x65, 0xc1, 0x27, 0x59, 0x0c, 0x9e, 0x83, 0xd5, 0x41, + 0x42, 0x7f, 0xc2, 0x91, 0xe3, 0x63, 0x32, 0xf4, 0xb9, 0xb6, 0x24, 0x4c, 0xa0, 0x38, 0x12, 0xd5, + 0x1c, 0xc7, 0x02, 0xb1, 0x5a, 0x4a, 0x7d, 0x4b, 0xaa, 0x4f, 0xd1, 0x0c, 0xbb, 0x29, 0xf7, 0x32, + 0x37, 0x93, 0x0d, 0x10, 0xc7, 0x8c, 0xe7, 0xb2, 0xcb, 0x6f, 0x2a, 0x3b, 0x45, 0x33, 0xec, 0xa6, + 0xdc, 0x2b, 0xd9, 0x13, 0xd0, 0x10, 0x57, 0xc1, 0x61, 0x31, 0x76, 0x99, 0x56, 0xef, 0x2c, 0xec, + 0x37, 0x7a, 0x1b, 0x26, 0x71, 0x59, 0xef, 0x91, 0x79, 0x9a, 0x21, 0x67, 0x31, 0x76, 0xad, 0xed, + 0xb2, 0x65, 0x2a, 0xe9, 0x86, 0x0d, 0xe2, 0x3c, 0x85, 0xc1, 0x67, 0xa0, 0x39, 0x8a, 0x87, 0x09, + 0xf2, 0xb0, 0x13, 0x23, 0xee, 0x6b, 0x2b, 0xe2, 0x01, 0xf7, 0xe4, 0x03, 0x96, 0x7d, 0xff, 0x14, + 0x27, 0x17, 0x01, 0x3e, 0x45, 0xdc, 0xb7, 0x76, 0x26, 0xa9, 0xbe, 0xa9, 0xce, 0xb0, 0xc2, 0x34, + 0xec, 0x86, 0xda, 0x66, 0x59, 0xd0, 0x01, 0xbb, 0x28, 0x08, 0xe8, 0x8f, 0xce, 0x28, 0xf6, 0x10, + 0xc7, 0x0e, 0x1a, 0x70, 0x9c, 0x38, 0x78, 0x1c, 0x93, 0xe4, 0x4a, 0x03, 0x9d, 0xda, 0x7e, 0xdd, + 0x7a, 0x7f, 0x92, 0xea, 0x1d, 0x29, 0x74, 0x6f, 0xaa, 0x61, 0x6f, 0x0b, 0xec, 0x5c, 0x40, 0x9f, + 0x66, 0xc8, 0x67, 0x02, 0x80, 0x3f, 0x00, 0xfd, 0x0e, 0x56, 0x48, 0x58, 0x1f, 0xfb, 0xe8, 0x92, + 0xd0, 0x51, 0xa2, 0x35, 0x84, 0xcd, 0x87, 0x93, 0x54, 0xff, 0xe0, 0x5e, 0x9b, 0x2a, 0xc1, 0xb0, + 0x5b, 0xb3, 0x66, 0x4f, 0x2b, 0xf0, 0xe1, 0xe2, 0xcf, 0xbf, 0xeb, 0x73, 0xc6, 0x6f, 0xf3, 0x60, + 0xed, 0x88, 0x46, 0x0c, 0x47, 0x6c, 0xc4, 0xe4, 0x4d, 0xb7, 0xc0, 0x4a, 0x31, 0x5c, 0xc4, 0x55, + 0xcf, 0x2a, 0x38, 0xdb, 0x9e, 0x5f, 0xe7, 0x19, 0x56, 0x3d, 0x3b, 0xea, 0xe7, 0x59, 0x17, 0x96, + 0x34, 0xf8, 0x18, 0x2c, 0x26, 0x94, 0x72, 0x35, 0x0b, 0xee, 0x39, 0x00, 0x9b, 0x52, 0x6e, 0x2d, + 0x66, 0x74, 0x5b, 0x64, 0xc3, 0x5f, 0x6a, 0x60, 0x2b, 0xc2, 0x63, 0xee, 0x14, 0x03, 0x95, 0x39, + 0x3e, 0x62, 0xbe, 0xb8, 0xf7, 0x4d, 0xeb, 0x9b, 0x49, 0xaa, 0xbf, 0x2b, 0xdf, 0xfd, 0xae, 0x2c, + 0xe3, 0xdf, 0x54, 0x7f, 0x3c, 0x24, 0xdc, 0x1f, 0xf5, 0x33, 0xaf, 0xbb, 0x67, 0x7a, 0x37, 0x20, + 0x7d, 0xd6, 0xed, 0x5f, 0x71, 0xcc, 0xcc, 0x63, 0x3c, 0xb6, 0xb2, 0x85, 0x0d, 0x33, 0xb9, 0x67, + 0x85, 0xda, 0x31, 0x62, 0xbe, 0x2a, 0xcf, 0x1f, 0xf3, 0xa0, 0x59, 0xad, 0x1a, 0x3c, 0x00, 0x2b, + 0xb2, 0xd3, 0x8b, 0x39, 0x68, 0x6d, 0x4d, 0x52, 0x7d, 0x43, 0x3e, 0x56, 0x01, 0x19, 0x76, 0x5d, + 0xae, 0x4f, 0x3c, 0x68, 0x56, 0x26, 0xe7, 0xbc, 0x60, 0x6c, 0x4e, 0x52, 0x7d, 0x5d, 0x31, 0x14, + 0x62, 0x94, 0xe3, 0xf4, 0x2b, 0x50, 0xf7, 0x31, 0xf2, 0x70, 0xe2, 0x1c, 0xa8, 0x81, 0xb7, 0x3d, + 0x3b, 0x4b, 0x8f, 0x05, 0x6e, 0xb5, 0x6f, 0x52, 0x7d, 0x59, 0xae, 0x0f, 0x4a, 0xc9, 0x9c, 0x6c, + 0xd8, 0xcb, 0x72, 0x79, 0x50, 0x91, 0xec, 0xa9, 0xd1, 0xf6, 0x06, 0x92, 0xbd, 0x57, 0x24, 0x7b, + 0x85, 0x64, 0xef, 0xb0, 0x9e, 0xd5, 0xe7, 0x45, 0x56, 0xa3, 0x5f, 0x17, 0xc0, 0x92, 0x64, 0x40, + 0x04, 0x56, 0x19, 0x19, 0x46, 0xd8, 0x73, 0x64, 0x9a, 0x6a, 0x9f, 0x76, 0xd5, 0x48, 0x7e, 0x0a, + 0xcf, 0x44, 0x9a, 0x32, 0x6d, 0x5d, 0xa7, 0x7a, 0xad, 0x9c, 0x16, 0x53, 0x12, 0x86, 0xdd, 0x64, + 0x95, 0x5c, 0xf8, 0x3d, 0x58, 0x2d, 0xce, 0xdd, 0x61, 0x38, 0x6f, 0xb1, 0x3b, 0x2c, 0x8a, 0x03, + 0x3d, 0xc3, 0xdc, 0xd2, 0x4a, 0xf9, 0x29, 0xba, 0x61, 0x37, 0x2f, 0x2b, 0x79, 0xf0, 0x5b, 0x20, + 0x3f, 0x0f, 0xc2, 0x5f, 0x0c, 0xb9, 0x85, 0x7b, 0x87, 0xdc, 0x03, 0x35, 0xe4, 0xde, 0xa9, 0x7c, + 0x6c, 0x0a, 0x9e, 0x61, 0xaf, 0xaa, 0x80, 0x1a, 0x73, 0x01, 0x80, 0x79, 0x46, 0xd9, 0xb8, 0xea, + 0x34, 0x5e, 0xf7, 0xf4, 0x0f, 0x26, 0xa9, 0xbe, 0x3b, 0xed, 0x52, 0x6a, 0x18, 0xf6, 0xdb, 0x2a, + 0x58, 0xb6, 0xb0, 0xf1, 0x05, 0xa8, 0xe7, 0x1f, 0x5c, 0xd8, 0x02, 0x2b, 0xd1, 0x28, 0xc4, 0x49, + 0x86, 0x88, 0x13, 0x59, 0xb0, 0xcb, 0x00, 0xec, 0x80, 0x86, 0x87, 0x23, 0x1a, 0x92, 0x48, 0xe0, + 0xf3, 0x02, 0xaf, 0x86, 0xac, 0xd3, 0x97, 0x37, 0xed, 0xda, 0xf5, 0x4d, 0xbb, 0xf6, 0xf7, 0x4d, + 0xbb, 0xf6, 0xfc, 0xb6, 0x3d, 0x77, 0x7d, 0xdb, 0x9e, 0xfb, 0xf3, 0xb6, 0x3d, 0xf7, 0xdd, 0xc7, + 0x95, 0xeb, 0xe6, 0x52, 0x16, 0x52, 0xa6, 0xfe, 0x3d, 0x64, 0xde, 0x45, 0x77, 0xdc, 0xcd, 0x7e, + 0x7a, 0x7c, 0xf4, 0xc9, 0xc3, 0xd9, 0x9f, 0x43, 0xfd, 0x25, 0x31, 0x47, 0x1e, 0xfd, 0x17, 0x00, + 0x00, 0xff, 0xff, 0x0a, 0x9b, 0x13, 0xaa, 0x7c, 0x09, 0x00, 0x00, } func (m *ClientState) Marshal() (dAtA []byte, err error) { @@ -409,7 +413,7 @@ func (m *ClientState) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0 } i-- - dAtA[i] = 0x50 + dAtA[i] = 0x58 } if m.AllowUpdateAfterExpiry { i-- @@ -419,7 +423,19 @@ func (m *ClientState) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0 } i-- - dAtA[i] = 0x48 + dAtA[i] = 0x50 + } + if m.UpgradePath != nil { + { + size, err := m.UpgradePath.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTendermint(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a } if len(m.ProofSpecs) > 0 { for iNdEx := len(m.ProofSpecs) - 1; iNdEx >= 0; iNdEx-- { @@ -455,29 +471,29 @@ func (m *ClientState) MarshalToSizedBuffer(dAtA []byte) (int, error) { } i-- dAtA[i] = 0x32 - n3, err3 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.MaxClockDrift, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.MaxClockDrift):]) - if err3 != nil { - return 0, err3 - } - i -= n3 - i = encodeVarintTendermint(dAtA, i, uint64(n3)) - i-- - dAtA[i] = 0x2a - n4, err4 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.UnbondingPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.UnbondingPeriod):]) + n4, err4 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.MaxClockDrift, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.MaxClockDrift):]) if err4 != nil { return 0, err4 } i -= n4 i = encodeVarintTendermint(dAtA, i, uint64(n4)) i-- - dAtA[i] = 0x22 - n5, err5 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.TrustingPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.TrustingPeriod):]) + dAtA[i] = 0x2a + n5, err5 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.UnbondingPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.UnbondingPeriod):]) if err5 != nil { return 0, err5 } i -= n5 i = encodeVarintTendermint(dAtA, i, uint64(n5)) i-- + dAtA[i] = 0x22 + n6, err6 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.TrustingPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.TrustingPeriod):]) + if err6 != nil { + return 0, err6 + } + i -= n6 + i = encodeVarintTendermint(dAtA, i, uint64(n6)) + i-- dAtA[i] = 0x1a { size, err := m.TrustLevel.MarshalToSizedBuffer(dAtA[:i]) @@ -536,12 +552,12 @@ func (m *ConsensusState) MarshalToSizedBuffer(dAtA []byte) (int, error) { } i-- dAtA[i] = 0x12 - n8, err8 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) - if err8 != nil { - return 0, err8 + n9, err9 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) + if err9 != nil { + return 0, err9 } - i -= n8 - i = encodeVarintTendermint(dAtA, i, uint64(n8)) + i -= n9 + i = encodeVarintTendermint(dAtA, i, uint64(n9)) i-- dAtA[i] = 0xa return len(dAtA) - i, nil @@ -749,6 +765,10 @@ func (m *ClientState) Size() (n int) { n += 1 + l + sovTendermint(uint64(l)) } } + if m.UpgradePath != nil { + l = m.UpgradePath.Size() + n += 1 + l + sovTendermint(uint64(l)) + } if m.AllowUpdateAfterExpiry { n += 2 } @@ -1138,6 +1158,42 @@ func (m *ClientState) Unmarshal(dAtA []byte) error { } iNdEx = postIndex case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UpgradePath", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTendermint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTendermint + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTendermint + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.UpgradePath == nil { + m.UpgradePath = &types1.MerklePath{} + } + if err := m.UpgradePath.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field AllowUpdateAfterExpiry", wireType) } @@ -1157,7 +1213,7 @@ func (m *ClientState) Unmarshal(dAtA []byte) error { } } m.AllowUpdateAfterExpiry = bool(v != 0) - case 10: + case 11: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field AllowUpdateAfterMisbehaviour", wireType) } diff --git a/x/ibc/07-tendermint/types/tendermint_test.go b/x/ibc/07-tendermint/types/tendermint_test.go index 39216abd2a..78d09ceb84 100644 --- a/x/ibc/07-tendermint/types/tendermint_test.go +++ b/x/ibc/07-tendermint/types/tendermint_test.go @@ -15,8 +15,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing" ibctestingmock "github.com/cosmos/cosmos-sdk/x/ibc/testing/mock" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) const ( @@ -29,7 +31,11 @@ const ( maxClockDrift time.Duration = time.Second * 10 ) -var height = clienttypes.NewHeight(0, 4) +var ( + height = clienttypes.NewHeight(0, 4) + upgradeHeight = clienttypes.NewHeight(1, 1) + upgradePath = commitmenttypes.NewMerklePath([]string{"upgrade", upgradetypes.KeyUpgradedClient}) +) type TendermintTestSuite struct { suite.Suite diff --git a/x/ibc/07-tendermint/types/update_test.go b/x/ibc/07-tendermint/types/update_test.go index 673539e879..52a040d0c0 100644 --- a/x/ibc/07-tendermint/types/update_test.go +++ b/x/ibc/07-tendermint/types/update_test.go @@ -57,7 +57,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { { name: "successful update with next height and same validator set", setup: func() { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false) + clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) newHeader = types.CreateTestHeader(chainID, heightPlus1, height, suite.headerTime, suite.valSet, suite.valSet, signers) currentTime = suite.now @@ -67,7 +67,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { { name: "successful update with future height and different validator set", setup: func() { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false) + clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) newHeader = types.CreateTestHeader(chainID, heightPlus5, height, suite.headerTime, bothValSet, suite.valSet, bothSigners) currentTime = suite.now @@ -77,7 +77,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { { name: "successful update with next height and different validator set", setup: func() { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false) + clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), bothValSet.Hash()) newHeader = types.CreateTestHeader(chainID, heightPlus1, height, suite.headerTime, bothValSet, bothValSet, bothSigners) currentTime = suite.now @@ -87,7 +87,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { { name: "successful update for a previous height", setup: func() { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false) + clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) consStateHeight = heightMinus3 newHeader = types.CreateTestHeader(chainID, heightMinus1, heightMinus3, suite.headerTime, bothValSet, suite.valSet, bothSigners) @@ -98,7 +98,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { { name: "successful update for a previous epoch", setup: func() { - clientState = types.NewClientState(chainIDEpoch1, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false) + clientState = types.NewClientState(chainIDEpoch1, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) newHeader = types.CreateTestHeader(chainIDEpoch0, height, heightMinus3, suite.headerTime, bothValSet, suite.valSet, bothSigners) currentTime = suite.now @@ -108,7 +108,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { { name: "unsuccessful update with incorrect header chain-id", setup: func() { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false) + clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) newHeader = types.CreateTestHeader("ethermint", heightPlus1, height, suite.headerTime, suite.valSet, suite.valSet, signers) currentTime = suite.now @@ -118,7 +118,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { { name: "unsuccessful update to a future epoch", setup: func() { - clientState = types.NewClientState(chainIDEpoch0, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false) + clientState = types.NewClientState(chainIDEpoch0, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) newHeader = types.CreateTestHeader(chainIDEpoch1, clienttypes.NewHeight(1, 1), height, suite.headerTime, suite.valSet, suite.valSet, signers) currentTime = suite.now @@ -128,7 +128,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { { name: "unsuccessful update: header height epoch and trusted height epoch mismatch", setup: func() { - clientState = types.NewClientState(chainIDEpoch1, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(1, 1), commitmenttypes.GetSDKSpecs(), false, false) + clientState = types.NewClientState(chainIDEpoch1, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(1, 1), commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) newHeader = types.CreateTestHeader(chainIDEpoch1, clienttypes.NewHeight(1, 3), height, suite.headerTime, suite.valSet, suite.valSet, signers) currentTime = suite.now @@ -138,7 +138,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { { name: "unsuccessful update with next height: update header mismatches nextValSetHash", setup: func() { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false) + clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) newHeader = types.CreateTestHeader(chainID, heightPlus1, height, suite.headerTime, bothValSet, suite.valSet, bothSigners) currentTime = suite.now @@ -148,7 +148,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { { name: "unsuccessful update with next height: update header mismatches different nextValSetHash", setup: func() { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false) + clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), bothValSet.Hash()) newHeader = types.CreateTestHeader(chainID, heightPlus1, height, suite.headerTime, suite.valSet, bothValSet, signers) currentTime = suite.now @@ -158,7 +158,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { { name: "unsuccessful update with future height: too much change in validator set", setup: func() { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false) + clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) newHeader = types.CreateTestHeader(chainID, heightPlus5, height, suite.headerTime, altValSet, suite.valSet, altSigners) currentTime = suite.now @@ -168,7 +168,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { { name: "unsuccessful updates, passed in incorrect trusted validators for given consensus state", setup: func() { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false) + clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) newHeader = types.CreateTestHeader(chainID, heightPlus5, height, suite.headerTime, bothValSet, bothValSet, bothSigners) currentTime = suite.now @@ -178,7 +178,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { { name: "unsuccessful update: trusting period has passed since last client timestamp", setup: func() { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false) + clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) newHeader = types.CreateTestHeader(chainID, heightPlus1, height, suite.headerTime, suite.valSet, suite.valSet, signers) // make current time pass trusting period from last timestamp on clientstate @@ -189,7 +189,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { { name: "unsuccessful update: header timestamp is past current timestamp", setup: func() { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false) + clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) newHeader = types.CreateTestHeader(chainID, heightPlus1, height, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers) currentTime = suite.now @@ -199,7 +199,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { { name: "unsuccessful update: header timestamp is not past last client timestamp", setup: func() { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false) + clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) newHeader = types.CreateTestHeader(chainID, heightPlus1, height, suite.clientTime, suite.valSet, suite.valSet, signers) currentTime = suite.now @@ -209,7 +209,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { { name: "header basic validation failed", setup: func() { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false) + clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) newHeader = types.CreateTestHeader(chainID, heightPlus1, height, suite.headerTime, suite.valSet, suite.valSet, signers) // cause new header to fail validatebasic by changing commit height to mismatch header height @@ -221,7 +221,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { { name: "header height < consensus height", setup: func() { - clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, heightPlus5, commitmenttypes.GetSDKSpecs(), false, false) + clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, heightPlus5, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) // Make new header at height less than latest client state newHeader = types.CreateTestHeader(chainID, heightMinus1, height, suite.headerTime, suite.valSet, suite.valSet, signers) diff --git a/x/ibc/07-tendermint/types/upgrade.go b/x/ibc/07-tendermint/types/upgrade.go new file mode 100644 index 0000000000..d2f9366d1e --- /dev/null +++ b/x/ibc/07-tendermint/types/upgrade.go @@ -0,0 +1,58 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + "github.com/cosmos/cosmos-sdk/x/ibc/exported" +) + +// VerifyUpgrade checks if the upgraded client has been committed by the current client +// It will zero out all client-specific fields (e.g. TrustingPeriod and verify all data +// in client state that must be the same across all valid Tendermint clients for the new chain. +// VerifyUpgrade will return an error if: +// - the upgradedClient is not a Tendermint ClientState +// - the height of upgraded client is not greater than that of current client +// - the latest height of the new client does not match the height in committed client +// - any Tendermint chain specified parameter in upgraded client such as ChainID, UnbondingPeriod, +// and ProofSpecs do not match parameters set by committed client +func (cs ClientState) VerifyUpgrade( + ctx sdk.Context, cdc codec.BinaryMarshaler, clientStore sdk.KVStore, + upgradedClient exported.ClientState, proofUpgrade []byte, +) error { + if cs.UpgradePath == nil { + return sdkerrors.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade client, no upgrade path set") + } + + if !upgradedClient.GetLatestHeight().GT(cs.GetLatestHeight()) { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidHeight, "upgrade client height %s must be greater than current client height %s", + upgradedClient.GetLatestHeight(), cs.GetLatestHeight()) + } + + if len(proofUpgrade) == 0 { + return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "proof of upgrade is empty") + } + + var merkleProof commitmenttypes.MerkleProof + if err := cdc.UnmarshalBinaryBare(proofUpgrade, &merkleProof); err != nil { + return sdkerrors.Wrapf(commitmenttypes.ErrInvalidProof, "could not unmarshal merkle proof: %v", err) + } + + // counterparty chain must commit the upgraded client with all client-customizable fields zeroed out + // at the upgrade path specified by current client + committedClient := upgradedClient.ZeroCustomFields() + bz, err := codec.MarshalAny(cdc, committedClient) + if err != nil { + return sdkerrors.Wrapf(clienttypes.ErrInvalidClient, "could not marshal client state: %v", err) + } + + // Must prove against latest consensus state to ensure we are verifying against latest upgrade plan + consState, err := GetConsensusState(clientStore, cdc, cs.GetLatestHeight()) + if err != nil { + return sdkerrors.Wrap(err, "could not retrieve latest consensus state") + } + + return merkleProof.VerifyMembership(cs.ProofSpecs, consState.GetRoot(), *cs.UpgradePath, bz) +} diff --git a/x/ibc/07-tendermint/types/upgrade_test.go b/x/ibc/07-tendermint/types/upgrade_test.go new file mode 100644 index 0000000000..551e9e8515 --- /dev/null +++ b/x/ibc/07-tendermint/types/upgrade_test.go @@ -0,0 +1,276 @@ +package types_test + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + "github.com/cosmos/cosmos-sdk/x/ibc/exported" + solomachinetypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/solomachine/types" + ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing" + + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" +) + +func (suite *TendermintTestSuite) TestVerifyUpgrade() { + var ( + upgradedClient exported.ClientState + clientA string + proofUpgrade []byte + ) + + testCases := []struct { + name string + setup func() + expPass bool + }{ + { + name: "successful upgrade to a new tendermint client", + setup: func() { + + upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, upgradeHeight, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) + // zero custom fields and store in upgrade store + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), upgradedClient) + + // commit upgrade store changes and update clients + + suite.coordinator.CommitBlock(suite.chainB) + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, ibctesting.Tendermint) + suite.Require().NoError(err) + + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight()) + }, + expPass: true, + }, + { + name: "successful upgrade to a new tendermint client with different client chosen parameters", + setup: func() { + + upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, upgradeHeight, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) + // zero custom fields and store in upgrade store + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), upgradedClient) + + // change upgradedClient client-specified parameters + upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, ubdPeriod, ubdPeriod+trustingPeriod, maxClockDrift+5, upgradeHeight, commitmenttypes.GetSDKSpecs(), &upgradePath, true, true) + + suite.coordinator.CommitBlock(suite.chainB) + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, ibctesting.Tendermint) + suite.Require().NoError(err) + + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight()) + }, + expPass: true, + }, + { + name: "successful upgrade to a solomachine client", + setup: func() { + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + // demonstrate that VerifyUpgrade allows for arbitrary changes to clienstate structure so long as + // previous chain committed to the change + upgradedClient = ibctesting.NewSolomachine(suite.T(), suite.cdc, clientA, "diversifier", 1).ClientState() + soloClient, _ := upgradedClient.(*solomachinetypes.ClientState) + // change sequence to be higher height than latest current client height + soloClient.Sequence = cs.GetLatestHeight().GetEpochHeight() + 100 + // zero custom fields and store in upgrade store + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), upgradedClient) + + suite.coordinator.CommitBlock(suite.chainB) + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, ibctesting.Tendermint) + suite.Require().NoError(err) + + cs, found = suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight()) + }, + expPass: true, + }, + { + name: "successful upgrade to a solomachine client with different client-chosen parameters", + setup: func() { + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + // demonstrate that VerifyUpgrade allows for arbitrary changes to clienstate structure so long as + // previous chain committed to the change + upgradedClient = ibctesting.NewSolomachine(suite.T(), suite.cdc, clientA, "diversifier", 1).ClientState() + soloClient, _ := upgradedClient.(*solomachinetypes.ClientState) + // change sequence to be higher height than latest current client height + soloClient.Sequence = cs.GetLatestHeight().GetEpochHeight() + 100 + // zero custom fields and store in upgrade store + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), soloClient) + + // change client-specified parameter + soloClient.AllowUpdateAfterProposal = true + + suite.coordinator.CommitBlock(suite.chainB) + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, ibctesting.Tendermint) + suite.Require().NoError(err) + + cs, found = suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight()) + }, + expPass: true, + }, + { + name: "unsuccessful upgrade to a new tendermint client: chain-specified paramaters do not match committed client", + setup: func() { + + upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, upgradeHeight, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) + // zero custom fields and store in upgrade store + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), upgradedClient) + + // change upgradedClient client-specified parameters + upgradedClient = types.NewClientState("wrongchainID", types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, upgradeHeight, commitmenttypes.GetSDKSpecs(), &upgradePath, true, true) + + suite.coordinator.CommitBlock(suite.chainB) + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, ibctesting.Tendermint) + suite.Require().NoError(err) + + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight()) + }, + expPass: false, + }, + { + + name: "unsuccessful upgrade to a new solomachine client: chain-specified paramaters do not match committed client", + setup: func() { + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + // demonstrate that VerifyUpgrade allows for arbitrary changes to clienstate structure so long as + // previous chain committed to the change + upgradedClient = ibctesting.NewSolomachine(suite.T(), suite.cdc, clientA, "diversifier", 1).ClientState() + soloClient, _ := upgradedClient.(*solomachinetypes.ClientState) + // change sequence to be higher height than latest current client height + soloClient.Sequence = cs.GetLatestHeight().GetEpochHeight() + 100 + // zero custom fields and store in upgrade store + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), upgradedClient) + + // change chain-specified parameters from committed values + soloClient.Sequence = 10000 + + suite.coordinator.CommitBlock(suite.chainB) + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, ibctesting.Tendermint) + suite.Require().NoError(err) + + cs, found = suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight()) + }, + expPass: false, + }, + { + name: "unsuccessful upgrade to a new tendermint client: proof is empty", + setup: func() { + upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, upgradeHeight, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) + proofUpgrade = []byte{} + }, + expPass: false, + }, + { + name: "unsuccessful upgrade to a new tendermint client: proof unmarshal failed", + setup: func() { + upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, upgradeHeight, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) + proofUpgrade = []byte("proof") + }, + expPass: false, + }, + { + name: "unsuccessful upgrade to a new tendermint client: proof verification failed", + setup: func() { + // create but do not store upgraded client + upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, upgradeHeight, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) + + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight()) + }, + expPass: false, + }, + { + name: "unsuccessful upgrade to a new tendermint client: upgrade path is nil", + setup: func() { + + upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, upgradeHeight, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) + // zero custom fields and store in upgrade store + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), upgradedClient) + + // commit upgrade store changes and update clients + + suite.coordinator.CommitBlock(suite.chainB) + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, ibctesting.Tendermint) + suite.Require().NoError(err) + + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight()) + + // SetClientState with nil upgrade path + tmClient, _ := cs.(*types.ClientState) + tmClient.UpgradePath = nil + suite.chainA.App.IBCKeeper.ClientKeeper.SetClientState(suite.chainA.GetContext(), clientA, tmClient) + }, + expPass: false, + }, + { + name: "unsuccessful upgrade to a new tendermint client: upgraded height is not greater than current height", + setup: func() { + + upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false) + // zero custom fields and store in upgrade store + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), upgradedClient) + + // commit upgrade store changes and update clients + + suite.coordinator.CommitBlock(suite.chainB) + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, ibctesting.Tendermint) + suite.Require().NoError(err) + + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight()) + }, + expPass: false, + }, + } + + for _, tc := range testCases { + tc := tc + clientA, _ = suite.coordinator.SetupClients(suite.chainA, suite.chainB, ibctesting.Tendermint) + + tc.setup() + + cs := suite.chainA.GetClientState(clientA) + clientStore := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA) + + err := cs.VerifyUpgrade( + suite.chainA.GetContext(), + suite.cdc, + clientStore, + upgradedClient, + proofUpgrade, + ) + + if tc.expPass { + suite.Require().NoError(err, "verify upgrade failed on valid case: %s", tc.name) + } else { + suite.Require().Error(err, "verify upgrade passed on invalid case: %s", tc.name) + } + } +} diff --git a/x/ibc/09-localhost/types/client_state.go b/x/ibc/09-localhost/types/client_state.go index 774f762e4e..22d2ee0a65 100644 --- a/x/ibc/09-localhost/types/client_state.go +++ b/x/ibc/09-localhost/types/client_state.go @@ -69,6 +69,11 @@ func (cs ClientState) GetProofSpecs() []*ics23.ProofSpec { return nil } +// ZeroCustomFields returns the same client state since there are no custom fields in localhost +func (cs ClientState) ZeroCustomFields() exported.ClientState { + return &cs +} + // CheckHeaderAndUpdateState updates the localhost client. It only needs access to the context func (cs *ClientState) CheckHeaderAndUpdateState( ctx sdk.Context, _ codec.BinaryMarshaler, _ sdk.KVStore, _ exported.Header, @@ -97,6 +102,14 @@ func (cs ClientState) CheckProposedHeaderAndUpdateState( return nil, nil, sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "cannot update localhost client with a proposal") } +// VerifyUpgrade returns an error since localhost cannot be upgraded +func (cs ClientState) VerifyUpgrade( + _ sdk.Context, _ codec.BinaryMarshaler, _ sdk.KVStore, + _ exported.ClientState, _ []byte, +) error { + return sdkerrors.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade localhost client") +} + // VerifyClientState verifies that the localhost client state is stored locally func (cs ClientState) VerifyClientState( store sdk.KVStore, cdc codec.BinaryMarshaler, _ exported.Root, diff --git a/x/ibc/23-commitment/types/commitment.pb.go b/x/ibc/23-commitment/types/commitment.pb.go index e79a3d7eb9..09e5173cea 100644 --- a/x/ibc/23-commitment/types/commitment.pb.go +++ b/x/ibc/23-commitment/types/commitment.pb.go @@ -44,6 +44,10 @@ var KeyEncoding_value = map[string]int32{ "KEY_ENCODING_HEX": 1, } +func (x KeyEncoding) String() string { + return proto.EnumName(KeyEncoding_name, int32(x)) +} + func (KeyEncoding) EnumDescriptor() ([]byte, []int) { return fileDescriptor_71f36b3839a24c54, []int{0} } @@ -266,8 +270,8 @@ var xxx_messageInfo_KeyPath proto.InternalMessageInfo // Key defines a proof Key type Key struct { - name []byte `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - enc KeyEncoding `protobuf:"varint,2,opt,name=enc,proto3,enum=ibc.commitment.KeyEncoding" json:"enc,omitempty"` + Name []byte `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Enc KeyEncoding `protobuf:"varint,2,opt,name=enc,proto3,enum=ibc.commitment.KeyEncoding" json:"enc,omitempty"` } func (m *Key) Reset() { *m = Key{} } @@ -316,39 +320,38 @@ func init() { func init() { proto.RegisterFile("ibc/commitment/commitment.proto", fileDescriptor_71f36b3839a24c54) } var fileDescriptor_71f36b3839a24c54 = []byte{ - // 506 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x92, 0xc1, 0x6e, 0xd3, 0x4c, - 0x10, 0xc7, 0xed, 0x2f, 0xfe, 0x48, 0xd8, 0x54, 0x25, 0x2c, 0xa0, 0x46, 0x69, 0x6b, 0x47, 0x3e, - 0x40, 0x40, 0xaa, 0x2d, 0x52, 0xd4, 0x43, 0xc4, 0x01, 0xa5, 0x31, 0x34, 0x4a, 0x49, 0xa3, 0x45, - 0x91, 0x0a, 0x17, 0xcb, 0x71, 0x36, 0xb1, 0xe5, 0xda, 0x6b, 0xd9, 0x8b, 0x54, 0xbf, 0x41, 0xc5, - 0x89, 0x23, 0x17, 0x24, 0x24, 0x38, 0xf0, 0x28, 0x3d, 0xf6, 0xc8, 0xc9, 0x42, 0xce, 0x1b, 0xf4, - 0x09, 0xd0, 0xee, 0xa6, 0x4a, 0x2a, 0xf5, 0xb2, 0x9e, 0xf5, 0xfc, 0x3c, 0xf3, 0x9f, 0xbf, 0x07, - 0x68, 0xfe, 0xc4, 0x35, 0x5d, 0x12, 0x86, 0x3e, 0x0d, 0x71, 0x44, 0xd7, 0x42, 0x23, 0x4e, 0x08, - 0x25, 0x70, 0xd3, 0x9f, 0xb8, 0xc6, 0xea, 0x6d, 0xe3, 0xf1, 0x9c, 0xcc, 0x09, 0x4f, 0x99, 0x2c, - 0x12, 0x54, 0x63, 0x97, 0xe2, 0x68, 0x8a, 0x93, 0xd0, 0x67, 0x25, 0x92, 0x2c, 0xa6, 0xc4, 0x8c, - 0x13, 0x42, 0x66, 0x22, 0xad, 0x3f, 0x05, 0xe0, 0x3d, 0x4e, 0x82, 0x33, 0x8c, 0x08, 0xa1, 0x10, - 0x02, 0xc5, 0x73, 0x52, 0xaf, 0x2e, 0x37, 0xe5, 0xd6, 0x06, 0xe2, 0x71, 0x47, 0xb9, 0xf8, 0xa1, - 0x49, 0x7a, 0x0f, 0x6c, 0x08, 0x6e, 0x94, 0xe0, 0x99, 0x7f, 0x0e, 0x5f, 0x01, 0x10, 0xe0, 0xcc, - 0x8e, 0xf9, 0x4d, 0xf0, 0xdd, 0x27, 0xd7, 0xb9, 0xf6, 0x30, 0x73, 0xc2, 0xb3, 0x8e, 0xbe, 0xca, - 0xe9, 0xe8, 0x7e, 0x80, 0x33, 0xf1, 0x95, 0x6e, 0xdf, 0x74, 0x1b, 0x39, 0xd4, 0x83, 0x03, 0x50, - 0xe1, 0x9c, 0x43, 0x45, 0xc7, 0x6a, 0x7b, 0xcb, 0xb8, 0x3d, 0x93, 0x31, 0xc0, 0x19, 0x43, 0xbb, - 0x5b, 0x97, 0xb9, 0x26, 0x5d, 0xe7, 0xda, 0x83, 0xb5, 0xf2, 0x0e, 0xf5, 0x74, 0x54, 0x0e, 0x04, - 0xd1, 0x51, 0xbe, 0x31, 0x99, 0x6f, 0x40, 0xf5, 0x46, 0x26, 0x21, 0x33, 0xf8, 0x12, 0xfc, 0xcf, - 0x87, 0x5d, 0x96, 0xdf, 0x36, 0x56, 0x66, 0x18, 0xc2, 0x0c, 0x83, 0x83, 0x27, 0x71, 0x8a, 0x04, - 0xa9, 0xbf, 0x06, 0xe5, 0x65, 0x53, 0xf8, 0x0c, 0x28, 0x01, 0xce, 0xd2, 0xba, 0xdc, 0x2c, 0xb5, - 0xaa, 0xed, 0x47, 0x77, 0x68, 0x43, 0x1c, 0xe8, 0x54, 0x98, 0x45, 0xbc, 0xbf, 0x03, 0x4a, 0x03, - 0x9c, 0xc1, 0x1d, 0xa0, 0x44, 0x4e, 0x88, 0x97, 0xbe, 0x54, 0x8a, 0x5c, 0xe3, 0x77, 0xc4, 0x4f, - 0x78, 0x00, 0x4a, 0x38, 0x72, 0xeb, 0xff, 0x35, 0xe5, 0xd6, 0x66, 0x7b, 0xfb, 0x8e, 0xb2, 0x56, - 0xe4, 0x92, 0xa9, 0x1f, 0xcd, 0xbb, 0xe5, 0x22, 0xd7, 0x18, 0x8b, 0xd8, 0x21, 0xfe, 0xc4, 0x0b, - 0x07, 0x54, 0xd7, 0x10, 0xf8, 0x1c, 0xec, 0x0c, 0xac, 0x8f, 0xb6, 0x35, 0x3c, 0x3c, 0xe9, 0xf5, - 0x87, 0xef, 0xec, 0x31, 0x3a, 0xb6, 0xc7, 0xc3, 0x0f, 0x23, 0xeb, 0xb0, 0xff, 0xb6, 0x6f, 0xf5, - 0x6a, 0x52, 0xa3, 0xfc, 0xe5, 0x7b, 0xb3, 0x34, 0x46, 0xc7, 0x70, 0x17, 0xd4, 0x6e, 0xa1, 0x47, - 0xd6, 0x69, 0x4d, 0x16, 0xe9, 0x23, 0xeb, 0xb4, 0x51, 0xb9, 0xf8, 0xa9, 0x4a, 0xbf, 0x7f, 0xa9, - 0x52, 0x77, 0x74, 0x59, 0xa8, 0xf2, 0x55, 0xa1, 0xca, 0x7f, 0x0b, 0x55, 0xfe, 0xba, 0x50, 0xa5, - 0xab, 0x85, 0x2a, 0xfd, 0x59, 0xa8, 0xd2, 0xa7, 0x83, 0xb9, 0x4f, 0xbd, 0xcf, 0x13, 0xa6, 0xd7, - 0x74, 0x49, 0x1a, 0x92, 0x74, 0xf9, 0xd8, 0x4b, 0xa7, 0x81, 0x79, 0x6e, 0xb2, 0x9d, 0x6d, 0xef, - 0xef, 0xad, 0xad, 0x2d, 0xcd, 0x62, 0x9c, 0x4e, 0xee, 0xf1, 0x6d, 0xdb, 0xff, 0x17, 0x00, 0x00, - 0xff, 0xff, 0xeb, 0x84, 0x9f, 0x36, 0xd5, 0x02, 0x00, 0x00, + // 486 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x92, 0x51, 0x6b, 0xd3, 0x50, + 0x14, 0xc7, 0x13, 0x1b, 0xed, 0x3c, 0x1d, 0xb3, 0x5e, 0x95, 0x95, 0xce, 0x25, 0x25, 0x0f, 0x5a, + 0x85, 0x26, 0xd8, 0x89, 0x0f, 0xc5, 0x07, 0xe9, 0x1a, 0x5d, 0xe9, 0xec, 0x4a, 0xa4, 0x30, 0x05, + 0x09, 0x69, 0x7a, 0xdb, 0x84, 0x2c, 0xb9, 0x21, 0xb9, 0xc2, 0xf2, 0x0d, 0x86, 0x4f, 0x3e, 0xfa, + 0x22, 0x08, 0x7e, 0x99, 0x3d, 0xee, 0xd1, 0xa7, 0x22, 0xed, 0x37, 0xd8, 0x27, 0x90, 0x7b, 0x6f, + 0x4b, 0x3b, 0xd8, 0x53, 0x4e, 0xf2, 0xff, 0xe5, 0x9c, 0xff, 0xf9, 0x73, 0x40, 0x0b, 0x46, 0x9e, + 0xe9, 0x91, 0x28, 0x0a, 0x68, 0x84, 0x63, 0xba, 0x51, 0x1a, 0x49, 0x4a, 0x28, 0x41, 0x3b, 0xc1, + 0xc8, 0x33, 0xd6, 0x5f, 0xab, 0x8f, 0xa7, 0x64, 0x4a, 0xb8, 0x64, 0xb2, 0x4a, 0x50, 0xd5, 0x7d, + 0x8a, 0xe3, 0x31, 0x4e, 0xa3, 0x80, 0xb5, 0x48, 0xf3, 0x84, 0x12, 0x33, 0x49, 0x09, 0x99, 0x08, + 0x59, 0x7f, 0x06, 0xf0, 0x11, 0xa7, 0xe1, 0x19, 0xb6, 0x09, 0xa1, 0x08, 0x81, 0xe2, 0xbb, 0x99, + 0x5f, 0x91, 0x6b, 0x72, 0x7d, 0xdb, 0xe6, 0x75, 0x4b, 0xb9, 0xf8, 0xad, 0x49, 0x7a, 0x07, 0xb6, + 0x05, 0x37, 0x48, 0xf1, 0x24, 0x38, 0x47, 0xaf, 0x01, 0x42, 0x9c, 0x3b, 0x09, 0x7f, 0x13, 0x7c, + 0xfb, 0xc9, 0xf5, 0x4c, 0x7b, 0x98, 0xbb, 0xd1, 0x59, 0x4b, 0x5f, 0x6b, 0xba, 0x7d, 0x3f, 0xc4, + 0xb9, 0xf8, 0x4b, 0x77, 0x56, 0xd3, 0x06, 0x2e, 0xf5, 0x51, 0x0f, 0xb6, 0x38, 0xe7, 0x52, 0x31, + 0xb1, 0xd4, 0xdc, 0x35, 0x6e, 0xee, 0x64, 0xf4, 0x70, 0xce, 0xd0, 0xf6, 0xee, 0xe5, 0x4c, 0x93, + 0xae, 0x67, 0xda, 0x83, 0x8d, 0xf6, 0x2e, 0xf5, 0x75, 0xbb, 0x18, 0x0a, 0xa2, 0xa5, 0xfc, 0x64, + 0x36, 0xdf, 0x41, 0x69, 0x65, 0x93, 0x90, 0x09, 0x7a, 0x05, 0x77, 0xf9, 0xb2, 0xcb, 0xf6, 0x7b, + 0xc6, 0x3a, 0x0c, 0x43, 0x84, 0x61, 0x70, 0xf0, 0x24, 0xc9, 0x6c, 0x41, 0xea, 0x6f, 0xa1, 0xb8, + 0x1c, 0x8a, 0x9e, 0x83, 0x12, 0xe2, 0x3c, 0xab, 0xc8, 0xb5, 0x42, 0xbd, 0xd4, 0x7c, 0x74, 0x8b, + 0x37, 0x9b, 0x03, 0xad, 0x2d, 0x16, 0x11, 0x9f, 0xdf, 0x87, 0x42, 0x0f, 0xe7, 0x2c, 0xc7, 0xd8, + 0x8d, 0xf0, 0x2a, 0x47, 0x56, 0xa3, 0x06, 0x14, 0x70, 0xec, 0x55, 0xee, 0xd4, 0xe4, 0xfa, 0x4e, + 0x73, 0xef, 0x96, 0x66, 0x56, 0xec, 0x91, 0x71, 0x10, 0x4f, 0x6d, 0xc6, 0x89, 0xd8, 0x5f, 0x7e, + 0x85, 0xd2, 0x86, 0x82, 0x5e, 0xc0, 0xd3, 0x9e, 0xf5, 0xd9, 0xb1, 0xfa, 0x87, 0x27, 0x9d, 0x6e, + 0xff, 0x83, 0x33, 0xb4, 0x8f, 0x9d, 0x61, 0xff, 0xd3, 0xc0, 0x3a, 0xec, 0xbe, 0xef, 0x5a, 0x9d, + 0xb2, 0x54, 0x2d, 0x7e, 0xff, 0x55, 0x2b, 0x0c, 0xed, 0x63, 0xb4, 0x0f, 0xe5, 0x1b, 0xe8, 0x91, + 0x75, 0x5a, 0x96, 0x85, 0x7c, 0x64, 0x9d, 0x56, 0x95, 0x8b, 0x3f, 0xaa, 0xd4, 0x1e, 0x5c, 0xce, + 0x55, 0xf9, 0x6a, 0xae, 0xca, 0xff, 0xe6, 0xaa, 0xfc, 0x63, 0xa1, 0x4a, 0x57, 0x0b, 0x55, 0xfa, + 0xbb, 0x50, 0xa5, 0x2f, 0x6f, 0xa6, 0x01, 0xf5, 0xbf, 0x8d, 0x98, 0x45, 0xd3, 0x23, 0x59, 0x44, + 0xb2, 0xe5, 0xa3, 0x91, 0x8d, 0x43, 0xf3, 0xdc, 0x64, 0xc7, 0xd9, 0x3c, 0x68, 0x6c, 0xdc, 0x27, + 0xcd, 0x13, 0x9c, 0x8d, 0xee, 0xf1, 0xb3, 0x3a, 0xf8, 0x1f, 0x00, 0x00, 0xff, 0xff, 0xf2, 0xfd, + 0xcd, 0x54, 0xbe, 0x02, 0x00, 0x00, } func (m *MerkleRoot) Marshal() (dAtA []byte, err error) { @@ -536,15 +539,15 @@ func (m *Key) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.enc != 0 { - i = encodeVarintCommitment(dAtA, i, uint64(m.enc)) + if m.Enc != 0 { + i = encodeVarintCommitment(dAtA, i, uint64(m.Enc)) i-- dAtA[i] = 0x10 } - if len(m.name) > 0 { - i -= len(m.name) - copy(dAtA[i:], m.name) - i = encodeVarintCommitment(dAtA, i, uint64(len(m.name))) + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintCommitment(dAtA, i, uint64(len(m.Name))) i-- dAtA[i] = 0xa } @@ -633,12 +636,12 @@ func (m *Key) Size() (n int) { } var l int _ = l - l = len(m.name) + l = len(m.Name) if l > 0 { n += 1 + l + sovCommitment(uint64(l)) } - if m.enc != 0 { - n += 1 + sovCommitment(uint64(m.enc)) + if m.Enc != 0 { + n += 1 + sovCommitment(uint64(m.Enc)) } return n } @@ -1116,7 +1119,7 @@ func (m *Key) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field name", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -1143,16 +1146,16 @@ func (m *Key) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.name = append(m.name[:0], dAtA[iNdEx:postIndex]...) - if m.name == nil { - m.name = []byte{} + m.Name = append(m.Name[:0], dAtA[iNdEx:postIndex]...) + if m.Name == nil { + m.Name = []byte{} } iNdEx = postIndex case 2: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field enc", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Enc", wireType) } - m.enc = 0 + m.Enc = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowCommitment @@ -1162,7 +1165,7 @@ func (m *Key) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.enc |= KeyEncoding(b&0x7F) << shift + m.Enc |= KeyEncoding(b&0x7F) << shift if b < 0x80 { break } diff --git a/x/ibc/23-commitment/types/key_path.go b/x/ibc/23-commitment/types/key_path.go index 2dc4c47c5b..589406b901 100644 --- a/x/ibc/23-commitment/types/key_path.go +++ b/x/ibc/23-commitment/types/key_path.go @@ -7,7 +7,7 @@ import ( // AppendKey appends a new key to a KeyPath func (pth KeyPath) AppendKey(key []byte, enc KeyEncoding) KeyPath { - pth.Keys = append(pth.Keys, &Key{name: key, enc: enc}) + pth.Keys = append(pth.Keys, &Key{Name: key, Enc: enc}) return pth } @@ -15,11 +15,11 @@ func (pth KeyPath) AppendKey(key []byte, enc KeyEncoding) KeyPath { func (pth *KeyPath) String() string { res := "" for _, key := range pth.Keys { - switch key.enc { + switch key.Enc { case URL: - res += "/" + url.PathEscape(string(key.name)) + res += "/" + url.PathEscape(string(key.Name)) case HEX: - res += "/x:" + fmt.Sprintf("%X", key.name) + res += "/x:" + fmt.Sprintf("%X", key.Name) default: panic("unexpected key encoding type") } @@ -36,5 +36,5 @@ func (pth *KeyPath) String() string { func (pth *KeyPath) GetKey(i int) []byte { total := len(pth.Keys) index := (total + i) % total - return pth.Keys[index].name + return pth.Keys[index].Name } diff --git a/x/ibc/23-commitment/types/merkle.go b/x/ibc/23-commitment/types/merkle.go index 44028cf012..c0a1d3e5d9 100644 --- a/x/ibc/23-commitment/types/merkle.go +++ b/x/ibc/23-commitment/types/merkle.go @@ -126,7 +126,7 @@ func (proof MerkleProof) VerifyMembership(specs []*ics23.ProofSpec, root exporte // VerifyMembership specific argument validation mpath, ok := path.(MerklePath) if !ok { - return sdkerrors.Wrapf(ErrInvalidProof, "path %v is not of type MerkleProof", path) + return sdkerrors.Wrapf(ErrInvalidProof, "path %v is not of type MerklePath", path) } if len(mpath.KeyPath.Keys) != len(specs) { return sdkerrors.Wrapf(ErrInvalidProof, "path length %d not same as proof %d", diff --git a/x/ibc/exported/client.go b/x/ibc/exported/client.go index e08fdc4bdd..57839ff34b 100644 --- a/x/ibc/exported/client.go +++ b/x/ibc/exported/client.go @@ -32,6 +32,19 @@ type ClientState interface { CheckMisbehaviourAndUpdateState(sdk.Context, codec.BinaryMarshaler, sdk.KVStore, Misbehaviour) (ClientState, error) CheckProposedHeaderAndUpdateState(sdk.Context, codec.BinaryMarshaler, sdk.KVStore, Header) (ClientState, ConsensusState, error) + // Upgrade functions + VerifyUpgrade( + ctx sdk.Context, + cdc codec.BinaryMarshaler, + store sdk.KVStore, + newClient ClientState, + proofUpgrade []byte, + ) error + // Utility function that zeroes out any client customizable fields in client state + // Ledger enforced fields are maintained while all custom fields are zero values + // Used to verify upgrades + ZeroCustomFields() ClientState + // State verification functions VerifyClientState( diff --git a/x/ibc/genesis_test.go b/x/ibc/genesis_test.go index f12b37d6c7..742be0f734 100644 --- a/x/ibc/genesis_test.go +++ b/x/ibc/genesis_test.go @@ -37,7 +37,7 @@ func (suite *IBCTestSuite) TestValidateGenesis() { ClientGenesis: clienttypes.NewGenesisState( []clienttypes.IdentifiedClientState{ clienttypes.NewIdentifiedClientState( - clientID, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), false, false), + clientID, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), ), clienttypes.NewIdentifiedClientState( exported.Localhost, localhosttypes.NewClientState("chaindID", clientHeight), @@ -100,7 +100,7 @@ func (suite *IBCTestSuite) TestValidateGenesis() { ClientGenesis: clienttypes.NewGenesisState( []clienttypes.IdentifiedClientState{ clienttypes.NewIdentifiedClientState( - clientID, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), false, false), + clientID, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), ), clienttypes.NewIdentifiedClientState( exported.Localhost, localhosttypes.NewClientState("(chaindID)", clienttypes.ZeroHeight()), @@ -169,7 +169,7 @@ func (suite *IBCTestSuite) TestInitGenesis() { ClientGenesis: clienttypes.NewGenesisState( []clienttypes.IdentifiedClientState{ clienttypes.NewIdentifiedClientState( - clientID, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), false, false), + clientID, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), &ibctesting.UpgradePath, false, false), ), clienttypes.NewIdentifiedClientState( exported.Localhost, localhosttypes.NewClientState("chaindID", clientHeight), diff --git a/x/ibc/light-clients/solomachine/types/client_state.go b/x/ibc/light-clients/solomachine/types/client_state.go index f18bd3bd81..b54920c388 100644 --- a/x/ibc/light-clients/solomachine/types/client_state.go +++ b/x/ibc/light-clients/solomachine/types/client_state.go @@ -68,6 +68,22 @@ func (cs ClientState) Validate() error { return cs.ConsensusState.ValidateBasic() } +// ZeroCustomFields returns solomachine client state with client-specific fields FrozenSequence, +// and AllowUpdateAfterProposal zeroed out +func (cs ClientState) ZeroCustomFields() exported.ClientState { + return NewClientState( + cs.Sequence, cs.ConsensusState, false, + ) +} + +// VerifyUpgrade returns an error since solomachine client does not support upgrades +func (cs ClientState) VerifyUpgrade( + _ sdk.Context, _ codec.BinaryMarshaler, _ sdk.KVStore, + _ exported.ClientState, _ []byte, +) error { + return sdkerrors.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade solomachine client") +} + // VerifyClientState verifies a proof of the client state of the running chain // stored on the solo machine. func (cs ClientState) VerifyClientState( diff --git a/x/ibc/testing/chain.go b/x/ibc/testing/chain.go index e7e80d04c9..5a6a824818 100644 --- a/x/ibc/testing/chain.go +++ b/x/ibc/testing/chain.go @@ -37,6 +37,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/testing/mock" "github.com/cosmos/cosmos-sdk/x/ibc/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) const ( @@ -69,6 +70,8 @@ var ( TestHash = tmhash.Sum([]byte("TESTING HASH")) TestCoin = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) + UpgradePath = commitmenttypes.NewMerklePath([]string{"upgrade", upgradetypes.KeyUpgradedClient}) + ConnectionVersion = connectiontypes.GetCompatibleEncodedVersions()[0] MockAcknowledgement = mock.MockAcknowledgement @@ -196,6 +199,31 @@ func (chain *TestChain) QueryProof(key []byte) ([]byte, clienttypes.Height) { return proof, clienttypes.NewHeight(epoch, uint64(res.Height)+1) } +// QueryUpgradeProof performs an abci query with the given key and returns the proto encoded merkle proof +// for the query and the height at which the proof will succeed on a tendermint verifier. +func (chain *TestChain) QueryUpgradeProof(key []byte, height uint64) ([]byte, clienttypes.Height) { + res := chain.App.Query(abci.RequestQuery{ + Path: "store/upgrade/key", + Height: int64(height - 1), + Data: upgradetypes.UpgradedClientKey(), + Prove: true, + }) + + merkleProof := commitmenttypes.MerkleProof{ + Proof: res.ProofOps, + } + + proof, err := chain.App.AppCodec().MarshalBinaryBare(&merkleProof) + require.NoError(chain.t, err) + + epoch := clienttypes.ParseChainID(chain.ChainID) + + // proof height + 1 is returned as the proof created corresponds to the height the proof + // was created in the IAVL tree. Tendermint and subsequently the clients that rely on it + // have heights 1 above the IAVL tree. Thus we return proof height + 1 + return proof, clienttypes.NewHeight(epoch, uint64(res.Height+1)) +} + // QueryClientStateProof performs and abci query for a client state // stored with a given clientID and returns the ClientState along with the proof func (chain *TestChain) QueryClientStateProof(clientID string) (exported.ClientState, []byte) { @@ -392,7 +420,7 @@ func (chain *TestChain) ConstructMsgCreateClient(counterparty *TestChain, client clientState = ibctmtypes.NewClientState( counterparty.ChainID, DefaultTrustLevel, TrustingPeriod, UnbondingPeriod, MaxClockDrift, height, commitmenttypes.GetSDKSpecs(), - false, false, + &UpgradePath, false, false, ) consensusState = counterparty.LastHeader.ConsensusState() case SoloMachine: diff --git a/x/staking/types/staking.pb.go b/x/staking/types/staking.pb.go index c1108cab32..9951a81740 100644 --- a/x/staking/types/staking.pb.go +++ b/x/staking/types/staking.pb.go @@ -1167,582 +1167,584 @@ func (this *Pool) Description() (desc *github_com_gogo_protobuf_protoc_gen_gogo_ func StakingDescription() (desc *github_com_gogo_protobuf_protoc_gen_gogo_descriptor.FileDescriptorSet) { d := &github_com_gogo_protobuf_protoc_gen_gogo_descriptor.FileDescriptorSet{} var gzipped = []byte{ - // 9197 bytes of a gzipped FileDescriptorSet + // 9223 bytes of a gzipped FileDescriptorSet 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x6d, 0x74, 0x1c, 0xd7, - 0x75, 0x18, 0x67, 0x3f, 0x80, 0xdd, 0xbb, 0x0b, 0x60, 0xf1, 0x00, 0x42, 0xcb, 0x25, 0x09, 0x40, - 0x23, 0x59, 0xa2, 0x28, 0x09, 0x90, 0x28, 0x92, 0x22, 0x97, 0xb1, 0x64, 0x2c, 0xb0, 0x04, 0x41, - 0xe2, 0x4b, 0x03, 0x90, 0xf2, 0x47, 0xd2, 0x3d, 0x83, 0xdd, 0x87, 0xc5, 0x88, 0xbb, 0x33, 0xe3, - 0x99, 0x59, 0x12, 0x90, 0xed, 0x73, 0x94, 0xd8, 0x75, 0x6d, 0xa5, 0xa9, 0xed, 0x38, 0x27, 0xf5, - 0x97, 0x5c, 0x39, 0x4e, 0xeb, 0xd4, 0x49, 0x9b, 0x0f, 0xa7, 0x69, 0xd3, 0xf6, 0x9c, 0x3a, 0x3d, - 0x4d, 0xe3, 0xb4, 0xa7, 0x39, 0xd2, 0x69, 0xce, 0x69, 0x9a, 0xd3, 0x30, 0xa9, 0xac, 0xa6, 0xaa, - 0xeb, 0xb6, 0x0e, 0xab, 0xa6, 0x69, 0xfd, 0xa3, 0x3d, 0xef, 0x6b, 0xbe, 0x76, 0x17, 0xb3, 0x0b, - 0x91, 0x92, 0xd3, 0xf4, 0x17, 0xf6, 0xdd, 0x77, 0xef, 0x7d, 0xf7, 0xde, 0x77, 0xef, 0x7d, 0xf7, - 0xbd, 0x79, 0x33, 0x80, 0x2f, 0x5e, 0x80, 0xe9, 0xba, 0x61, 0xd4, 0x1b, 0x78, 0xd6, 0xb4, 0x0c, - 0xc7, 0xd8, 0x6a, 0x6d, 0xcf, 0xd6, 0xb0, 0x5d, 0xb5, 0x34, 0xd3, 0x31, 0xac, 0x19, 0x0a, 0x43, - 0x23, 0x0c, 0x63, 0x46, 0x60, 0xc8, 0x2b, 0x30, 0x7a, 0x51, 0x6b, 0xe0, 0x05, 0x17, 0x71, 0x03, - 0x3b, 0xe8, 0x1c, 0x24, 0xb6, 0xb5, 0x06, 0xce, 0x4b, 0xd3, 0xf1, 0x13, 0x99, 0x53, 0xf7, 0xcf, - 0x84, 0x88, 0x66, 0x82, 0x14, 0xeb, 0x04, 0xac, 0x50, 0x0a, 0xf9, 0xf5, 0x04, 0x8c, 0x75, 0xe8, - 0x45, 0x08, 0x12, 0xba, 0xda, 0x24, 0x1c, 0xa5, 0x13, 0x69, 0x85, 0xfe, 0x46, 0x79, 0x18, 0x34, - 0xd5, 0xea, 0x75, 0xb5, 0x8e, 0xf3, 0x31, 0x0a, 0x16, 0x4d, 0x34, 0x09, 0x50, 0xc3, 0x26, 0xd6, - 0x6b, 0x58, 0xaf, 0xee, 0xe5, 0xe3, 0xd3, 0xf1, 0x13, 0x69, 0xc5, 0x07, 0x41, 0x0f, 0xc3, 0xa8, - 0xd9, 0xda, 0x6a, 0x68, 0xd5, 0x8a, 0x0f, 0x0d, 0xa6, 0xe3, 0x27, 0x92, 0x4a, 0x8e, 0x75, 0x2c, - 0x78, 0xc8, 0x0f, 0xc2, 0xc8, 0x4d, 0xac, 0x5e, 0xf7, 0xa3, 0x66, 0x28, 0xea, 0x30, 0x01, 0xfb, - 0x10, 0xe7, 0x21, 0xdb, 0xc4, 0xb6, 0xad, 0xd6, 0x71, 0xc5, 0xd9, 0x33, 0x71, 0x3e, 0x41, 0xb5, - 0x9f, 0x6e, 0xd3, 0x3e, 0xac, 0x79, 0x86, 0x53, 0x6d, 0xee, 0x99, 0x18, 0xcd, 0x41, 0x1a, 0xeb, + 0x75, 0x18, 0x67, 0x3f, 0x80, 0xdd, 0xbb, 0xf8, 0x58, 0x3c, 0x80, 0xd0, 0x72, 0x49, 0x02, 0xd0, + 0x48, 0x96, 0x28, 0x4a, 0x5a, 0x48, 0x14, 0x49, 0x91, 0xcb, 0x58, 0x32, 0x16, 0x58, 0x82, 0x20, + 0xf1, 0xa5, 0x01, 0x48, 0xf9, 0x23, 0xe9, 0x9e, 0xc1, 0xee, 0xc3, 0x62, 0xc4, 0xdd, 0x99, 0xf1, + 0xcc, 0x2c, 0x09, 0xc8, 0xf6, 0x39, 0x4a, 0xec, 0xba, 0xb6, 0xd2, 0xd4, 0x76, 0x9d, 0x93, 0xda, + 0x8e, 0xe5, 0xca, 0x71, 0x5a, 0xa7, 0x4e, 0xda, 0x7c, 0x38, 0x4d, 0x9b, 0xb6, 0xe7, 0xd4, 0x6e, + 0x9b, 0xc6, 0x69, 0x4f, 0x73, 0xa4, 0xd3, 0x9c, 0xd3, 0x34, 0xa7, 0x61, 0x52, 0x59, 0x4d, 0x55, + 0xd7, 0x6d, 0x1d, 0x56, 0x4d, 0xd3, 0xfa, 0x47, 0x7b, 0xde, 0xd7, 0x7c, 0xed, 0x2e, 0x66, 0x17, + 0x22, 0x25, 0xa7, 0xe9, 0x2f, 0xec, 0xbb, 0xef, 0xde, 0xfb, 0xee, 0xbd, 0xef, 0xde, 0xfb, 0xee, + 0x7b, 0xf3, 0x66, 0x00, 0xff, 0xf4, 0x02, 0xcc, 0xd4, 0x0d, 0xa3, 0xde, 0xc0, 0xb3, 0xa6, 0x65, + 0x38, 0xc6, 0x56, 0x6b, 0x7b, 0xb6, 0x86, 0xed, 0xaa, 0xa5, 0x99, 0x8e, 0x61, 0x15, 0x28, 0x0c, + 0x8d, 0x32, 0x8c, 0x82, 0xc0, 0x90, 0x57, 0x60, 0xec, 0xa2, 0xd6, 0xc0, 0x0b, 0x2e, 0xe2, 0x06, + 0x76, 0xd0, 0x39, 0x48, 0x6c, 0x6b, 0x0d, 0x9c, 0x93, 0x66, 0xe2, 0x27, 0x32, 0xa7, 0xee, 0x2f, + 0x84, 0x88, 0x0a, 0x41, 0x8a, 0x75, 0x02, 0x56, 0x28, 0x85, 0xfc, 0x7a, 0x02, 0xc6, 0x3b, 0xf4, + 0x22, 0x04, 0x09, 0x5d, 0x6d, 0x12, 0x8e, 0xd2, 0x89, 0xb4, 0x42, 0x7f, 0xa3, 0x1c, 0x0c, 0x9a, + 0x6a, 0xf5, 0xba, 0x5a, 0xc7, 0xb9, 0x18, 0x05, 0x8b, 0x26, 0x9a, 0x02, 0xa8, 0x61, 0x13, 0xeb, + 0x35, 0xac, 0x57, 0xf7, 0x72, 0xf1, 0x99, 0xf8, 0x89, 0xb4, 0xe2, 0x83, 0xa0, 0x87, 0x61, 0xcc, + 0x6c, 0x6d, 0x35, 0xb4, 0x6a, 0xc5, 0x87, 0x06, 0x33, 0xf1, 0x13, 0x49, 0x25, 0xcb, 0x3a, 0x16, + 0x3c, 0xe4, 0x07, 0x61, 0xf4, 0x26, 0x56, 0xaf, 0xfb, 0x51, 0x33, 0x14, 0x75, 0x84, 0x80, 0x7d, + 0x88, 0xf3, 0x30, 0xd4, 0xc4, 0xb6, 0xad, 0xd6, 0x71, 0xc5, 0xd9, 0x33, 0x71, 0x2e, 0x41, 0xb5, + 0x9f, 0x69, 0xd3, 0x3e, 0xac, 0x79, 0x86, 0x53, 0x6d, 0xee, 0x99, 0x18, 0xcd, 0x41, 0x1a, 0xeb, 0xad, 0x26, 0xe3, 0x90, 0xec, 0x62, 0xbf, 0xb2, 0xde, 0x6a, 0x86, 0xb9, 0xa4, 0x08, 0x19, 0x67, - 0x31, 0x68, 0x63, 0xeb, 0x86, 0x56, 0xc5, 0xf9, 0x01, 0xca, 0xe0, 0xc1, 0x36, 0x06, 0x1b, 0xac, - 0x3f, 0xcc, 0x43, 0xd0, 0xa1, 0x79, 0x48, 0xe3, 0x5d, 0x07, 0xeb, 0xb6, 0x66, 0xe8, 0xf9, 0x41, + 0x31, 0x68, 0x63, 0xeb, 0x86, 0x56, 0xc5, 0xb9, 0x01, 0xca, 0xe0, 0xc1, 0x36, 0x06, 0x1b, 0xac, + 0x3f, 0xcc, 0x43, 0xd0, 0xa1, 0x79, 0x48, 0xe3, 0x5d, 0x07, 0xeb, 0xb6, 0x66, 0xe8, 0xb9, 0x41, 0xca, 0xe4, 0x5d, 0x1d, 0x66, 0x11, 0x37, 0x6a, 0x61, 0x16, 0x1e, 0x1d, 0x3a, 0x0b, 0x83, 0x86, - 0xe9, 0x68, 0x86, 0x6e, 0xe7, 0x53, 0xd3, 0xd2, 0x89, 0xcc, 0xa9, 0x63, 0x1d, 0x1d, 0x61, 0x8d, - 0xe1, 0x28, 0x02, 0x19, 0x2d, 0x41, 0xce, 0x36, 0x5a, 0x56, 0x15, 0x57, 0xaa, 0x46, 0x0d, 0x57, - 0x34, 0x7d, 0xdb, 0xc8, 0xa7, 0x29, 0x83, 0xa9, 0x76, 0x45, 0x28, 0xe2, 0xbc, 0x51, 0xc3, 0x4b, - 0xfa, 0xb6, 0xa1, 0x0c, 0xdb, 0x81, 0x36, 0x9a, 0x80, 0x01, 0x7b, 0x4f, 0x77, 0xd4, 0xdd, 0x7c, - 0x96, 0x7a, 0x08, 0x6f, 0xc9, 0xbf, 0x3e, 0x00, 0x23, 0xbd, 0xb8, 0xd8, 0x05, 0x48, 0x6e, 0x13, - 0x2d, 0xf3, 0xb1, 0x7e, 0x6c, 0xc0, 0x68, 0x82, 0x46, 0x1c, 0x38, 0xa0, 0x11, 0xe7, 0x20, 0xa3, - 0x63, 0xdb, 0xc1, 0x35, 0xe6, 0x11, 0xf1, 0x1e, 0x7d, 0x0a, 0x18, 0x51, 0xbb, 0x4b, 0x25, 0x0e, - 0xe4, 0x52, 0xef, 0x85, 0x11, 0x57, 0xa4, 0x8a, 0xa5, 0xea, 0x75, 0xe1, 0x9b, 0xb3, 0x51, 0x92, - 0xcc, 0x94, 0x05, 0x9d, 0x42, 0xc8, 0x94, 0x61, 0x1c, 0x68, 0xa3, 0x05, 0x00, 0x43, 0xc7, 0xc6, - 0x76, 0xa5, 0x86, 0xab, 0x8d, 0x7c, 0xaa, 0x8b, 0x95, 0xd6, 0x08, 0x4a, 0x9b, 0x95, 0x0c, 0x06, + 0xe9, 0x68, 0x86, 0x6e, 0xe7, 0x52, 0x33, 0xd2, 0x89, 0xcc, 0xa9, 0x63, 0x1d, 0x1d, 0x61, 0x8d, + 0xe1, 0x28, 0x02, 0x19, 0x2d, 0x41, 0xd6, 0x36, 0x5a, 0x56, 0x15, 0x57, 0xaa, 0x46, 0x0d, 0x57, + 0x34, 0x7d, 0xdb, 0xc8, 0xa5, 0x29, 0x83, 0xe9, 0x76, 0x45, 0x28, 0xe2, 0xbc, 0x51, 0xc3, 0x4b, + 0xfa, 0xb6, 0xa1, 0x8c, 0xd8, 0x81, 0x36, 0x9a, 0x84, 0x01, 0x7b, 0x4f, 0x77, 0xd4, 0xdd, 0xdc, + 0x10, 0xf5, 0x10, 0xde, 0x92, 0x7f, 0x7d, 0x00, 0x46, 0x7b, 0x71, 0xb1, 0x0b, 0x90, 0xdc, 0x26, + 0x5a, 0xe6, 0x62, 0xfd, 0xd8, 0x80, 0xd1, 0x04, 0x8d, 0x38, 0x70, 0x40, 0x23, 0xce, 0x41, 0x46, + 0xc7, 0xb6, 0x83, 0x6b, 0xcc, 0x23, 0xe2, 0x3d, 0xfa, 0x14, 0x30, 0xa2, 0x76, 0x97, 0x4a, 0x1c, + 0xc8, 0xa5, 0xde, 0x0b, 0xa3, 0xae, 0x48, 0x15, 0x4b, 0xd5, 0xeb, 0xc2, 0x37, 0x67, 0xa3, 0x24, + 0x29, 0x94, 0x05, 0x9d, 0x42, 0xc8, 0x94, 0x11, 0x1c, 0x68, 0xa3, 0x05, 0x00, 0x43, 0xc7, 0xc6, + 0x76, 0xa5, 0x86, 0xab, 0x8d, 0x5c, 0xaa, 0x8b, 0x95, 0xd6, 0x08, 0x4a, 0x9b, 0x95, 0x0c, 0x06, 0xad, 0x36, 0xd0, 0x79, 0xcf, 0xd5, 0x06, 0xbb, 0x78, 0xca, 0x0a, 0x0b, 0xb2, 0x36, 0x6f, 0xbb, - 0x0a, 0xc3, 0x16, 0x26, 0x7e, 0x8f, 0x6b, 0x5c, 0xb3, 0x34, 0x15, 0x62, 0x26, 0x52, 0x33, 0x85, - 0x93, 0x31, 0xc5, 0x86, 0x2c, 0x7f, 0x13, 0xdd, 0x07, 0x2e, 0xa0, 0x42, 0xdd, 0x0a, 0x68, 0x16, - 0xca, 0x0a, 0xe0, 0xaa, 0xda, 0xc4, 0x85, 0xe7, 0x61, 0x38, 0x68, 0x1e, 0x34, 0x0e, 0x49, 0xdb, - 0x51, 0x2d, 0x87, 0x7a, 0x61, 0x52, 0x61, 0x0d, 0x94, 0x83, 0x38, 0xd6, 0x6b, 0x34, 0xcb, 0x25, + 0x0a, 0x23, 0x16, 0x26, 0x7e, 0x8f, 0x6b, 0x5c, 0xb3, 0x34, 0x15, 0xa2, 0x10, 0xa9, 0x99, 0xc2, + 0xc9, 0x98, 0x62, 0xc3, 0x96, 0xbf, 0x89, 0xee, 0x03, 0x17, 0x50, 0xa1, 0x6e, 0x05, 0x34, 0x0b, + 0x0d, 0x09, 0xe0, 0xaa, 0xda, 0xc4, 0xf9, 0xe7, 0x61, 0x24, 0x68, 0x1e, 0x34, 0x01, 0x49, 0xdb, + 0x51, 0x2d, 0x87, 0x7a, 0x61, 0x52, 0x61, 0x0d, 0x94, 0x85, 0x38, 0xd6, 0x6b, 0x34, 0xcb, 0x25, 0x15, 0xf2, 0x13, 0xbd, 0xc7, 0x53, 0x38, 0x4e, 0x15, 0x7e, 0xa0, 0x7d, 0x46, 0x03, 0x9c, 0xc3, - 0x7a, 0x17, 0x9e, 0x84, 0xa1, 0x80, 0x02, 0xbd, 0x0e, 0x2d, 0x7f, 0x18, 0x0e, 0x77, 0x64, 0x8d, - 0xde, 0x0b, 0xe3, 0x2d, 0x5d, 0xd3, 0x1d, 0x6c, 0x99, 0x16, 0x26, 0x1e, 0xcb, 0x86, 0xca, 0xff, - 0xc7, 0xc1, 0x2e, 0x3e, 0x77, 0xd5, 0x8f, 0xcd, 0xb8, 0x28, 0x63, 0xad, 0x76, 0xe0, 0xc9, 0x74, - 0xea, 0x8d, 0xc1, 0xdc, 0x0b, 0x2f, 0xbc, 0xf0, 0x42, 0x4c, 0xfe, 0xdc, 0x00, 0x8c, 0x77, 0x8a, - 0x99, 0x8e, 0xe1, 0x3b, 0x01, 0x03, 0x7a, 0xab, 0xb9, 0x85, 0x2d, 0x6a, 0xa4, 0xa4, 0xc2, 0x5b, - 0x68, 0x0e, 0x92, 0x0d, 0x75, 0x0b, 0x37, 0xf2, 0x89, 0x69, 0xe9, 0xc4, 0xf0, 0xa9, 0x87, 0x7b, - 0x8a, 0xca, 0x99, 0x65, 0x42, 0xa2, 0x30, 0x4a, 0xf4, 0x14, 0x24, 0x78, 0x8a, 0x26, 0x1c, 0x4e, - 0xf6, 0xc6, 0x81, 0xc4, 0x92, 0x42, 0xe9, 0xd0, 0x51, 0x48, 0x93, 0xbf, 0xcc, 0x37, 0x06, 0xa8, - 0xcc, 0x29, 0x02, 0x20, 0x7e, 0x81, 0x0a, 0x90, 0xa2, 0x61, 0x52, 0xc3, 0x62, 0x69, 0x73, 0xdb, - 0xc4, 0xb1, 0x6a, 0x78, 0x5b, 0x6d, 0x35, 0x9c, 0xca, 0x0d, 0xb5, 0xd1, 0xc2, 0xd4, 0xe1, 0xd3, - 0x4a, 0x96, 0x03, 0xaf, 0x11, 0x18, 0x9a, 0x82, 0x0c, 0x8b, 0x2a, 0x4d, 0xaf, 0xe1, 0x5d, 0x9a, + 0x7a, 0xe7, 0x9f, 0x84, 0xe1, 0x80, 0x02, 0xbd, 0x0e, 0x2d, 0x7f, 0x18, 0x0e, 0x77, 0x64, 0x8d, + 0xde, 0x0b, 0x13, 0x2d, 0x5d, 0xd3, 0x1d, 0x6c, 0x99, 0x16, 0x26, 0x1e, 0xcb, 0x86, 0xca, 0xfd, + 0xc7, 0xc1, 0x2e, 0x3e, 0x77, 0xd5, 0x8f, 0xcd, 0xb8, 0x28, 0xe3, 0xad, 0x76, 0xe0, 0xc9, 0x74, + 0xea, 0x8d, 0xc1, 0xec, 0x0b, 0x2f, 0xbc, 0xf0, 0x42, 0x4c, 0xfe, 0xe6, 0x00, 0x4c, 0x74, 0x8a, + 0x99, 0x8e, 0xe1, 0x3b, 0x09, 0x03, 0x7a, 0xab, 0xb9, 0x85, 0x2d, 0x6a, 0xa4, 0xa4, 0xc2, 0x5b, + 0x68, 0x0e, 0x92, 0x0d, 0x75, 0x0b, 0x37, 0x72, 0x89, 0x19, 0xe9, 0xc4, 0xc8, 0xa9, 0x87, 0x7b, + 0x8a, 0xca, 0xc2, 0x32, 0x21, 0x51, 0x18, 0x25, 0x7a, 0x0a, 0x12, 0x3c, 0x45, 0x13, 0x0e, 0x27, + 0x7b, 0xe3, 0x40, 0x62, 0x49, 0xa1, 0x74, 0xe8, 0x28, 0xa4, 0xc9, 0x5f, 0xe6, 0x1b, 0x03, 0x54, + 0xe6, 0x14, 0x01, 0x10, 0xbf, 0x40, 0x79, 0x48, 0xd1, 0x30, 0xa9, 0x61, 0xb1, 0xb4, 0xb9, 0x6d, + 0xe2, 0x58, 0x35, 0xbc, 0xad, 0xb6, 0x1a, 0x4e, 0xe5, 0x86, 0xda, 0x68, 0x61, 0xea, 0xf0, 0x69, + 0x65, 0x88, 0x03, 0xaf, 0x11, 0x18, 0x9a, 0x86, 0x0c, 0x8b, 0x2a, 0x4d, 0xaf, 0xe1, 0x5d, 0x9a, 0x3d, 0x93, 0x0a, 0x0b, 0xb4, 0x25, 0x02, 0x21, 0xc3, 0x3f, 0x67, 0x1b, 0xba, 0x70, 0x4d, 0x3a, - 0x04, 0x01, 0xd0, 0xe1, 0x9f, 0x0c, 0x27, 0xee, 0xe3, 0x9d, 0xd5, 0x0b, 0xfb, 0x94, 0xfc, 0x6b, - 0x31, 0x48, 0xd0, 0x7c, 0x31, 0x02, 0x99, 0xcd, 0xf7, 0xad, 0x97, 0x2b, 0x0b, 0x6b, 0x57, 0x4b, - 0xcb, 0xe5, 0x9c, 0x84, 0x86, 0x01, 0x28, 0xe0, 0xe2, 0xf2, 0xda, 0xdc, 0x66, 0x2e, 0xe6, 0xb6, - 0x97, 0x56, 0x37, 0xcf, 0x9e, 0xce, 0xc5, 0x5d, 0x82, 0xab, 0x0c, 0x90, 0xf0, 0x23, 0x3c, 0x71, - 0x2a, 0x97, 0x44, 0x39, 0xc8, 0x32, 0x06, 0x4b, 0xef, 0x2d, 0x2f, 0x9c, 0x3d, 0x9d, 0x1b, 0x08, - 0x42, 0x9e, 0x38, 0x95, 0x1b, 0x44, 0x43, 0x90, 0xa6, 0x90, 0xd2, 0xda, 0xda, 0x72, 0x2e, 0xe5, - 0xf2, 0xdc, 0xd8, 0x54, 0x96, 0x56, 0x17, 0x73, 0x69, 0x97, 0xe7, 0xa2, 0xb2, 0x76, 0x75, 0x3d, - 0x07, 0x2e, 0x87, 0x95, 0xf2, 0xc6, 0xc6, 0xdc, 0x62, 0x39, 0x97, 0x71, 0x31, 0x4a, 0xef, 0xdb, - 0x2c, 0x6f, 0xe4, 0xb2, 0x01, 0xb1, 0x9e, 0x38, 0x95, 0x1b, 0x72, 0x87, 0x28, 0xaf, 0x5e, 0x5d, - 0xc9, 0x0d, 0xa3, 0x51, 0x18, 0x62, 0x43, 0x08, 0x21, 0x46, 0x42, 0xa0, 0xb3, 0xa7, 0x73, 0x39, - 0x4f, 0x10, 0xc6, 0x65, 0x34, 0x00, 0x38, 0x7b, 0x3a, 0x87, 0xe4, 0x79, 0x48, 0x52, 0xef, 0x42, - 0x08, 0x86, 0x97, 0xe7, 0x4a, 0xe5, 0xe5, 0xca, 0xda, 0xfa, 0xe6, 0xd2, 0xda, 0xea, 0xdc, 0x72, - 0x4e, 0xf2, 0x60, 0x4a, 0xf9, 0x99, 0xab, 0x4b, 0x4a, 0x79, 0x21, 0x17, 0xf3, 0xc3, 0xd6, 0xcb, - 0x73, 0x9b, 0xe5, 0x85, 0x5c, 0x5c, 0xae, 0xc2, 0x78, 0xa7, 0x3c, 0xd9, 0x31, 0x32, 0x7c, 0x53, - 0x1c, 0xeb, 0x32, 0xc5, 0x94, 0x57, 0xdb, 0x14, 0x7f, 0x3b, 0x06, 0x63, 0x1d, 0xd6, 0x8a, 0x8e, - 0x83, 0x3c, 0x0d, 0x49, 0xe6, 0xa2, 0x6c, 0xf5, 0x7c, 0xa8, 0xe3, 0xa2, 0x43, 0x1d, 0xb6, 0x6d, - 0x05, 0xa5, 0x74, 0xfe, 0x0a, 0x22, 0xde, 0xa5, 0x82, 0x20, 0x2c, 0xda, 0x72, 0xfa, 0x8f, 0xb4, - 0xe5, 0x74, 0xb6, 0xec, 0x9d, 0xed, 0x65, 0xd9, 0xa3, 0xb0, 0xfe, 0x72, 0x7b, 0xb2, 0x43, 0x6e, - 0xbf, 0x00, 0xa3, 0x6d, 0x8c, 0x7a, 0xce, 0xb1, 0x1f, 0x95, 0x20, 0xdf, 0xcd, 0x38, 0x11, 0x99, - 0x2e, 0x16, 0xc8, 0x74, 0x17, 0xc2, 0x16, 0xbc, 0xb7, 0xfb, 0x24, 0xb4, 0xcd, 0xf5, 0xd7, 0x24, - 0x98, 0xe8, 0x5c, 0x29, 0x76, 0x94, 0xe1, 0x29, 0x18, 0x68, 0x62, 0x67, 0xc7, 0x10, 0xd5, 0xd2, - 0x03, 0x1d, 0xd6, 0x60, 0xd2, 0x1d, 0x9e, 0x6c, 0x4e, 0xe5, 0x5f, 0xc4, 0xe3, 0xdd, 0xca, 0x3d, - 0x26, 0x4d, 0x9b, 0xa4, 0x9f, 0x8c, 0xc1, 0xe1, 0x8e, 0xcc, 0x3b, 0x0a, 0x7a, 0x1c, 0x40, 0xd3, - 0xcd, 0x96, 0xc3, 0x2a, 0x22, 0x96, 0x60, 0xd3, 0x14, 0x42, 0x93, 0x17, 0x49, 0x9e, 0x2d, 0xc7, - 0xed, 0x8f, 0xd3, 0x7e, 0x60, 0x20, 0x8a, 0x70, 0xce, 0x13, 0x34, 0x41, 0x05, 0x9d, 0xec, 0xa2, - 0x69, 0x9b, 0x63, 0x3e, 0x06, 0xb9, 0x6a, 0x43, 0xc3, 0xba, 0x53, 0xb1, 0x1d, 0x0b, 0xab, 0x4d, - 0x4d, 0xaf, 0xd3, 0x15, 0x24, 0x55, 0x4c, 0x6e, 0xab, 0x0d, 0x1b, 0x2b, 0x23, 0xac, 0x7b, 0x43, - 0xf4, 0x12, 0x0a, 0xea, 0x40, 0x96, 0x8f, 0x62, 0x20, 0x40, 0xc1, 0xba, 0x5d, 0x0a, 0xf9, 0x27, - 0xd3, 0x90, 0xf1, 0xd5, 0xd5, 0xe8, 0x5e, 0xc8, 0x3e, 0xa7, 0xde, 0x50, 0x2b, 0x62, 0xaf, 0xc4, - 0x2c, 0x91, 0x21, 0xb0, 0x75, 0xbe, 0x5f, 0x7a, 0x0c, 0xc6, 0x29, 0x8a, 0xd1, 0x72, 0xb0, 0x55, - 0xa9, 0x36, 0x54, 0xdb, 0xa6, 0x46, 0x4b, 0x51, 0x54, 0x44, 0xfa, 0xd6, 0x48, 0xd7, 0xbc, 0xe8, - 0x41, 0x67, 0x60, 0x8c, 0x52, 0x34, 0x5b, 0x0d, 0x47, 0x33, 0x1b, 0xb8, 0x42, 0x76, 0x6f, 0x36, - 0x5d, 0x49, 0x5c, 0xc9, 0x46, 0x09, 0xc6, 0x0a, 0x47, 0x20, 0x12, 0xd9, 0x68, 0x01, 0x8e, 0x53, - 0xb2, 0x3a, 0xd6, 0xb1, 0xa5, 0x3a, 0xb8, 0x82, 0x3f, 0xd8, 0x52, 0x1b, 0x76, 0x45, 0xd5, 0x6b, - 0x95, 0x1d, 0xd5, 0xde, 0xc9, 0x8f, 0x13, 0x06, 0xa5, 0x58, 0x5e, 0x52, 0x8e, 0x10, 0xc4, 0x45, - 0x8e, 0x57, 0xa6, 0x68, 0x73, 0x7a, 0xed, 0x92, 0x6a, 0xef, 0xa0, 0x22, 0x4c, 0x50, 0x2e, 0xb6, - 0x63, 0x69, 0x7a, 0xbd, 0x52, 0xdd, 0xc1, 0xd5, 0xeb, 0x95, 0x96, 0xb3, 0x7d, 0x2e, 0x7f, 0xd4, - 0x3f, 0x3e, 0x95, 0x70, 0x83, 0xe2, 0xcc, 0x13, 0x94, 0xab, 0xce, 0xf6, 0x39, 0xb4, 0x01, 0x59, - 0x32, 0x19, 0x4d, 0xed, 0x79, 0x5c, 0xd9, 0x36, 0x2c, 0xba, 0x34, 0x0e, 0x77, 0x48, 0x4d, 0x3e, - 0x0b, 0xce, 0xac, 0x71, 0x82, 0x15, 0xa3, 0x86, 0x8b, 0xc9, 0x8d, 0xf5, 0x72, 0x79, 0x41, 0xc9, - 0x08, 0x2e, 0x17, 0x0d, 0x8b, 0x38, 0x54, 0xdd, 0x70, 0x0d, 0x9c, 0x61, 0x0e, 0x55, 0x37, 0x84, - 0x79, 0xcf, 0xc0, 0x58, 0xb5, 0xca, 0x74, 0xd6, 0xaa, 0x15, 0xbe, 0xc7, 0xb2, 0xf3, 0xb9, 0x80, - 0xb1, 0xaa, 0xd5, 0x45, 0x86, 0xc0, 0x7d, 0xdc, 0x46, 0xe7, 0xe1, 0xb0, 0x67, 0x2c, 0x3f, 0xe1, - 0x68, 0x9b, 0x96, 0x61, 0xd2, 0x33, 0x30, 0x66, 0xee, 0xb5, 0x13, 0xa2, 0xc0, 0x88, 0xe6, 0x5e, - 0x98, 0xec, 0x49, 0x18, 0x37, 0x77, 0xcc, 0x76, 0xba, 0x93, 0x7e, 0x3a, 0x64, 0xee, 0x98, 0x61, - 0xc2, 0x77, 0xd1, 0x0d, 0xb7, 0x85, 0xab, 0xaa, 0x83, 0x6b, 0xf9, 0x7b, 0xfc, 0xe8, 0xbe, 0x0e, - 0x34, 0x0b, 0xb9, 0x6a, 0xb5, 0x82, 0x75, 0x75, 0xab, 0x81, 0x2b, 0xaa, 0x85, 0x75, 0xd5, 0xce, - 0x4f, 0xf9, 0x91, 0x87, 0xab, 0xd5, 0x32, 0xed, 0x9d, 0xa3, 0x9d, 0xe8, 0x24, 0x8c, 0x1a, 0x5b, - 0xcf, 0x55, 0x99, 0x4b, 0x56, 0x4c, 0x0b, 0x6f, 0x6b, 0xbb, 0xf9, 0xfb, 0xa9, 0x7d, 0x47, 0x48, - 0x07, 0x75, 0xc8, 0x75, 0x0a, 0x46, 0x0f, 0x41, 0xae, 0x6a, 0xef, 0xa8, 0x96, 0x49, 0x73, 0xb2, - 0x6d, 0xaa, 0x55, 0x9c, 0x7f, 0x17, 0x43, 0x65, 0xf0, 0x55, 0x01, 0x26, 0x21, 0x61, 0xdf, 0xd4, - 0xb6, 0x1d, 0xc1, 0xf1, 0x41, 0x16, 0x12, 0x14, 0xc6, 0xb9, 0x9d, 0x80, 0x1c, 0x31, 0x45, 0x60, - 0xe0, 0x13, 0x14, 0x6d, 0xd8, 0xdc, 0x31, 0xfd, 0xe3, 0xde, 0x07, 0x43, 0x04, 0xd3, 0x1b, 0xf4, - 0x21, 0x56, 0x90, 0x99, 0x3b, 0xbe, 0x11, 0x4f, 0xc3, 0x04, 0x41, 0x6a, 0x62, 0x47, 0xad, 0xa9, - 0x8e, 0xea, 0xc3, 0x7e, 0x84, 0x62, 0x13, 0xbb, 0xaf, 0xf0, 0xce, 0x80, 0x9c, 0x56, 0x6b, 0x6b, - 0xcf, 0xf5, 0xac, 0x47, 0x99, 0x9c, 0x04, 0x26, 0x7c, 0xeb, 0xae, 0x15, 0xdd, 0x72, 0x11, 0xb2, - 0x7e, 0xc7, 0x47, 0x69, 0x60, 0xae, 0x9f, 0x93, 0x48, 0x15, 0x34, 0xbf, 0xb6, 0x40, 0xea, 0x97, - 0xf7, 0x97, 0x73, 0x31, 0x52, 0x47, 0x2d, 0x2f, 0x6d, 0x96, 0x2b, 0xca, 0xd5, 0xd5, 0xcd, 0xa5, - 0x95, 0x72, 0x2e, 0xee, 0x2b, 0xd8, 0x2f, 0x27, 0x52, 0x0f, 0xe4, 0x1e, 0x94, 0x5f, 0x8d, 0xc1, - 0x70, 0x70, 0x07, 0x86, 0x7e, 0x08, 0xee, 0x11, 0xc7, 0x25, 0x36, 0x76, 0x2a, 0x37, 0x35, 0x8b, - 0x46, 0x64, 0x53, 0x65, 0xab, 0xa3, 0xeb, 0x13, 0xe3, 0x1c, 0x6b, 0x03, 0x3b, 0xcf, 0x6a, 0x16, - 0x89, 0xb7, 0xa6, 0xea, 0xa0, 0x65, 0x98, 0xd2, 0x8d, 0x8a, 0xed, 0xa8, 0x7a, 0x4d, 0xb5, 0x6a, - 0x15, 0xef, 0xa0, 0xaa, 0xa2, 0x56, 0xab, 0xd8, 0xb6, 0x0d, 0xb6, 0x12, 0xba, 0x5c, 0x8e, 0xe9, - 0xc6, 0x06, 0x47, 0xf6, 0x96, 0x88, 0x39, 0x8e, 0x1a, 0xf2, 0xdf, 0x78, 0x37, 0xff, 0x3d, 0x0a, - 0xe9, 0xa6, 0x6a, 0x56, 0xb0, 0xee, 0x58, 0x7b, 0xb4, 0xee, 0x4e, 0x29, 0xa9, 0xa6, 0x6a, 0x96, - 0x49, 0xfb, 0x6d, 0xd9, 0xfe, 0x5c, 0x4e, 0xa4, 0x52, 0xb9, 0xf4, 0xe5, 0x44, 0x2a, 0x9d, 0x03, - 0xf9, 0xb5, 0x38, 0x64, 0xfd, 0x75, 0x38, 0xd9, 0xd6, 0x54, 0xe9, 0x92, 0x25, 0xd1, 0xa4, 0x76, - 0xdf, 0xbe, 0x55, 0xfb, 0xcc, 0x3c, 0x59, 0xcb, 0x8a, 0x03, 0xac, 0x3a, 0x56, 0x18, 0x25, 0xa9, - 0x23, 0x88, 0xb3, 0x61, 0x56, 0x8d, 0xa4, 0x14, 0xde, 0x42, 0x8b, 0x30, 0xf0, 0x9c, 0x4d, 0x79, - 0x0f, 0x50, 0xde, 0xf7, 0xef, 0xcf, 0xfb, 0xf2, 0x06, 0x65, 0x9e, 0xbe, 0xbc, 0x51, 0x59, 0x5d, - 0x53, 0x56, 0xe6, 0x96, 0x15, 0x4e, 0x8e, 0x8e, 0x40, 0xa2, 0xa1, 0x3e, 0xbf, 0x17, 0x5c, 0xf5, - 0x28, 0xa8, 0xd7, 0x49, 0x38, 0x02, 0x89, 0x9b, 0x58, 0xbd, 0x1e, 0x5c, 0x6b, 0x28, 0xe8, 0x2e, - 0x06, 0xc3, 0x2c, 0x24, 0xa9, 0xbd, 0x10, 0x00, 0xb7, 0x58, 0xee, 0x10, 0x4a, 0x41, 0x62, 0x7e, - 0x4d, 0x21, 0x01, 0x91, 0x83, 0x2c, 0x83, 0x56, 0xd6, 0x97, 0xca, 0xf3, 0xe5, 0x5c, 0x4c, 0x3e, - 0x03, 0x03, 0xcc, 0x08, 0x24, 0x58, 0x5c, 0x33, 0xe4, 0x0e, 0xf1, 0x26, 0xe7, 0x21, 0x89, 0xde, - 0xab, 0x2b, 0xa5, 0xb2, 0x92, 0x8b, 0x05, 0xa7, 0x3a, 0x91, 0x4b, 0xca, 0x36, 0x64, 0xfd, 0x85, - 0xf8, 0xdb, 0xb3, 0xc9, 0xfe, 0xa6, 0x04, 0x19, 0x5f, 0x61, 0x4d, 0x2a, 0x22, 0xb5, 0xd1, 0x30, - 0x6e, 0x56, 0xd4, 0x86, 0xa6, 0xda, 0xdc, 0x35, 0x80, 0x82, 0xe6, 0x08, 0xa4, 0xd7, 0xa9, 0x7b, - 0x9b, 0x42, 0x24, 0x99, 0x1b, 0x90, 0xbf, 0x2c, 0x41, 0x2e, 0x5c, 0xd9, 0x86, 0xc4, 0x94, 0xde, - 0x49, 0x31, 0xe5, 0x2f, 0x49, 0x30, 0x1c, 0x2c, 0x67, 0x43, 0xe2, 0xdd, 0xfb, 0x8e, 0x8a, 0xf7, - 0x47, 0x31, 0x18, 0x0a, 0x14, 0xb1, 0xbd, 0x4a, 0xf7, 0x41, 0x18, 0xd5, 0x6a, 0xb8, 0x69, 0x1a, - 0x0e, 0xd6, 0xab, 0x7b, 0x95, 0x06, 0xbe, 0x81, 0x1b, 0x79, 0x99, 0x26, 0x8d, 0xd9, 0xfd, 0xcb, - 0xe4, 0x99, 0x25, 0x8f, 0x6e, 0x99, 0x90, 0x15, 0xc7, 0x96, 0x16, 0xca, 0x2b, 0xeb, 0x6b, 0x9b, - 0xe5, 0xd5, 0xf9, 0xf7, 0x55, 0xae, 0xae, 0x5e, 0x59, 0x5d, 0x7b, 0x76, 0x55, 0xc9, 0x69, 0x21, - 0xb4, 0xbb, 0x18, 0xf6, 0xeb, 0x90, 0x0b, 0x0b, 0x85, 0xee, 0x81, 0x4e, 0x62, 0xe5, 0x0e, 0xa1, - 0x31, 0x18, 0x59, 0x5d, 0xab, 0x6c, 0x2c, 0x2d, 0x94, 0x2b, 0xe5, 0x8b, 0x17, 0xcb, 0xf3, 0x9b, - 0x1b, 0xec, 0xe0, 0xc3, 0xc5, 0xde, 0x0c, 0x04, 0xb8, 0xfc, 0x85, 0x38, 0x8c, 0x75, 0x90, 0x04, - 0xcd, 0xf1, 0x2d, 0x0b, 0xdb, 0x45, 0x3d, 0xda, 0x8b, 0xf4, 0x33, 0xa4, 0x66, 0x58, 0x57, 0x2d, - 0x87, 0xef, 0x70, 0x1e, 0x02, 0x62, 0x25, 0xdd, 0xd1, 0xb6, 0x35, 0x6c, 0xf1, 0x73, 0x22, 0xb6, - 0x8f, 0x19, 0xf1, 0xe0, 0xec, 0xa8, 0xe8, 0x11, 0x40, 0xa6, 0x61, 0x6b, 0x8e, 0x76, 0x03, 0x57, - 0x34, 0x5d, 0x1c, 0x2a, 0x91, 0x7d, 0x4d, 0x42, 0xc9, 0x89, 0x9e, 0x25, 0xdd, 0x71, 0xb1, 0x75, - 0x5c, 0x57, 0x43, 0xd8, 0x24, 0x99, 0xc7, 0x95, 0x9c, 0xe8, 0x71, 0xb1, 0xef, 0x85, 0x6c, 0xcd, - 0x68, 0x91, 0x62, 0x8f, 0xe1, 0x91, 0xb5, 0x43, 0x52, 0x32, 0x0c, 0xe6, 0xa2, 0xf0, 0x32, 0xde, - 0x3b, 0xcd, 0xca, 0x2a, 0x19, 0x06, 0x63, 0x28, 0x0f, 0xc2, 0x88, 0x5a, 0xaf, 0x5b, 0x84, 0xb9, - 0x60, 0xc4, 0x36, 0x26, 0xc3, 0x2e, 0x98, 0x22, 0x16, 0x2e, 0x43, 0x4a, 0xd8, 0x81, 0x2c, 0xd5, - 0xc4, 0x12, 0x15, 0x93, 0xed, 0xb6, 0x63, 0x27, 0xd2, 0x4a, 0x4a, 0x17, 0x9d, 0xf7, 0x42, 0x56, - 0xb3, 0x2b, 0xde, 0xe1, 0x7c, 0x6c, 0x3a, 0x76, 0x22, 0xa5, 0x64, 0x34, 0xdb, 0x3d, 0xd8, 0x94, - 0xbf, 0x16, 0x83, 0xe1, 0xe0, 0xc3, 0x05, 0xb4, 0x00, 0xa9, 0x86, 0x51, 0x55, 0xa9, 0x6b, 0xb1, - 0x27, 0x5b, 0x27, 0x22, 0x9e, 0x47, 0xcc, 0x2c, 0x73, 0x7c, 0xc5, 0xa5, 0x2c, 0xfc, 0x8e, 0x04, - 0x29, 0x01, 0x46, 0x13, 0x90, 0x30, 0x55, 0x67, 0x87, 0xb2, 0x4b, 0x96, 0x62, 0x39, 0x49, 0xa1, - 0x6d, 0x02, 0xb7, 0x4d, 0x55, 0xa7, 0x2e, 0xc0, 0xe1, 0xa4, 0x4d, 0xe6, 0xb5, 0x81, 0xd5, 0x1a, - 0xdd, 0xf5, 0x18, 0xcd, 0x26, 0xd6, 0x1d, 0x5b, 0xcc, 0x2b, 0x87, 0xcf, 0x73, 0x30, 0x7a, 0x18, - 0x46, 0x1d, 0x4b, 0xd5, 0x1a, 0x01, 0xdc, 0x04, 0xc5, 0xcd, 0x89, 0x0e, 0x17, 0xb9, 0x08, 0x47, - 0x04, 0xdf, 0x1a, 0x76, 0xd4, 0xea, 0x0e, 0xae, 0x79, 0x44, 0x03, 0xf4, 0x74, 0xe3, 0x1e, 0x8e, - 0xb0, 0xc0, 0xfb, 0x05, 0xad, 0xfc, 0xaa, 0x04, 0xa3, 0x62, 0x9f, 0x56, 0x73, 0x8d, 0xb5, 0x02, - 0xa0, 0xea, 0xba, 0xe1, 0xf8, 0xcd, 0xd5, 0xee, 0xca, 0x6d, 0x74, 0x33, 0x73, 0x2e, 0x91, 0xe2, - 0x63, 0x50, 0x68, 0x02, 0x78, 0x3d, 0x5d, 0xcd, 0x36, 0x05, 0x19, 0xfe, 0xe4, 0x88, 0x3e, 0x7e, - 0x64, 0x3b, 0x7b, 0x60, 0x20, 0xb2, 0xa1, 0x43, 0xe3, 0x90, 0xdc, 0xc2, 0x75, 0x4d, 0xe7, 0xe7, - 0xc1, 0xac, 0x21, 0xce, 0x5f, 0x12, 0xee, 0xf9, 0x4b, 0xe9, 0x53, 0x12, 0x8c, 0x55, 0x8d, 0x66, - 0x58, 0xde, 0x52, 0x2e, 0x74, 0xbc, 0x60, 0x5f, 0x92, 0xde, 0xff, 0x54, 0x5d, 0x73, 0x76, 0x5a, - 0x5b, 0x33, 0x55, 0xa3, 0x39, 0x5b, 0x37, 0x1a, 0xaa, 0x5e, 0xf7, 0x9e, 0x9f, 0xd2, 0x1f, 0xd5, - 0x47, 0xeb, 0x58, 0x7f, 0xb4, 0x6e, 0xf8, 0x9e, 0xa6, 0x5e, 0xf0, 0x7e, 0xfe, 0x99, 0x24, 0xfd, - 0x4c, 0x2c, 0xbe, 0xb8, 0x5e, 0xfa, 0x7a, 0xac, 0xb0, 0xc8, 0x86, 0x5b, 0x17, 0xe6, 0x51, 0xf0, - 0x76, 0x03, 0x57, 0x89, 0xca, 0xf0, 0x9d, 0x87, 0x61, 0xbc, 0x6e, 0xd4, 0x0d, 0xca, 0x71, 0x96, - 0xfc, 0xe2, 0x4f, 0x64, 0xd3, 0x2e, 0xb4, 0x10, 0xf9, 0xf8, 0xb6, 0xb8, 0x0a, 0x63, 0x1c, 0xb9, - 0x42, 0x1f, 0x09, 0xb1, 0x8d, 0x0d, 0xda, 0xf7, 0x58, 0x2d, 0xff, 0xcb, 0xaf, 0xd3, 0x05, 0x5d, - 0x19, 0xe5, 0xa4, 0xa4, 0x8f, 0xed, 0x7d, 0x8a, 0x0a, 0x1c, 0x0e, 0xf0, 0x63, 0x61, 0x8b, 0xad, - 0x08, 0x8e, 0xbf, 0xc9, 0x39, 0x8e, 0xf9, 0x38, 0x6e, 0x70, 0xd2, 0xe2, 0x3c, 0x0c, 0xf5, 0xc3, - 0xeb, 0x9f, 0x73, 0x5e, 0x59, 0xec, 0x67, 0xb2, 0x08, 0x23, 0x94, 0x49, 0xb5, 0x65, 0x3b, 0x46, - 0x93, 0xe6, 0xc4, 0xfd, 0xd9, 0xfc, 0xd6, 0xeb, 0x2c, 0x8e, 0x86, 0x09, 0xd9, 0xbc, 0x4b, 0x55, - 0x2c, 0x02, 0x7d, 0x0a, 0x56, 0xc3, 0xd5, 0x46, 0x04, 0x87, 0x6f, 0x71, 0x41, 0x5c, 0xfc, 0xe2, - 0x35, 0x18, 0x27, 0xbf, 0x69, 0xca, 0xf2, 0x4b, 0x12, 0x7d, 0x06, 0x97, 0x7f, 0xf5, 0xa3, 0x2c, - 0x54, 0xc7, 0x5c, 0x06, 0x3e, 0x99, 0x7c, 0xb3, 0x58, 0xc7, 0x8e, 0x83, 0x2d, 0xbb, 0xa2, 0x36, - 0x3a, 0x89, 0xe7, 0x3b, 0xc4, 0xc8, 0x7f, 0xfe, 0xbb, 0xc1, 0x59, 0x5c, 0x64, 0x94, 0x73, 0x8d, - 0x46, 0xf1, 0x2a, 0xdc, 0xd3, 0xc1, 0x2b, 0x7a, 0xe0, 0xf9, 0x05, 0xce, 0x73, 0xbc, 0xcd, 0x33, - 0x08, 0xdb, 0x75, 0x10, 0x70, 0x77, 0x2e, 0x7b, 0xe0, 0xf9, 0x45, 0xce, 0x13, 0x71, 0x5a, 0x31, - 0xa5, 0x84, 0xe3, 0x65, 0x18, 0xbd, 0x81, 0xad, 0x2d, 0xc3, 0xe6, 0x07, 0x47, 0x3d, 0xb0, 0xfb, - 0x12, 0x67, 0x37, 0xc2, 0x09, 0xe9, 0x49, 0x12, 0xe1, 0x75, 0x1e, 0x52, 0xdb, 0x6a, 0x15, 0xf7, - 0xc0, 0xe2, 0x25, 0xce, 0x62, 0x90, 0xe0, 0x13, 0xd2, 0x39, 0xc8, 0xd6, 0x0d, 0xbe, 0x6a, 0x45, - 0x93, 0x7f, 0x99, 0x93, 0x67, 0x04, 0x0d, 0x67, 0x61, 0x1a, 0x66, 0xab, 0x41, 0x96, 0xb4, 0x68, - 0x16, 0x7f, 0x43, 0xb0, 0x10, 0x34, 0x9c, 0x45, 0x1f, 0x66, 0x7d, 0x59, 0xb0, 0xb0, 0x7d, 0xf6, - 0x7c, 0x1a, 0x32, 0x86, 0xde, 0xd8, 0x33, 0xf4, 0x5e, 0x84, 0xf8, 0x0a, 0xe7, 0x00, 0x9c, 0x84, - 0x30, 0xb8, 0x00, 0xe9, 0x5e, 0x27, 0xe2, 0x6f, 0x7e, 0x57, 0x84, 0x87, 0x98, 0x81, 0x45, 0x18, - 0x11, 0x09, 0x4a, 0x33, 0xf4, 0x1e, 0x58, 0xfc, 0x2d, 0xce, 0x62, 0xd8, 0x47, 0xc6, 0xd5, 0x70, - 0xb0, 0xed, 0xd4, 0x71, 0x2f, 0x4c, 0xbe, 0x26, 0xd4, 0xe0, 0x24, 0xdc, 0x94, 0x5b, 0x58, 0xaf, - 0xee, 0xf4, 0xc6, 0xe1, 0xe7, 0x84, 0x29, 0x05, 0x0d, 0x61, 0x31, 0x0f, 0x43, 0x4d, 0xd5, 0xb2, - 0x77, 0xd4, 0x46, 0x4f, 0xd3, 0xf1, 0xb7, 0x39, 0x8f, 0xac, 0x4b, 0xc4, 0x2d, 0xd2, 0xd2, 0xfb, - 0x61, 0xf3, 0x75, 0x61, 0x11, 0x1f, 0x19, 0x0f, 0x3d, 0xdb, 0xa1, 0xa7, 0x6c, 0xfd, 0x70, 0xfb, - 0x79, 0x11, 0x7a, 0x8c, 0x76, 0xc5, 0xcf, 0xf1, 0x02, 0xa4, 0x6d, 0xed, 0xf9, 0x9e, 0xd8, 0xfc, - 0x82, 0x98, 0x69, 0x4a, 0x40, 0x88, 0xdf, 0x07, 0x47, 0x3a, 0x2e, 0x13, 0x3d, 0x30, 0xfb, 0x3b, - 0x9c, 0xd9, 0x44, 0x87, 0xa5, 0x82, 0xa7, 0x84, 0x7e, 0x59, 0xfe, 0x5d, 0x91, 0x12, 0x70, 0x88, - 0xd7, 0x3a, 0xd9, 0x47, 0xd8, 0xea, 0x76, 0x7f, 0x56, 0xfb, 0x45, 0x61, 0x35, 0x46, 0x1b, 0xb0, - 0xda, 0x26, 0x4c, 0x70, 0x8e, 0xfd, 0xcd, 0xeb, 0x2f, 0x89, 0xc4, 0xca, 0xa8, 0xaf, 0x06, 0x67, - 0xf7, 0x03, 0x50, 0x70, 0xcd, 0x29, 0x0a, 0x56, 0xbb, 0xd2, 0x54, 0xcd, 0x1e, 0x38, 0xff, 0x32, - 0xe7, 0x2c, 0x32, 0xbe, 0x5b, 0xf1, 0xda, 0x2b, 0xaa, 0x49, 0x98, 0xbf, 0x17, 0xf2, 0x82, 0x79, - 0x4b, 0xb7, 0x70, 0xd5, 0xa8, 0xeb, 0xda, 0xf3, 0xb8, 0xd6, 0x03, 0xeb, 0x5f, 0x09, 0x4d, 0xd5, - 0x55, 0x1f, 0x39, 0xe1, 0xbc, 0x04, 0x39, 0xb7, 0x56, 0xa9, 0x68, 0x4d, 0xd3, 0xb0, 0x9c, 0x08, - 0x8e, 0xdf, 0x10, 0x33, 0xe5, 0xd2, 0x2d, 0x51, 0xb2, 0x62, 0x19, 0x86, 0x69, 0xb3, 0x57, 0x97, - 0xfc, 0x55, 0xce, 0x68, 0xc8, 0xa3, 0xe2, 0x89, 0xa3, 0x6a, 0x34, 0x4d, 0xd5, 0xea, 0x25, 0xff, - 0xfd, 0x3d, 0x91, 0x38, 0x38, 0x09, 0x4f, 0x1c, 0xce, 0x9e, 0x89, 0xc9, 0x6a, 0xdf, 0x03, 0x87, - 0x5f, 0x13, 0x89, 0x43, 0xd0, 0x70, 0x16, 0xa2, 0x60, 0xe8, 0x81, 0xc5, 0xdf, 0x17, 0x2c, 0x04, - 0x0d, 0x61, 0xf1, 0x8c, 0xb7, 0xd0, 0x5a, 0xb8, 0xae, 0xd9, 0x8e, 0xc5, 0xca, 0xe4, 0xfd, 0x59, - 0xfd, 0x83, 0xef, 0x06, 0x8b, 0x30, 0xc5, 0x47, 0x4a, 0x32, 0x11, 0x3f, 0x76, 0xa5, 0xbb, 0xa8, - 0x68, 0xc1, 0x7e, 0x5d, 0x64, 0x22, 0x1f, 0x19, 0x91, 0xcd, 0x57, 0x21, 0x12, 0xb3, 0x57, 0xc9, - 0xde, 0xa1, 0x07, 0x76, 0xff, 0x30, 0x24, 0xdc, 0x86, 0xa0, 0x25, 0x3c, 0x7d, 0xf5, 0x4f, 0x4b, - 0xbf, 0x8e, 0xf7, 0x7a, 0xf2, 0xce, 0x7f, 0x14, 0xaa, 0x7f, 0xae, 0x32, 0x4a, 0x96, 0x43, 0x46, - 0x42, 0xf5, 0x14, 0x8a, 0xba, 0x3f, 0x94, 0xff, 0xd1, 0x37, 0xb9, 0xbe, 0xc1, 0x72, 0xaa, 0xb8, - 0x4c, 0x9c, 0x3c, 0x58, 0xf4, 0x44, 0x33, 0xfb, 0xe8, 0x9b, 0xae, 0x9f, 0x07, 0x6a, 0x9e, 0xe2, - 0x45, 0x18, 0x0a, 0x14, 0x3c, 0xd1, 0xac, 0x3e, 0xc6, 0x59, 0x65, 0xfd, 0xf5, 0x4e, 0xf1, 0x0c, - 0x24, 0x48, 0xf1, 0x12, 0x4d, 0xfe, 0x97, 0x39, 0x39, 0x45, 0x2f, 0xbe, 0x1b, 0x52, 0xa2, 0x68, - 0x89, 0x26, 0xfd, 0x38, 0x27, 0x75, 0x49, 0x08, 0xb9, 0x28, 0x58, 0xa2, 0xc9, 0xff, 0x8a, 0x20, - 0x17, 0x24, 0x84, 0xbc, 0x77, 0x13, 0x7e, 0xf3, 0xc7, 0x13, 0x7c, 0xd1, 0x11, 0xb6, 0xbb, 0x00, - 0x83, 0xbc, 0x52, 0x89, 0xa6, 0xfe, 0x24, 0x1f, 0x5c, 0x50, 0x14, 0x9f, 0x84, 0x64, 0x8f, 0x06, - 0xff, 0x09, 0x4e, 0xca, 0xf0, 0x8b, 0xf3, 0x90, 0xf1, 0x55, 0x27, 0xd1, 0xe4, 0x7f, 0x8d, 0x93, - 0xfb, 0xa9, 0x88, 0xe8, 0xbc, 0x3a, 0x89, 0x66, 0xf0, 0x29, 0x21, 0x3a, 0xa7, 0x20, 0x66, 0x13, - 0x85, 0x49, 0x34, 0xf5, 0xa7, 0x85, 0xd5, 0x05, 0x49, 0xf1, 0x69, 0x48, 0xbb, 0x8b, 0x4d, 0x34, - 0xfd, 0x67, 0x38, 0xbd, 0x47, 0x43, 0x2c, 0xe0, 0x5b, 0xec, 0xa2, 0x59, 0xfc, 0xa4, 0xb0, 0x80, - 0x8f, 0x8a, 0x84, 0x51, 0xb8, 0x80, 0x89, 0xe6, 0xf4, 0x59, 0x11, 0x46, 0xa1, 0xfa, 0x85, 0xcc, - 0x26, 0xcd, 0xf9, 0xd1, 0x2c, 0x7e, 0x4a, 0xcc, 0x26, 0xc5, 0x27, 0x62, 0x84, 0x2b, 0x82, 0x68, - 0x1e, 0x7f, 0x5d, 0x88, 0x11, 0x2a, 0x08, 0x8a, 0xeb, 0x80, 0xda, 0xab, 0x81, 0x68, 0x7e, 0x9f, - 0xe3, 0xfc, 0x46, 0xdb, 0x8a, 0x81, 0xe2, 0xb3, 0x30, 0xd1, 0xb9, 0x12, 0x88, 0xe6, 0xfa, 0xf9, - 0x37, 0x43, 0x7b, 0x37, 0x7f, 0x21, 0x50, 0xdc, 0xf4, 0x96, 0x14, 0x7f, 0x15, 0x10, 0xcd, 0xf6, - 0x0b, 0x6f, 0x06, 0x13, 0xb7, 0xbf, 0x08, 0x28, 0xce, 0x01, 0x78, 0x0b, 0x70, 0x34, 0xaf, 0x2f, - 0x71, 0x5e, 0x3e, 0x22, 0x12, 0x1a, 0x7c, 0xfd, 0x8d, 0xa6, 0x7f, 0x49, 0x84, 0x06, 0xa7, 0x20, - 0xa1, 0x21, 0x96, 0xde, 0x68, 0xea, 0x2f, 0x8b, 0xd0, 0x10, 0x24, 0xc4, 0xb3, 0x7d, 0xab, 0x5b, - 0x34, 0x87, 0xaf, 0x08, 0xcf, 0xf6, 0x51, 0x15, 0x57, 0x61, 0xb4, 0x6d, 0x41, 0x8c, 0x66, 0xf5, - 0x33, 0x9c, 0x55, 0x2e, 0xbc, 0x1e, 0xfa, 0x17, 0x2f, 0xbe, 0x18, 0x46, 0x73, 0xfb, 0x6a, 0x68, - 0xf1, 0xe2, 0x6b, 0x61, 0xf1, 0x02, 0xa4, 0xf4, 0x56, 0xa3, 0x41, 0x82, 0x07, 0xed, 0x7f, 0xe7, - 0x2f, 0xff, 0x9f, 0xbe, 0xcf, 0xad, 0x23, 0x08, 0x8a, 0x67, 0x20, 0x89, 0x9b, 0x5b, 0xb8, 0x16, - 0x45, 0xf9, 0x9d, 0xef, 0x8b, 0x84, 0x49, 0xb0, 0x8b, 0x4f, 0x03, 0xb0, 0xa3, 0x11, 0xfa, 0x78, - 0x30, 0x82, 0xf6, 0x3f, 0x7f, 0x9f, 0xdf, 0xc6, 0xf1, 0x48, 0x3c, 0x06, 0xec, 0x6e, 0xcf, 0xfe, - 0x0c, 0xbe, 0x1b, 0x64, 0x40, 0x67, 0xe4, 0x3c, 0x0c, 0x3e, 0x67, 0x1b, 0xba, 0xa3, 0xd6, 0xa3, - 0xa8, 0xff, 0x0b, 0xa7, 0x16, 0xf8, 0xc4, 0x60, 0x4d, 0xc3, 0xc2, 0x8e, 0x5a, 0xb7, 0xa3, 0x68, - 0xff, 0x2b, 0xa7, 0x75, 0x09, 0x08, 0x71, 0x55, 0xb5, 0x9d, 0x5e, 0xf4, 0xfe, 0x6f, 0x82, 0x58, - 0x10, 0x10, 0xa1, 0xc9, 0xef, 0xeb, 0x78, 0x2f, 0x8a, 0xf6, 0x7b, 0x42, 0x68, 0x8e, 0x5f, 0x7c, - 0x37, 0xa4, 0xc9, 0x4f, 0x76, 0xc5, 0x2e, 0x82, 0xf8, 0x4f, 0x38, 0xb1, 0x47, 0x41, 0x46, 0xb6, - 0x9d, 0x9a, 0xa3, 0x45, 0x1b, 0xfb, 0x36, 0x9f, 0x69, 0x81, 0x5f, 0x9c, 0x83, 0x8c, 0xed, 0xd4, - 0x6a, 0x2d, 0x5e, 0x9f, 0x46, 0x90, 0xff, 0xf7, 0xef, 0xbb, 0x47, 0x16, 0x2e, 0x0d, 0x99, 0xed, - 0x9b, 0xd7, 0x1d, 0xd3, 0xa0, 0x8f, 0x40, 0xa2, 0x38, 0xbc, 0xc9, 0x39, 0xf8, 0x48, 0x8a, 0xf3, - 0x90, 0x25, 0xba, 0x58, 0xd8, 0xc4, 0xf4, 0x79, 0x55, 0x04, 0x8b, 0xff, 0xc1, 0x0d, 0x10, 0x20, - 0x2a, 0xfd, 0xc8, 0xb7, 0x5e, 0x9b, 0x94, 0x5e, 0x79, 0x6d, 0x52, 0xfa, 0xa3, 0xd7, 0x26, 0xa5, - 0x4f, 0x7f, 0x7b, 0xf2, 0xd0, 0x2b, 0xdf, 0x9e, 0x3c, 0xf4, 0x7b, 0xdf, 0x9e, 0x3c, 0xd4, 0xf9, - 0xd8, 0x18, 0x16, 0x8d, 0x45, 0x83, 0x1d, 0x18, 0xbf, 0x5f, 0x0e, 0x1c, 0x17, 0xd7, 0x0d, 0xef, - 0xb4, 0xd6, 0xdd, 0xe4, 0xc0, 0xc7, 0xe2, 0x30, 0x59, 0x35, 0xec, 0xa6, 0x61, 0xcf, 0x6e, 0xa9, - 0x36, 0x9e, 0xbd, 0xf1, 0xf8, 0x16, 0x76, 0xd4, 0xc7, 0x67, 0xab, 0x86, 0xa6, 0xf3, 0x63, 0xdf, - 0x31, 0xd6, 0x3f, 0x43, 0xfa, 0x67, 0x78, 0x7f, 0xa1, 0xe3, 0x09, 0xb1, 0xbc, 0x08, 0x89, 0x79, - 0x43, 0xd3, 0xd1, 0x38, 0x24, 0x6b, 0x58, 0x37, 0x9a, 0xfc, 0x06, 0x18, 0x6b, 0xa0, 0xfb, 0x60, - 0x40, 0x6d, 0x1a, 0x2d, 0xdd, 0x61, 0xc7, 0xe5, 0xa5, 0xcc, 0xb7, 0x6e, 0x4d, 0x1d, 0xfa, 0xfd, - 0x5b, 0x53, 0xf1, 0x25, 0xdd, 0x51, 0x78, 0x57, 0x31, 0xf1, 0xc6, 0xcb, 0x53, 0x92, 0x7c, 0x19, - 0x06, 0x17, 0x70, 0xf5, 0x20, 0xbc, 0x16, 0x70, 0x35, 0xc4, 0xeb, 0x21, 0x48, 0x2d, 0xe9, 0x0e, - 0xbb, 0xa3, 0x77, 0x1c, 0xe2, 0x9a, 0xce, 0x6e, 0x7d, 0x84, 0xc6, 0x27, 0x70, 0x82, 0xba, 0x80, - 0xab, 0x2e, 0x6a, 0x0d, 0x57, 0xc3, 0xa8, 0x84, 0x3d, 0x81, 0x97, 0x16, 0x7e, 0xef, 0xdf, 0x4f, - 0x1e, 0x7a, 0xe1, 0xb5, 0xc9, 0x43, 0xdd, 0xe6, 0x27, 0x60, 0x7e, 0x6e, 0x62, 0xf6, 0xe7, 0x51, - 0xbb, 0x76, 0x7d, 0x96, 0x84, 0x96, 0xbd, 0x35, 0x40, 0xed, 0xf6, 0x04, 0x7c, 0x3a, 0x06, 0x53, - 0xe1, 0x23, 0x75, 0xe2, 0xc7, 0xb6, 0xa3, 0x36, 0xcd, 0x6e, 0x2f, 0x44, 0x5d, 0x80, 0xf4, 0xa6, - 0xc0, 0x41, 0x79, 0x18, 0xb4, 0x71, 0xd5, 0xd0, 0x6b, 0x36, 0x15, 0x39, 0xae, 0x88, 0x26, 0x31, - 0xa0, 0xae, 0xea, 0x86, 0xcd, 0xef, 0x6b, 0xb2, 0x46, 0xe9, 0xa7, 0xa5, 0xfe, 0x1c, 0x6b, 0xd8, - 0x1d, 0x8a, 0x9a, 0x67, 0x5d, 0x7a, 0xff, 0xc3, 0xfb, 0x3d, 0x8d, 0xa0, 0xea, 0x79, 0x2a, 0xf8, - 0x1e, 0x3d, 0x4c, 0x86, 0x1f, 0x3d, 0x3c, 0x8b, 0x1b, 0x8d, 0x2b, 0xba, 0x71, 0x53, 0xdf, 0x0c, - 0x98, 0xe4, 0x5f, 0x49, 0x30, 0x4d, 0x2f, 0xa2, 0x5b, 0x4d, 0x4d, 0x77, 0x66, 0x1b, 0xda, 0x96, - 0x3d, 0xbb, 0xa5, 0x39, 0x36, 0xb3, 0x1c, 0xb7, 0xc9, 0xb8, 0x87, 0x31, 0x43, 0x30, 0x66, 0x08, - 0x86, 0x7c, 0x1a, 0x52, 0x25, 0xcd, 0x99, 0xb3, 0x2c, 0x75, 0x0f, 0x21, 0x48, 0x10, 0x18, 0x37, - 0x0a, 0xfd, 0x4d, 0x2c, 0x82, 0x1b, 0xb8, 0x69, 0xd3, 0x87, 0x5e, 0x09, 0x85, 0x35, 0x4a, 0x57, - 0xbb, 0xce, 0xe4, 0x05, 0x9f, 0xa6, 0x3e, 0x91, 0x7c, 0x3f, 0x59, 0x24, 0x74, 0x12, 0xd7, 0xd5, - 0xe7, 0xeb, 0x09, 0x38, 0xee, 0x43, 0xa8, 0x5a, 0x7b, 0xa6, 0x43, 0x43, 0xd2, 0xd8, 0xe6, 0xca, - 0x8c, 0xfa, 0x94, 0x61, 0xdd, 0x5d, 0xc2, 0x6c, 0x1b, 0x92, 0xeb, 0x84, 0x8e, 0x28, 0xe2, 0x18, - 0x8e, 0xda, 0xe0, 0xda, 0xb1, 0x06, 0x81, 0xb2, 0xcb, 0xf8, 0x31, 0x06, 0xd5, 0xc4, 0x3d, 0xfc, - 0x06, 0x56, 0xb7, 0xd9, 0xe5, 0xc7, 0x38, 0x7d, 0xf6, 0x99, 0x22, 0x00, 0x7a, 0xcf, 0x71, 0x1c, - 0x92, 0x6a, 0x8b, 0x3d, 0xb6, 0x8b, 0x9f, 0xc8, 0x2a, 0xac, 0x21, 0x5f, 0x81, 0x41, 0xfe, 0xa8, - 0x00, 0xe5, 0x20, 0x7e, 0x1d, 0xef, 0xd1, 0x71, 0xb2, 0x0a, 0xf9, 0x89, 0x66, 0x20, 0x49, 0x85, - 0xe7, 0xb7, 0xba, 0xf3, 0x33, 0x6d, 0xd2, 0xcf, 0x50, 0x21, 0x15, 0x86, 0x26, 0x5f, 0x86, 0xd4, - 0x82, 0xd1, 0xd4, 0x74, 0x23, 0xc8, 0x2d, 0xcd, 0xb8, 0x51, 0x99, 0xcd, 0x16, 0x0f, 0x67, 0x85, - 0x35, 0xd0, 0x04, 0x0c, 0xb0, 0xcb, 0xb0, 0xfc, 0xd1, 0x23, 0x6f, 0xc9, 0xf3, 0x30, 0x48, 0x79, - 0xaf, 0x99, 0x64, 0x7e, 0xdd, 0x8b, 0x48, 0x69, 0xfe, 0xc6, 0x03, 0x67, 0x1f, 0xf3, 0x84, 0x45, - 0x90, 0xa8, 0xa9, 0x8e, 0xca, 0xf5, 0xa6, 0xbf, 0xe5, 0xa7, 0x20, 0xc5, 0x99, 0xd8, 0xe8, 0x14, - 0xc4, 0x0d, 0xd3, 0xe6, 0x0f, 0x0f, 0x0b, 0xdd, 0x54, 0x59, 0x33, 0x4b, 0x09, 0x92, 0x08, 0x14, - 0x82, 0x5c, 0x52, 0xba, 0xfa, 0xcb, 0xb9, 0xfe, 0xfd, 0x85, 0x0d, 0xe3, 0x3a, 0xcb, 0x57, 0x62, - 0x30, 0xe9, 0xeb, 0xbd, 0x81, 0x2d, 0x52, 0x2f, 0x07, 0x5c, 0x1f, 0xf9, 0x84, 0xe4, 0xfd, 0x5d, - 0xdc, 0xe5, 0xdd, 0x10, 0x9f, 0x33, 0x4d, 0x54, 0x80, 0x14, 0x7b, 0x48, 0x68, 0x30, 0x7f, 0x49, - 0x28, 0x6e, 0x9b, 0xf4, 0xd9, 0xc6, 0xb6, 0x73, 0x53, 0xb5, 0xdc, 0xd7, 0x40, 0x44, 0x5b, 0x3e, - 0x0f, 0xe9, 0x79, 0x43, 0xb7, 0xb1, 0x6e, 0xb7, 0x68, 0xe8, 0x6c, 0x35, 0x8c, 0xea, 0x75, 0xce, - 0x81, 0x35, 0x88, 0xc1, 0x55, 0xd3, 0xa4, 0x94, 0x09, 0x85, 0xfc, 0x64, 0xa9, 0xb7, 0xb4, 0xd1, - 0xd5, 0x44, 0xe7, 0xfb, 0x37, 0x11, 0x57, 0xd2, 0xb5, 0xd1, 0x1f, 0x48, 0x70, 0xac, 0x3d, 0xa0, - 0xae, 0xe3, 0x3d, 0xbb, 0xdf, 0x78, 0x3a, 0x07, 0xe9, 0x75, 0xfa, 0x2e, 0xe6, 0x15, 0xbc, 0x87, - 0x0a, 0x30, 0x88, 0x6b, 0xa7, 0xce, 0x9c, 0x79, 0xfc, 0x3c, 0xf3, 0xf6, 0x4b, 0x87, 0x14, 0x01, - 0x28, 0xa6, 0x88, 0x56, 0x6f, 0x7c, 0x65, 0x4a, 0x2a, 0x25, 0x21, 0x6e, 0xb7, 0x9a, 0x77, 0xd5, - 0x07, 0xbe, 0x90, 0x0c, 0x24, 0x40, 0x96, 0x51, 0x6f, 0xa8, 0x0d, 0xad, 0xa6, 0x7a, 0x6f, 0xc9, - 0xe6, 0x7c, 0x3a, 0x52, 0x8c, 0xce, 0x2a, 0x16, 0xf6, 0xb5, 0x94, 0xfc, 0x2b, 0x12, 0x64, 0xaf, - 0x09, 0xce, 0x1b, 0xd8, 0x41, 0x17, 0x00, 0xdc, 0x91, 0x44, 0x58, 0x1c, 0x9d, 0x09, 0x8f, 0x35, - 0xe3, 0xd2, 0x28, 0x3e, 0x74, 0xf4, 0x24, 0x75, 0x34, 0xd3, 0xb0, 0xf9, 0x3b, 0x02, 0x11, 0xa4, - 0x2e, 0x32, 0x7a, 0x04, 0x10, 0xcd, 0x60, 0x95, 0x1b, 0x86, 0xa3, 0xe9, 0xf5, 0x8a, 0x69, 0xdc, - 0xe4, 0x2f, 0x54, 0xc5, 0x95, 0x1c, 0xed, 0xb9, 0x46, 0x3b, 0xd6, 0x09, 0x9c, 0x08, 0x9d, 0x76, - 0xb9, 0x90, 0xf5, 0x4f, 0xad, 0xd5, 0x2c, 0x6c, 0xdb, 0x3c, 0x49, 0x89, 0x26, 0xba, 0x00, 0x83, - 0x66, 0x6b, 0xab, 0x22, 0x32, 0x42, 0xe6, 0xd4, 0xb1, 0x4e, 0xf1, 0x2d, 0xe6, 0x9f, 0x47, 0xf8, - 0x80, 0xd9, 0xda, 0x22, 0xde, 0x70, 0x2f, 0x64, 0x3b, 0x08, 0x93, 0xb9, 0xe1, 0xc9, 0x41, 0x5f, - 0xf1, 0xe5, 0x1a, 0x54, 0x4c, 0x4b, 0x33, 0x2c, 0xcd, 0xd9, 0xa3, 0x4f, 0xf8, 0xe3, 0x4a, 0x4e, - 0x74, 0xac, 0x73, 0xb8, 0x7c, 0x1d, 0x46, 0x36, 0xb4, 0xa6, 0x49, 0xef, 0xa4, 0x70, 0xc9, 0xcf, - 0x78, 0xf2, 0x49, 0xd1, 0xf2, 0x75, 0x95, 0x2c, 0xd6, 0x26, 0x59, 0xe9, 0x99, 0xae, 0xde, 0xf9, - 0x64, 0xff, 0xde, 0x19, 0x2c, 0x58, 0xfe, 0xb4, 0x10, 0x08, 0x3e, 0xbe, 0xdc, 0xfb, 0xd2, 0x53, - 0xaf, 0x8e, 0x19, 0x55, 0xf6, 0x14, 0x22, 0x8b, 0x80, 0xc2, 0xfe, 0xcb, 0x6a, 0x21, 0x22, 0x91, - 0x16, 0x22, 0x83, 0x4c, 0x3e, 0x0f, 0x43, 0xeb, 0xaa, 0xe5, 0x6c, 0x60, 0xe7, 0x12, 0x56, 0x6b, - 0xd8, 0x0a, 0xae, 0xbb, 0x43, 0x62, 0xdd, 0x45, 0x90, 0xa0, 0x8b, 0x2b, 0x5b, 0x77, 0xe8, 0x6f, - 0x79, 0x07, 0x12, 0xf4, 0x1e, 0x90, 0xbb, 0x26, 0x73, 0x0a, 0xb6, 0x26, 0x93, 0x6c, 0xba, 0xe7, - 0x60, 0x9b, 0x93, 0xb0, 0x06, 0x3a, 0x2d, 0x56, 0xd6, 0xf8, 0xfe, 0x2b, 0x2b, 0x77, 0x55, 0xbe, - 0xbe, 0x36, 0x60, 0xb0, 0x44, 0x92, 0xf1, 0xd2, 0x82, 0x2b, 0x88, 0xe4, 0x09, 0x82, 0x56, 0x60, - 0xc4, 0x54, 0x2d, 0x87, 0x5e, 0x80, 0xde, 0xa1, 0x5a, 0xf0, 0x68, 0x98, 0x6a, 0x8f, 0xcd, 0x80, - 0xb2, 0x7c, 0x94, 0x21, 0xd3, 0x0f, 0x94, 0xff, 0x38, 0x01, 0x03, 0xdc, 0x18, 0xef, 0x86, 0x41, - 0x6e, 0x56, 0xee, 0xbf, 0xc7, 0x67, 0xda, 0x97, 0xa6, 0x19, 0x77, 0x09, 0xe1, 0xfc, 0x04, 0x0d, - 0x7a, 0x00, 0x52, 0xd5, 0x1d, 0x55, 0xd3, 0x2b, 0x5a, 0x4d, 0xd4, 0xf2, 0xaf, 0xdd, 0x9a, 0x1a, - 0x9c, 0x27, 0xb0, 0xa5, 0x05, 0x65, 0x90, 0x76, 0x2e, 0xd5, 0x48, 0x2d, 0xb0, 0x83, 0xb5, 0xfa, - 0x8e, 0xc3, 0x63, 0x90, 0xb7, 0xd0, 0x39, 0x48, 0x10, 0x97, 0xe1, 0xef, 0xc7, 0x14, 0xda, 0xf6, - 0x58, 0x6e, 0xdd, 0x5a, 0x4a, 0x91, 0x81, 0x3f, 0xfd, 0x87, 0x53, 0x92, 0x42, 0x29, 0xd0, 0x3c, - 0x0c, 0x35, 0x54, 0xdb, 0xa9, 0xd0, 0x35, 0x8c, 0x0c, 0x9f, 0xa4, 0x2c, 0x8e, 0xb4, 0x1b, 0x84, - 0x1b, 0x96, 0x8b, 0x9e, 0x21, 0x54, 0x0c, 0x54, 0x43, 0x27, 0x20, 0x47, 0x99, 0x54, 0x8d, 0x66, - 0x53, 0x73, 0x58, 0x75, 0x35, 0x40, 0xed, 0x3e, 0x4c, 0xe0, 0xf3, 0x14, 0x4c, 0x6b, 0xac, 0xa3, - 0x90, 0xa6, 0x17, 0xf2, 0x29, 0x0a, 0xbb, 0x7c, 0x96, 0x22, 0x00, 0xda, 0xf9, 0x20, 0x8c, 0x78, - 0x19, 0x94, 0xa1, 0xa4, 0x18, 0x17, 0x0f, 0x4c, 0x11, 0x1f, 0x83, 0x71, 0x1d, 0xef, 0xd2, 0xeb, - 0x70, 0x01, 0xec, 0x34, 0xc5, 0x46, 0xa4, 0xef, 0x5a, 0x90, 0xe2, 0x5d, 0x30, 0x5c, 0x15, 0xc6, - 0x67, 0xb8, 0x40, 0x71, 0x87, 0x5c, 0x28, 0x45, 0x3b, 0x02, 0x29, 0xd5, 0x34, 0x19, 0x42, 0x86, - 0x67, 0x50, 0xd3, 0xa4, 0x5d, 0x27, 0x61, 0x94, 0xea, 0x68, 0x61, 0xbb, 0xd5, 0x70, 0x38, 0x93, - 0x2c, 0xc5, 0x19, 0x21, 0x1d, 0x0a, 0x83, 0x53, 0xdc, 0xfb, 0x60, 0x08, 0xdf, 0xd0, 0x6a, 0x58, - 0xaf, 0x62, 0x86, 0x37, 0x44, 0xf1, 0xb2, 0x02, 0x48, 0x91, 0x1e, 0x02, 0x37, 0x33, 0x56, 0x44, - 0xd6, 0x1e, 0x66, 0xfc, 0x04, 0x7c, 0x8e, 0x81, 0xe5, 0x47, 0x20, 0xb1, 0xa0, 0x3a, 0x2a, 0x29, - 0x31, 0x9c, 0x5d, 0xb6, 0x14, 0x65, 0x15, 0xf2, 0xb3, 0x63, 0xb8, 0xbd, 0x11, 0x83, 0xc4, 0x35, - 0xc3, 0xc1, 0xe8, 0x09, 0x5f, 0x59, 0x38, 0xdc, 0xc9, 0xc7, 0x37, 0xb4, 0xba, 0x8e, 0x6b, 0x2b, - 0x76, 0xdd, 0xf7, 0xa6, 0xac, 0xe7, 0x62, 0xb1, 0x80, 0x8b, 0x8d, 0x43, 0xd2, 0x32, 0x5a, 0x7a, - 0x4d, 0xdc, 0xe5, 0xa2, 0x0d, 0x54, 0x86, 0x94, 0xeb, 0x39, 0x89, 0x28, 0xcf, 0x19, 0x21, 0x9e, - 0x43, 0xfc, 0x9a, 0x03, 0x94, 0xc1, 0x2d, 0xee, 0x40, 0x25, 0x48, 0xbb, 0x29, 0x8f, 0x7b, 0x60, - 0x6f, 0x4e, 0xec, 0x91, 0x91, 0x25, 0xc8, 0xf5, 0x07, 0xd7, 0xa0, 0xcc, 0x0b, 0x73, 0x6e, 0x07, - 0xb7, 0x68, 0xc0, 0xd5, 0xf8, 0x5b, 0xbb, 0x83, 0x54, 0x2f, 0xcf, 0xd5, 0xd8, 0x9b, 0xbb, 0xc7, - 0x20, 0x6d, 0x6b, 0x75, 0x5d, 0x75, 0x5a, 0x16, 0xe6, 0xde, 0xe8, 0x01, 0xe4, 0xcf, 0xc4, 0x60, - 0x80, 0x79, 0xb7, 0xcf, 0x6e, 0x52, 0x67, 0xbb, 0xc5, 0xba, 0xd9, 0x2d, 0x7e, 0x70, 0xbb, 0xcd, - 0x01, 0xb8, 0xc2, 0xd8, 0xfc, 0xad, 0xcb, 0x0e, 0x75, 0x06, 0x13, 0x71, 0x43, 0xab, 0xf3, 0xe0, - 0xf5, 0x11, 0xb9, 0x1e, 0x94, 0xf4, 0xe5, 0xc9, 0x0b, 0x90, 0xde, 0xd2, 0x9c, 0x8a, 0x4a, 0x36, - 0x8f, 0xd4, 0x84, 0x99, 0x53, 0x93, 0x33, 0x9d, 0x76, 0x99, 0x33, 0x62, 0x8b, 0xa9, 0xa4, 0xb6, - 0xf8, 0x2f, 0xf9, 0x0f, 0x24, 0x52, 0x2b, 0xf3, 0x01, 0xd1, 0x1c, 0x0c, 0x09, 0x45, 0x2b, 0xdb, - 0x0d, 0xb5, 0xce, 0x9d, 0xf1, 0x78, 0x57, 0x6d, 0x2f, 0x36, 0xd4, 0xba, 0x92, 0xe1, 0x0a, 0x92, - 0x46, 0xe7, 0x89, 0x8d, 0x75, 0x99, 0xd8, 0x80, 0x27, 0xc5, 0x0f, 0xe6, 0x49, 0x81, 0x39, 0x4f, - 0x84, 0xe7, 0xfc, 0x1b, 0x31, 0xba, 0x67, 0x32, 0x0d, 0x5b, 0x6d, 0xbc, 0x1d, 0x21, 0x76, 0x14, - 0xd2, 0xa6, 0xd1, 0xa8, 0xb0, 0x1e, 0x76, 0x69, 0x32, 0x65, 0x1a, 0x0d, 0xa5, 0xcd, 0x8f, 0x92, - 0x77, 0x28, 0xfe, 0x06, 0xee, 0x80, 0xd5, 0x06, 0xc3, 0x56, 0xb3, 0x20, 0xcb, 0x4c, 0xc1, 0x17, - 0xcc, 0xc7, 0x88, 0x0d, 0xe8, 0x0a, 0x2c, 0xb5, 0x2f, 0xf0, 0x4c, 0x6c, 0x86, 0xa9, 0x70, 0x3c, - 0x42, 0xc1, 0xd6, 0x97, 0x4e, 0x9b, 0x6d, 0xbf, 0x9f, 0x2b, 0x1c, 0x4f, 0xfe, 0x69, 0x09, 0x60, - 0x99, 0x58, 0x96, 0xea, 0x4b, 0x96, 0x3a, 0x9b, 0x8a, 0x50, 0x09, 0x8c, 0x3c, 0xd9, 0x6d, 0xd2, - 0xf8, 0xf8, 0x59, 0xdb, 0x2f, 0xf7, 0x3c, 0x0c, 0x79, 0xce, 0x68, 0x63, 0x21, 0xcc, 0xe4, 0x3e, - 0xc5, 0xfd, 0x06, 0x76, 0x94, 0xec, 0x0d, 0x5f, 0x4b, 0xfe, 0xa7, 0x12, 0xa4, 0xa9, 0x4c, 0x2b, - 0xd8, 0x51, 0x03, 0x73, 0x28, 0x1d, 0x7c, 0x0e, 0x8f, 0x03, 0x30, 0x36, 0xb6, 0xf6, 0x3c, 0xe6, - 0x9e, 0x95, 0xa6, 0x90, 0x0d, 0xed, 0x79, 0x8c, 0xce, 0xba, 0x06, 0x8f, 0xef, 0x6f, 0x70, 0x51, - 0xfc, 0x73, 0xb3, 0xdf, 0x03, 0x83, 0xf4, 0x6b, 0x26, 0xbb, 0x36, 0xaf, 0xe7, 0x07, 0xf4, 0x56, - 0x73, 0x73, 0xd7, 0x96, 0x9f, 0x83, 0xc1, 0xcd, 0x5d, 0x76, 0x04, 0x73, 0x14, 0xd2, 0x96, 0x61, - 0xf0, 0x85, 0x9f, 0x15, 0x5c, 0x29, 0x02, 0xa0, 0xeb, 0x9c, 0x38, 0x76, 0x88, 0x79, 0xc7, 0x0e, - 0xde, 0xb9, 0x49, 0xbc, 0xa7, 0x73, 0x93, 0x93, 0xff, 0x46, 0x82, 0x8c, 0x2f, 0x3f, 0xa0, 0xc7, - 0xe1, 0x70, 0x69, 0x79, 0x6d, 0xfe, 0x4a, 0x65, 0x69, 0xa1, 0x72, 0x71, 0x79, 0x6e, 0xd1, 0x7b, - 0x2d, 0xa0, 0x30, 0xf1, 0xe2, 0x4b, 0xd3, 0xc8, 0x87, 0x7b, 0x55, 0xbf, 0xae, 0x1b, 0x37, 0x75, - 0x34, 0x0b, 0xe3, 0x41, 0x92, 0xb9, 0xd2, 0x46, 0x79, 0x75, 0x33, 0x27, 0x15, 0x0e, 0xbf, 0xf8, - 0xd2, 0xf4, 0xa8, 0x8f, 0x62, 0x6e, 0xcb, 0xc6, 0xba, 0xd3, 0x4e, 0x30, 0xbf, 0xb6, 0xb2, 0xb2, - 0xb4, 0x99, 0x8b, 0xb5, 0x11, 0xf0, 0x15, 0xe0, 0x21, 0x18, 0x0d, 0x12, 0xac, 0x2e, 0x2d, 0xe7, - 0xe2, 0x05, 0xf4, 0xe2, 0x4b, 0xd3, 0xc3, 0x3e, 0xec, 0x55, 0xad, 0x51, 0x48, 0x7d, 0xe2, 0xab, - 0x93, 0x87, 0x7e, 0xee, 0x67, 0x27, 0x25, 0xa2, 0xd9, 0x50, 0x20, 0x47, 0xa0, 0x47, 0xe0, 0x9e, - 0x8d, 0xa5, 0xc5, 0xd5, 0xf2, 0x42, 0x65, 0x65, 0x63, 0xb1, 0xc2, 0xbe, 0x87, 0xe0, 0x6a, 0x37, - 0xf2, 0xe2, 0x4b, 0xd3, 0x19, 0xae, 0x52, 0x37, 0xec, 0x75, 0xa5, 0x7c, 0x6d, 0x6d, 0xb3, 0x9c, - 0x93, 0x18, 0xf6, 0xba, 0x85, 0x6f, 0x18, 0x0e, 0xfb, 0xdc, 0xd1, 0x63, 0x70, 0xa4, 0x03, 0xb6, - 0xab, 0xd8, 0xe8, 0x8b, 0x2f, 0x4d, 0x0f, 0xad, 0x5b, 0x98, 0xc5, 0x0f, 0xa5, 0x98, 0x81, 0x7c, - 0x3b, 0xc5, 0xda, 0xfa, 0xda, 0xc6, 0xdc, 0x72, 0x6e, 0xba, 0x90, 0x7b, 0xf1, 0xa5, 0xe9, 0xac, - 0x48, 0x86, 0x04, 0xdf, 0xd3, 0xec, 0x6e, 0x6e, 0xbc, 0xfe, 0x6a, 0x0c, 0x26, 0xdb, 0x2e, 0x5f, - 0xf3, 0x47, 0x16, 0xdd, 0x0e, 0x8a, 0x8b, 0x90, 0x5a, 0x10, 0x4f, 0x42, 0xfa, 0x3d, 0x27, 0xfe, - 0xa9, 0x3e, 0xcf, 0x89, 0x87, 0xc4, 0x48, 0xe2, 0x98, 0xf8, 0x64, 0xf4, 0x31, 0xb1, 0x90, 0xff, - 0x00, 0xa7, 0xc4, 0xff, 0xe1, 0x61, 0xb8, 0x9f, 0x1f, 0xae, 0xdb, 0x8e, 0x7a, 0x5d, 0xd3, 0xeb, - 0xee, 0x23, 0x0c, 0xde, 0xe6, 0x46, 0x99, 0xe0, 0x4f, 0x31, 0x04, 0x74, 0xdf, 0x07, 0x19, 0x85, - 0x7d, 0xf7, 0xb6, 0xd1, 0x7b, 0xd6, 0x88, 0x19, 0x2a, 0x44, 0x3c, 0x72, 0x91, 0x3f, 0x29, 0xc1, - 0xf0, 0x25, 0xcd, 0x76, 0x0c, 0x4b, 0xab, 0xaa, 0x0d, 0xfa, 0x96, 0xc3, 0xd9, 0x5e, 0x17, 0x8d, - 0x50, 0x0e, 0x7b, 0x1a, 0x06, 0x6e, 0xa8, 0x0d, 0x96, 0xad, 0xe3, 0xf4, 0xab, 0x0c, 0x9d, 0x0d, - 0xe1, 0xe5, 0x6c, 0xc1, 0x80, 0x91, 0xc9, 0xbf, 0x18, 0x83, 0x11, 0x1a, 0xe5, 0x36, 0xfb, 0x0c, - 0x0f, 0xd9, 0xa1, 0x96, 0x20, 0x61, 0xa9, 0x0e, 0x3f, 0x74, 0x2d, 0xcd, 0xf0, 0x87, 0x23, 0x0f, - 0x44, 0x3f, 0xf0, 0x98, 0x59, 0xc0, 0x55, 0x85, 0xd2, 0xa2, 0x1f, 0x86, 0x54, 0x53, 0xdd, 0xad, - 0x50, 0x3e, 0x6c, 0xdf, 0x37, 0xd7, 0x1f, 0x9f, 0xdb, 0xb7, 0xa6, 0x46, 0xf6, 0xd4, 0x66, 0xa3, - 0x28, 0x0b, 0x3e, 0xb2, 0x32, 0xd8, 0x54, 0x77, 0x89, 0x88, 0xc8, 0x84, 0x11, 0x02, 0xad, 0xee, - 0xa8, 0x7a, 0x1d, 0xb3, 0x41, 0xe8, 0x11, 0x72, 0xe9, 0x52, 0xdf, 0x83, 0x4c, 0x78, 0x83, 0xf8, - 0xd8, 0xc9, 0xca, 0x50, 0x53, 0xdd, 0x9d, 0xa7, 0x00, 0x32, 0x62, 0x31, 0xf5, 0xb9, 0x97, 0xa7, - 0x0e, 0xd1, 0x07, 0x4e, 0xaf, 0x4a, 0x00, 0x9e, 0xc5, 0xd0, 0x0f, 0x43, 0xae, 0xea, 0xb6, 0x28, - 0xad, 0xcd, 0xe7, 0xf0, 0xc1, 0x6e, 0x73, 0x11, 0xb2, 0x37, 0x2b, 0x3a, 0x5e, 0xb9, 0x35, 0x25, - 0x29, 0x23, 0xd5, 0xd0, 0x54, 0x7c, 0x00, 0x32, 0x2d, 0xb3, 0xa6, 0x3a, 0xb8, 0x42, 0x77, 0xc1, - 0xb1, 0xc8, 0x02, 0x66, 0x92, 0xf0, 0xba, 0x7d, 0x6b, 0x0a, 0x31, 0xb5, 0x7c, 0xc4, 0x32, 0x2d, - 0x6b, 0x80, 0x41, 0x08, 0x81, 0x4f, 0xa7, 0xdf, 0x96, 0x20, 0xb3, 0xe0, 0xbb, 0x6d, 0x94, 0x87, - 0xc1, 0xa6, 0xa1, 0x6b, 0xd7, 0xb9, 0x3f, 0xa6, 0x15, 0xd1, 0x44, 0x05, 0x48, 0xb1, 0x17, 0xbf, - 0x9c, 0x3d, 0x71, 0x94, 0x2c, 0xda, 0x84, 0xea, 0x26, 0xde, 0xb2, 0x35, 0x31, 0x1b, 0x8a, 0x68, - 0xa2, 0x8b, 0x90, 0xb3, 0x71, 0xb5, 0x65, 0x69, 0xce, 0x5e, 0xa5, 0x6a, 0xe8, 0x8e, 0x5a, 0x75, - 0xd8, 0x2b, 0x44, 0xa5, 0xa3, 0xb7, 0x6f, 0x4d, 0xdd, 0xc3, 0x64, 0x0d, 0x63, 0xc8, 0xca, 0x88, - 0x00, 0xcd, 0x33, 0x08, 0x19, 0xa1, 0x86, 0x1d, 0x55, 0x6b, 0xd8, 0xb4, 0x26, 0x4c, 0x2b, 0xa2, - 0xe9, 0xd3, 0xe5, 0x27, 0x06, 0xfd, 0x07, 0x87, 0x17, 0x21, 0x67, 0x98, 0xd8, 0x0a, 0x54, 0xd8, - 0x52, 0x78, 0xe4, 0x30, 0x86, 0xac, 0x8c, 0x08, 0x90, 0xa8, 0xbe, 0x2f, 0x92, 0x69, 0x16, 0xdb, - 0x6c, 0xb3, 0xb5, 0x25, 0xce, 0x1b, 0x03, 0x7c, 0xc2, 0x18, 0x32, 0x99, 0x50, 0x0e, 0x5a, 0xa7, - 0x10, 0x52, 0x21, 0x3f, 0xa7, 0x6a, 0x0d, 0xf1, 0x72, 0xab, 0xc2, 0x5b, 0x68, 0x09, 0x06, 0x6c, - 0x47, 0x75, 0x5a, 0xac, 0x16, 0x49, 0x96, 0x1e, 0xff, 0xdf, 0xb7, 0xa6, 0x1e, 0xed, 0xc1, 0x89, - 0x4b, 0x86, 0x5e, 0xdb, 0xa0, 0x84, 0x0a, 0x67, 0x80, 0x2e, 0xc2, 0x80, 0x63, 0x5c, 0xc7, 0x3a, - 0xb7, 0x51, 0x5f, 0x01, 0x4c, 0x9f, 0xd5, 0x32, 0x6a, 0xe4, 0x40, 0xae, 0x86, 0x1b, 0xb8, 0xce, - 0x0a, 0xc2, 0x1d, 0x95, 0x6c, 0xc4, 0xe8, 0x07, 0xa6, 0x4a, 0x4b, 0x7d, 0x47, 0x19, 0x37, 0x50, - 0x98, 0x9f, 0xac, 0x8c, 0xb8, 0xa0, 0x0d, 0x0a, 0x41, 0x57, 0x02, 0xf7, 0xde, 0xf8, 0x57, 0xd8, - 0xee, 0xeb, 0x16, 0x4a, 0x3e, 0xa7, 0x15, 0xc7, 0x37, 0xfe, 0x5b, 0x73, 0x17, 0x21, 0xd7, 0xd2, - 0xb7, 0x0c, 0x9d, 0xbe, 0x90, 0xc6, 0x77, 0x26, 0x64, 0xab, 0x1b, 0xf7, 0xcf, 0x5a, 0x18, 0x43, - 0x56, 0x46, 0x5c, 0xd0, 0x25, 0xb6, 0x7f, 0xa9, 0xc1, 0xb0, 0x87, 0x45, 0x23, 0x31, 0x1d, 0x19, - 0x89, 0xf7, 0xf2, 0x48, 0x3c, 0x1c, 0x1e, 0xc5, 0x0b, 0xc6, 0x21, 0x17, 0x48, 0xc8, 0xd0, 0x25, - 0x00, 0x2f, 0xfe, 0xe9, 0x31, 0x4e, 0xe6, 0x94, 0x1c, 0x9d, 0x44, 0xc4, 0xd6, 0xd7, 0xa3, 0x45, - 0x1f, 0x86, 0xb1, 0xa6, 0xa6, 0x57, 0x6c, 0xdc, 0xd8, 0xae, 0x70, 0x03, 0x13, 0x96, 0xf4, 0x83, - 0x22, 0xa5, 0xe5, 0xfe, 0xfc, 0xe1, 0xf6, 0xad, 0xa9, 0x02, 0xcf, 0x91, 0xed, 0x2c, 0x65, 0x65, - 0xb4, 0xa9, 0xe9, 0x1b, 0xb8, 0xb1, 0xbd, 0xe0, 0xc2, 0x8a, 0xd9, 0x4f, 0xbc, 0x3c, 0x75, 0x88, - 0xc7, 0xe3, 0x21, 0xf9, 0x2c, 0x7d, 0xf8, 0xc0, 0xe3, 0x08, 0xdb, 0x64, 0x37, 0xa5, 0x8a, 0x06, - 0x3d, 0xf0, 0x49, 0x2b, 0x1e, 0x80, 0xc5, 0xf1, 0x0b, 0xff, 0x6e, 0x5a, 0x92, 0x7f, 0x41, 0x82, - 0x81, 0x85, 0x6b, 0xeb, 0xaa, 0x66, 0xa1, 0x25, 0x18, 0xf5, 0x3c, 0x27, 0x18, 0xc5, 0xc7, 0x6e, - 0xdf, 0x9a, 0xca, 0x87, 0x9d, 0xcb, 0x0d, 0x63, 0xcf, 0x81, 0x45, 0x1c, 0x2f, 0x75, 0xdb, 0x72, - 0x07, 0x58, 0xb5, 0xa1, 0xc8, 0xed, 0x1b, 0xf2, 0x90, 0x9a, 0x65, 0x18, 0x64, 0xd2, 0xda, 0xa8, - 0x08, 0x49, 0x93, 0xfc, 0xe0, 0x4f, 0x56, 0x26, 0xbb, 0x3a, 0x2f, 0xc5, 0x77, 0xcf, 0x79, 0x09, - 0x89, 0xfc, 0x99, 0x18, 0xc0, 0xc2, 0xb5, 0x6b, 0x9b, 0x96, 0x66, 0x36, 0xb0, 0x73, 0x27, 0x35, - 0xdf, 0x84, 0xc3, 0xbe, 0xfd, 0x9d, 0x55, 0x0d, 0x69, 0x3f, 0x7d, 0xfb, 0xd6, 0xd4, 0xb1, 0xb0, - 0xf6, 0x3e, 0x34, 0x59, 0x19, 0xf3, 0x76, 0x7a, 0x56, 0xb5, 0x23, 0xd7, 0x9a, 0xed, 0xb8, 0x5c, - 0xe3, 0xdd, 0xb9, 0xfa, 0xd0, 0xfc, 0x5c, 0x17, 0x6c, 0xa7, 0xb3, 0x69, 0x37, 0x20, 0xe3, 0x99, - 0xc4, 0x46, 0x0b, 0x90, 0x72, 0xf8, 0x6f, 0x6e, 0x61, 0xb9, 0xbb, 0x85, 0x05, 0x19, 0xb7, 0xb2, - 0x4b, 0x29, 0xff, 0x99, 0x04, 0xe0, 0xf9, 0xec, 0x0f, 0xa6, 0x8b, 0x91, 0x54, 0xce, 0x13, 0x6f, - 0xfc, 0x40, 0xb5, 0x18, 0xa7, 0x0e, 0xd9, 0xf3, 0xc7, 0x63, 0x30, 0x76, 0x55, 0x64, 0x9e, 0x1f, - 0x78, 0x1b, 0xac, 0xc3, 0x20, 0xd6, 0x1d, 0x4b, 0xa3, 0x46, 0x20, 0xb3, 0xfd, 0x58, 0xb7, 0xd9, - 0xee, 0xa0, 0x13, 0xfd, 0xa2, 0x8a, 0x78, 0x26, 0xc1, 0xd9, 0x84, 0xac, 0xf1, 0xa9, 0x38, 0xe4, - 0xbb, 0x51, 0xa2, 0x79, 0x18, 0xa9, 0x5a, 0x98, 0x02, 0x2a, 0xfe, 0x43, 0xd0, 0x52, 0xc1, 0x2b, - 0x1d, 0x43, 0x08, 0xb2, 0x32, 0x2c, 0x20, 0x7c, 0xf5, 0xa8, 0x03, 0xa9, 0xeb, 0x88, 0xdb, 0x11, - 0xac, 0x1e, 0x0b, 0x39, 0x99, 0x2f, 0x1f, 0x62, 0x90, 0x20, 0x03, 0xb6, 0x7e, 0x0c, 0x7b, 0x50, - 0xba, 0x80, 0x7c, 0x10, 0x46, 0x34, 0x5d, 0x73, 0x34, 0xb5, 0x51, 0xd9, 0x52, 0x1b, 0xaa, 0x5e, - 0x3d, 0x48, 0x59, 0xcc, 0x52, 0x3e, 0x1f, 0x36, 0xc4, 0x4e, 0x56, 0x86, 0x39, 0xa4, 0xc4, 0x00, - 0xe8, 0x12, 0x0c, 0x8a, 0xa1, 0x12, 0x07, 0xaa, 0x36, 0x04, 0xb9, 0xbf, 0x82, 0x8b, 0xc3, 0xa8, - 0x82, 0x6b, 0xff, 0x7f, 0x2a, 0xfa, 0x9b, 0x8a, 0x15, 0x00, 0x16, 0xee, 0x24, 0xc1, 0x1e, 0x60, - 0x36, 0x48, 0xc2, 0x48, 0x33, 0x0e, 0x0b, 0xb6, 0xe3, 0x9b, 0x8f, 0x5b, 0x31, 0xc8, 0xfa, 0xe7, - 0xe3, 0x2f, 0xe8, 0xaa, 0x84, 0x96, 0xbc, 0x4c, 0x94, 0xe0, 0x1f, 0xa2, 0xec, 0x92, 0x89, 0xda, - 0xbc, 0x77, 0xff, 0x14, 0xf4, 0xa7, 0x31, 0x18, 0x58, 0x57, 0x2d, 0xb5, 0x69, 0xa3, 0x6a, 0x5b, - 0xa5, 0x29, 0x0e, 0x4e, 0xdb, 0xbe, 0x22, 0xcc, 0x0f, 0x1d, 0x22, 0x0a, 0xcd, 0xcf, 0x75, 0x28, - 0x34, 0xdf, 0x03, 0xc3, 0x64, 0xbf, 0xeb, 0xbb, 0x03, 0x42, 0xac, 0x3d, 0x54, 0x3a, 0xe2, 0x71, - 0x09, 0xf6, 0xb3, 0xed, 0xf0, 0x35, 0xff, 0x25, 0x90, 0x0c, 0xc1, 0xf0, 0x12, 0x33, 0x21, 0x9f, - 0xf0, 0xf6, 0x9d, 0xbe, 0x4e, 0x59, 0x81, 0xa6, 0xba, 0x5b, 0x66, 0x0d, 0xb4, 0x0c, 0x68, 0xc7, - 0x3d, 0xfa, 0xa8, 0x78, 0xe6, 0x24, 0xf4, 0xc7, 0x6f, 0xdf, 0x9a, 0x3a, 0xc2, 0xe8, 0xdb, 0x71, - 0x64, 0x65, 0xd4, 0x03, 0x0a, 0x6e, 0xa7, 0x01, 0x88, 0x5e, 0x15, 0x76, 0x85, 0x94, 0x6d, 0x77, - 0x0e, 0xdf, 0xbe, 0x35, 0x35, 0xca, 0xb8, 0x78, 0x7d, 0xb2, 0x92, 0x26, 0x8d, 0x05, 0xf2, 0xdb, - 0xe7, 0xd9, 0x5f, 0x95, 0x00, 0x79, 0x29, 0x5f, 0xc1, 0xb6, 0x49, 0xb6, 0x6b, 0xa4, 0x10, 0xf7, - 0x55, 0xcd, 0xd2, 0xfe, 0x85, 0xb8, 0x47, 0x2f, 0x0a, 0x71, 0x5f, 0xa4, 0x9c, 0xf7, 0xd2, 0x63, - 0x8c, 0xcf, 0x63, 0x87, 0xfb, 0xb6, 0x33, 0xf3, 0x86, 0x26, 0xa8, 0xdb, 0xf2, 0xe1, 0x21, 0xf9, - 0x5f, 0x4a, 0x70, 0xa4, 0xcd, 0xa3, 0x5c, 0x61, 0xff, 0x12, 0x20, 0xcb, 0xd7, 0xc9, 0x3f, 0x2a, - 0xc6, 0x84, 0xee, 0xdb, 0x41, 0x47, 0xad, 0xb6, 0xbc, 0x7b, 0xe7, 0x32, 0x3c, 0xbb, 0xb0, 0xfb, - 0x4f, 0x24, 0x18, 0xf7, 0x0f, 0xef, 0x2a, 0xb2, 0x0a, 0x59, 0xff, 0xe8, 0x5c, 0x85, 0xfb, 0x7b, - 0x51, 0x81, 0x4b, 0x1f, 0xa0, 0x47, 0xcf, 0x78, 0xe1, 0xca, 0x0e, 0xc7, 0x1e, 0xef, 0xd9, 0x1a, - 0x42, 0xa6, 0x70, 0xd8, 0x26, 0xe8, 0x7c, 0xfc, 0x1f, 0x09, 0x12, 0xeb, 0x86, 0xd1, 0x40, 0x06, - 0x8c, 0xea, 0x86, 0x53, 0x21, 0x9e, 0x85, 0x6b, 0x15, 0xbe, 0xe9, 0x66, 0x79, 0x70, 0xbe, 0x3f, - 0x23, 0x7d, 0xe7, 0xd6, 0x54, 0x3b, 0x2b, 0x65, 0x44, 0x37, 0x9c, 0x12, 0x85, 0x6c, 0xb2, 0x2d, - 0xf9, 0x87, 0x61, 0x28, 0x38, 0x18, 0xcb, 0x92, 0xcf, 0xf6, 0x3d, 0x58, 0x90, 0xcd, 0xed, 0x5b, - 0x53, 0xe3, 0x5e, 0xc4, 0xb8, 0x60, 0x59, 0xc9, 0x6e, 0xf9, 0x46, 0x67, 0xf7, 0xe3, 0xbe, 0xf7, - 0xf2, 0x94, 0x54, 0xba, 0xd8, 0xf5, 0x04, 0xfc, 0x91, 0x7d, 0x45, 0xd8, 0x75, 0x8f, 0x71, 0x83, - 0xc7, 0xde, 0xdf, 0x1c, 0x81, 0xa9, 0x2e, 0xe7, 0xbc, 0xce, 0xee, 0x81, 0x8e, 0x78, 0x23, 0xce, - 0x60, 0x0b, 0x3d, 0x1d, 0x2b, 0xcb, 0x2f, 0x25, 0x00, 0xad, 0xd8, 0xf5, 0x79, 0x52, 0x44, 0xf8, - 0xee, 0x74, 0x85, 0xce, 0x28, 0xa4, 0xb7, 0x74, 0x46, 0xb1, 0x12, 0xd8, 0xf5, 0xc7, 0xfa, 0x3b, - 0x3a, 0xec, 0x79, 0xeb, 0x1f, 0x7f, 0x5b, 0xb6, 0xfe, 0x9d, 0x2b, 0x83, 0xc4, 0x9d, 0xdb, 0x42, - 0x24, 0x0f, 0xb4, 0x85, 0x98, 0x80, 0x01, 0x7e, 0x64, 0xc7, 0x3e, 0x90, 0xce, 0x5b, 0xe8, 0x8c, - 0xf8, 0xae, 0xf4, 0x60, 0x6f, 0xb9, 0x99, 0x61, 0x17, 0x53, 0x9f, 0x10, 0x99, 0xf9, 0xb3, 0x71, - 0xc8, 0xad, 0xd8, 0xf5, 0x72, 0x4d, 0x73, 0xee, 0x92, 0x77, 0x3c, 0xdd, 0x7d, 0x23, 0x85, 0x6e, - 0xdf, 0x9a, 0x1a, 0x66, 0x56, 0xd8, 0x47, 0xf7, 0x26, 0x8c, 0x84, 0xce, 0xa7, 0xb9, 0x2f, 0x2c, - 0x1c, 0xe4, 0x98, 0x3c, 0xc4, 0x4a, 0xa6, 0x75, 0xaf, 0xcf, 0x23, 0xd1, 0x6e, 0x67, 0xf7, 0x63, - 0x2e, 0x70, 0xe9, 0x6e, 0x9e, 0x3a, 0x79, 0xb3, 0xf2, 0xc7, 0x12, 0x64, 0x56, 0x6c, 0xb1, 0x97, - 0xc3, 0x3f, 0xa0, 0xfb, 0xda, 0x27, 0xdd, 0x77, 0x5c, 0xe2, 0xbd, 0x79, 0x9f, 0x78, 0xef, 0xc5, - 0x53, 0xf4, 0x77, 0x62, 0x34, 0x3d, 0x95, 0x70, 0x5d, 0xd3, 0xdd, 0x35, 0x0c, 0xff, 0x45, 0x2d, - 0xcf, 0x3d, 0x83, 0x26, 0x0e, 0x6a, 0xd0, 0x37, 0x24, 0x18, 0x5a, 0xb1, 0xeb, 0x57, 0xf5, 0xda, - 0xff, 0xeb, 0xbe, 0x73, 0xc7, 0x97, 0xf0, 0x7f, 0x16, 0x83, 0x93, 0xfe, 0x35, 0xf7, 0x83, 0x2d, - 0x6c, 0xed, 0xb9, 0xcb, 0xaa, 0xa9, 0xd6, 0x35, 0xdd, 0xff, 0x14, 0xfb, 0x88, 0x5f, 0x60, 0x8a, - 0x2b, 0xc4, 0x96, 0x75, 0xc8, 0xac, 0xab, 0x75, 0xac, 0xe0, 0x0f, 0xb6, 0xb0, 0xed, 0x74, 0x78, - 0x37, 0x65, 0x02, 0x06, 0x8c, 0xed, 0x6d, 0x71, 0x45, 0x25, 0xa1, 0xf0, 0x16, 0x1a, 0x87, 0x64, - 0x43, 0x6b, 0x6a, 0xcc, 0x28, 0x09, 0x85, 0x35, 0xd0, 0x14, 0x64, 0xaa, 0x44, 0xf7, 0x0a, 0xbb, - 0xd3, 0x9b, 0x10, 0xdf, 0xde, 0x68, 0xe9, 0xce, 0x26, 0x81, 0xc8, 0x4f, 0x43, 0x96, 0x8d, 0xc7, - 0xeb, 0xd0, 0x23, 0x90, 0xa2, 0x77, 0x30, 0xbd, 0x51, 0x07, 0x49, 0xfb, 0x0a, 0x7b, 0x8f, 0x85, - 0x71, 0x61, 0x03, 0xb3, 0x46, 0xa9, 0xd4, 0xd5, 0x94, 0x27, 0xa2, 0x93, 0x1d, 0x33, 0x94, 0x6b, - 0xc6, 0xdf, 0x4c, 0xc2, 0x61, 0xfe, 0x78, 0x59, 0x35, 0xb5, 0xd9, 0x1d, 0xc7, 0x11, 0x2f, 0x88, - 0x01, 0xdf, 0x00, 0xaa, 0xa6, 0x26, 0xef, 0x41, 0xe2, 0x92, 0xe3, 0x98, 0xe8, 0x24, 0x24, 0xad, - 0x56, 0x03, 0x8b, 0x73, 0xd0, 0xf1, 0x19, 0x0f, 0x67, 0x86, 0x20, 0x28, 0xad, 0x06, 0x56, 0x18, - 0x0a, 0x2a, 0xc3, 0xd4, 0x76, 0xab, 0xd1, 0xd8, 0xab, 0xd4, 0x30, 0xfd, 0x77, 0x48, 0xee, 0x7f, - 0x1e, 0xc0, 0xbb, 0xa6, 0xaa, 0xbb, 0xc5, 0x47, 0x4a, 0x39, 0x46, 0xd1, 0x16, 0x28, 0x96, 0xf8, - 0xaf, 0x03, 0x65, 0x81, 0x23, 0xff, 0x7e, 0x0c, 0x52, 0x82, 0x35, 0x7d, 0xb1, 0x04, 0x37, 0x70, - 0xd5, 0x31, 0xc4, 0x83, 0x42, 0xb7, 0x8d, 0x10, 0xc4, 0xeb, 0x7c, 0x8a, 0xd2, 0x97, 0x0e, 0x29, - 0xa4, 0x41, 0x60, 0xee, 0xeb, 0x3e, 0x04, 0x66, 0xb6, 0xc8, 0xac, 0x25, 0x4c, 0x43, 0x1c, 0x58, - 0x5c, 0x3a, 0xa4, 0xd0, 0x16, 0xca, 0xc3, 0x00, 0x09, 0x20, 0x87, 0x7d, 0x13, 0x92, 0xc0, 0x79, - 0x1b, 0x4d, 0x40, 0xd2, 0x54, 0x9d, 0x2a, 0xbb, 0x87, 0x4b, 0x3a, 0x58, 0x93, 0xc4, 0x04, 0x7b, - 0x17, 0x37, 0xfc, 0xbf, 0x46, 0x88, 0x31, 0xd8, 0x47, 0xcf, 0x88, 0xdc, 0xeb, 0xaa, 0xe3, 0x60, - 0x4b, 0x27, 0x0c, 0x19, 0x3a, 0x7d, 0x87, 0xcc, 0xa8, 0xed, 0xf1, 0xff, 0x7f, 0x42, 0x7f, 0xf3, - 0xff, 0xcc, 0x40, 0xfd, 0xa1, 0x42, 0x3b, 0xd9, 0xbf, 0x7d, 0xca, 0x0a, 0x60, 0x89, 0x20, 0x95, - 0x61, 0x4c, 0xad, 0xd5, 0x34, 0xe2, 0xd5, 0x6a, 0xa3, 0xb2, 0xa5, 0xd1, 0x0d, 0xb6, 0x4d, 0xff, - 0xa9, 0x57, 0xb7, 0xb9, 0x40, 0x1e, 0x41, 0x89, 0xe3, 0x97, 0xd2, 0x30, 0x68, 0x32, 0xa1, 0xe4, - 0x0b, 0x30, 0xda, 0x26, 0x29, 0x91, 0xef, 0xba, 0xa6, 0xd7, 0xc4, 0x3b, 0x50, 0xe4, 0x37, 0x81, - 0xd1, 0x0f, 0x17, 0xb2, 0x47, 0xb0, 0xf4, 0x77, 0xe9, 0xc7, 0xba, 0xdf, 0xe5, 0x18, 0xf6, 0xdd, - 0xe5, 0x50, 0x4d, 0xad, 0x94, 0xa6, 0xfc, 0xf9, 0x15, 0x8e, 0x39, 0xde, 0xc1, 0xae, 0x6f, 0xcc, - 0x18, 0x56, 0x7d, 0xb6, 0x8e, 0x75, 0x51, 0x51, 0x93, 0x2e, 0xd5, 0xd4, 0x6c, 0xea, 0x8e, 0xde, - 0x87, 0x14, 0xed, 0x0b, 0xbe, 0xdf, 0xf4, 0x66, 0x47, 0x62, 0x71, 0x6e, 0x7d, 0xc9, 0xf5, 0xe3, - 0xdf, 0x88, 0xc1, 0x31, 0x9f, 0x1f, 0xfb, 0x90, 0xdb, 0xdd, 0xb9, 0xd0, 0xd9, 0xe3, 0x7b, 0xf8, - 0x0c, 0xe1, 0x15, 0x48, 0x10, 0x7c, 0x14, 0xf1, 0x7f, 0x13, 0xf2, 0xbf, 0xf4, 0x2f, 0xfe, 0xb1, - 0x4c, 0x9d, 0xa2, 0xf3, 0xac, 0x50, 0x26, 0xa5, 0x8f, 0xf7, 0x6e, 0xbf, 0x9c, 0xf7, 0x0d, 0x49, - 0xfb, 0xce, 0x99, 0x31, 0x6c, 0xc3, 0xd7, 0xcf, 0x80, 0xdc, 0x65, 0x9b, 0xc2, 0x32, 0xe6, 0xfe, - 0x1b, 0xa3, 0x3e, 0xd2, 0x71, 0xb7, 0x7b, 0x32, 0xfb, 0xcd, 0x60, 0x8f, 0x5b, 0xa8, 0x5d, 0x98, - 0x78, 0x86, 0x8c, 0xed, 0x1d, 0x1e, 0x89, 0xc4, 0x3e, 0xe1, 0x3e, 0xf2, 0x96, 0xf8, 0xff, 0x54, - 0x13, 0xcf, 0xaf, 0xc1, 0x93, 0x8f, 0x6f, 0x88, 0x1e, 0x98, 0xe9, 0xba, 0x5e, 0xcc, 0xf8, 0x16, - 0x0b, 0xc5, 0x47, 0x29, 0xff, 0xbc, 0x04, 0xf7, 0xb4, 0x0d, 0xcd, 0x73, 0xfc, 0x62, 0x87, 0x37, - 0xa0, 0x7a, 0xbe, 0x3b, 0xe3, 0x7f, 0x1b, 0x6a, 0xb1, 0x83, 0xb0, 0x0f, 0x46, 0x0a, 0xcb, 0xa4, - 0x08, 0x48, 0xfb, 0x14, 0x1c, 0x0e, 0x0a, 0x2b, 0xcc, 0xf4, 0x2e, 0x18, 0x0e, 0xd6, 0x04, 0xdc, - 0x5c, 0x43, 0x81, 0xaa, 0x40, 0xae, 0x84, 0xed, 0xec, 0xea, 0x5a, 0x86, 0xb4, 0x8b, 0xca, 0x77, - 0x23, 0x3d, 0xab, 0xea, 0x51, 0xca, 0x9f, 0x91, 0x60, 0x3a, 0x38, 0x82, 0x57, 0x7c, 0xdb, 0xfd, - 0x09, 0x7b, 0xc7, 0xa6, 0xf8, 0x0d, 0x09, 0xee, 0xdd, 0x47, 0x26, 0x6e, 0x80, 0xe7, 0x61, 0xdc, - 0x77, 0x3e, 0x26, 0x52, 0xb8, 0x98, 0xf6, 0x93, 0xd1, 0x07, 0x7b, 0xee, 0x71, 0xd0, 0x51, 0x62, - 0x94, 0xaf, 0xff, 0xe1, 0xd4, 0x58, 0x7b, 0x9f, 0xad, 0x8c, 0xb5, 0x9f, 0x69, 0xdd, 0x41, 0xff, - 0xf8, 0x82, 0x04, 0x0f, 0x05, 0x55, 0xed, 0xf0, 0xd0, 0xea, 0x9d, 0x9a, 0x87, 0x7f, 0x2b, 0xc1, - 0xc9, 0x5e, 0x84, 0xe3, 0x13, 0xb2, 0x05, 0x63, 0xde, 0x29, 0x75, 0x78, 0x3e, 0x1e, 0xee, 0xe3, - 0xf1, 0x1e, 0xf7, 0x52, 0xe4, 0x72, 0xbb, 0x0b, 0x86, 0x37, 0x79, 0x60, 0xf9, 0xa7, 0xdc, 0x35, - 0x72, 0xb0, 0xf0, 0x17, 0x46, 0x0e, 0x94, 0xfe, 0x1d, 0xe6, 0x22, 0xd6, 0x61, 0x2e, 0x7c, 0xbb, - 0x90, 0x1b, 0x3c, 0x6f, 0x75, 0x38, 0x99, 0xfe, 0x00, 0x8c, 0x75, 0x70, 0x65, 0x1e, 0xd5, 0x7d, - 0x78, 0xb2, 0x82, 0xda, 0x9d, 0x55, 0xde, 0x83, 0x29, 0x3a, 0x6e, 0x07, 0x43, 0xdf, 0x6d, 0x95, - 0x9b, 0x3c, 0xb7, 0x74, 0x1c, 0x9a, 0xeb, 0xbe, 0x04, 0x03, 0x6c, 0x9e, 0xb9, 0xba, 0x07, 0x70, - 0x14, 0xce, 0x40, 0xfe, 0xa2, 0xc8, 0x65, 0x0b, 0x42, 0xec, 0xce, 0x31, 0xd4, 0x8b, 0xae, 0x77, - 0x28, 0x86, 0x7c, 0xc6, 0x78, 0x55, 0x64, 0xb5, 0xce, 0xd2, 0x71, 0x73, 0x54, 0xef, 0x58, 0x56, - 0x63, 0xb6, 0xb9, 0xbb, 0xe9, 0xeb, 0x67, 0x45, 0xfa, 0x72, 0x75, 0x8a, 0x48, 0x5f, 0xef, 0x8c, - 0xe9, 0xdd, 0x44, 0x16, 0x21, 0xe6, 0x9f, 0xc7, 0x44, 0xf6, 0x3d, 0x09, 0x8e, 0x50, 0xdd, 0xfc, - 0x8f, 0x3b, 0xfa, 0x35, 0xf9, 0x23, 0x80, 0x6c, 0xab, 0x5a, 0xe9, 0x18, 0xdd, 0x39, 0xdb, 0xaa, - 0x5e, 0x0b, 0xac, 0x2f, 0x8f, 0x00, 0xaa, 0xd9, 0x4e, 0x18, 0x9b, 0x5d, 0x0e, 0xcd, 0xd5, 0x6c, - 0xe7, 0xda, 0x3e, 0xab, 0x51, 0xe2, 0x0e, 0x4c, 0xe7, 0x2b, 0x12, 0x14, 0x3a, 0xa9, 0xcc, 0xa7, - 0x4f, 0x83, 0x89, 0xc0, 0xa3, 0xb3, 0xf0, 0x0c, 0x3e, 0xd2, 0xcb, 0x03, 0xa3, 0x50, 0x18, 0x1d, - 0xb6, 0xf0, 0xdd, 0xae, 0x03, 0xa6, 0x82, 0x1e, 0xda, 0x5e, 0x59, 0xbf, 0x63, 0xe1, 0xf3, 0xab, - 0x6d, 0x79, 0xf5, 0xcf, 0x45, 0xed, 0xbd, 0x0b, 0x93, 0x5d, 0xa4, 0xbe, 0xdb, 0xeb, 0xde, 0x4e, - 0xd7, 0xc9, 0xbc, 0xd3, 0xe5, 0xfb, 0x69, 0x1e, 0x09, 0xc1, 0x17, 0x0f, 0x7c, 0x7b, 0xb1, 0x4e, - 0xef, 0x78, 0xca, 0xef, 0x83, 0xa3, 0x1d, 0xa9, 0xb8, 0x6c, 0x45, 0x48, 0xec, 0x68, 0xb6, 0xc3, - 0xc5, 0x7a, 0xa0, 0x9b, 0x58, 0x21, 0x6a, 0x4a, 0x23, 0x23, 0xc8, 0x51, 0xd6, 0xeb, 0x86, 0xd1, - 0xe0, 0x62, 0xc8, 0x57, 0x60, 0xd4, 0x07, 0xe3, 0x83, 0x9c, 0x85, 0x84, 0x69, 0xf0, 0xaf, 0x9a, - 0x64, 0x4e, 0x1d, 0xeb, 0x36, 0x08, 0xa1, 0xe1, 0x6a, 0x53, 0x7c, 0x79, 0x1c, 0x10, 0x63, 0x46, - 0x6f, 0x56, 0x88, 0x21, 0x36, 0x60, 0x2c, 0x00, 0xe5, 0x83, 0xfc, 0x10, 0x0c, 0x98, 0x14, 0xe2, - 0xbe, 0x3b, 0xd7, 0x6d, 0x18, 0x8a, 0xe5, 0x7e, 0x47, 0x82, 0xb6, 0x4e, 0x7d, 0xe7, 0x30, 0x24, - 0x29, 0x57, 0xf4, 0x79, 0x09, 0xc0, 0x77, 0x4f, 0x62, 0xa6, 0x1b, 0x9b, 0xce, 0x7b, 0xe2, 0xc2, - 0x6c, 0xcf, 0xf8, 0xbc, 0x66, 0x3b, 0xf9, 0x63, 0xff, 0xfa, 0xf5, 0xcf, 0xc6, 0xee, 0x47, 0xf2, - 0x6c, 0x97, 0xdd, 0xb8, 0x2f, 0x5e, 0xbe, 0x16, 0xf8, 0xa4, 0xc6, 0xa3, 0xbd, 0x0d, 0x25, 0x24, - 0x9b, 0xe9, 0x15, 0x9d, 0x0b, 0x76, 0x81, 0x0a, 0x76, 0x06, 0x3d, 0x11, 0x2d, 0xd8, 0xec, 0x87, - 0x82, 0x41, 0xf3, 0x11, 0xf4, 0xbb, 0x12, 0x8c, 0x77, 0xda, 0xd2, 0xa1, 0x73, 0xbd, 0x49, 0xd1, - 0x5e, 0x52, 0x14, 0xce, 0x1f, 0x80, 0x92, 0xab, 0xb2, 0x48, 0x55, 0x99, 0x43, 0x4f, 0x1f, 0x40, - 0x95, 0x59, 0xdf, 0xba, 0x83, 0xfe, 0x97, 0x04, 0xc7, 0xf7, 0xdd, 0x21, 0xa1, 0xb9, 0xde, 0xa4, - 0xdc, 0xa7, 0x76, 0x2a, 0x94, 0xde, 0x0a, 0x0b, 0xae, 0xf1, 0x33, 0x54, 0xe3, 0x2b, 0x68, 0xe9, - 0x20, 0x1a, 0x7b, 0x15, 0x91, 0x5f, 0xf7, 0xdf, 0x0a, 0xde, 0xb7, 0xdd, 0xdf, 0x9d, 0xda, 0x36, - 0x1e, 0x11, 0x81, 0xd1, 0x5e, 0xd4, 0xca, 0xef, 0xa5, 0x2a, 0x28, 0x68, 0xfd, 0x2d, 0x4e, 0xda, - 0xec, 0x87, 0x82, 0x89, 0xff, 0x23, 0xe8, 0x7f, 0x4a, 0x9d, 0xaf, 0xcf, 0x3e, 0xb9, 0xaf, 0x88, - 0xdd, 0x37, 0x55, 0x85, 0x73, 0xfd, 0x13, 0x72, 0x25, 0x9b, 0x54, 0xc9, 0x3a, 0xc2, 0x77, 0x5a, - 0xc9, 0x8e, 0x93, 0x88, 0x7e, 0x5b, 0x82, 0xf1, 0x4e, 0x7b, 0x92, 0x88, 0xb0, 0xdc, 0x67, 0x93, - 0x15, 0x11, 0x96, 0xfb, 0x6d, 0x80, 0xe4, 0x1f, 0xa2, 0xca, 0x9f, 0x45, 0xa7, 0xbb, 0x29, 0xbf, - 0xef, 0x2c, 0x92, 0x58, 0xdc, 0xb7, 0xc8, 0x8f, 0x88, 0xc5, 0x5e, 0xf6, 0x31, 0x11, 0xb1, 0xd8, - 0xd3, 0x1e, 0x23, 0x3a, 0x16, 0x5d, 0xcd, 0x7a, 0x9c, 0x46, 0x1b, 0xfd, 0x86, 0x04, 0x43, 0x81, - 0x8a, 0x18, 0x3d, 0xbe, 0xaf, 0xa0, 0x9d, 0x36, 0x0c, 0x85, 0x53, 0xfd, 0x90, 0x70, 0x5d, 0x96, - 0xa8, 0x2e, 0xf3, 0x68, 0xee, 0x20, 0xba, 0x58, 0x01, 0x89, 0x5f, 0x91, 0x60, 0xac, 0x43, 0x95, - 0x19, 0x11, 0x85, 0xdd, 0x8b, 0xe6, 0xc2, 0xb9, 0xfe, 0x09, 0xb9, 0x56, 0x17, 0xa9, 0x56, 0xef, - 0x41, 0x4f, 0x1d, 0x44, 0x2b, 0xdf, 0xfa, 0x7c, 0xcb, 0xbb, 0x8d, 0xe8, 0x1b, 0x07, 0x9d, 0xed, - 0x53, 0x30, 0xa1, 0xd0, 0x93, 0x7d, 0xd3, 0x71, 0x7d, 0x9e, 0xa5, 0xfa, 0x3c, 0x83, 0xd6, 0xde, - 0x9a, 0x3e, 0xed, 0xcb, 0xfa, 0x37, 0xda, 0x5f, 0x7c, 0xdd, 0xdf, 0x8b, 0x3a, 0x16, 0xab, 0x85, - 0x27, 0xfa, 0xa2, 0xe1, 0x4a, 0x9d, 0xa3, 0x4a, 0x9d, 0x42, 0x8f, 0x75, 0x53, 0xca, 0x77, 0xe5, - 0x54, 0xd3, 0xb7, 0x8d, 0xd9, 0x0f, 0xb1, 0x12, 0xf8, 0x23, 0xe8, 0x47, 0xc5, 0x75, 0xbf, 0x13, - 0xfb, 0x8e, 0xeb, 0xab, 0x63, 0x0b, 0x0f, 0xf5, 0x80, 0xc9, 0xe5, 0xba, 0x9f, 0xca, 0x35, 0x89, - 0x8e, 0x75, 0x93, 0x8b, 0xd4, 0xb2, 0xe8, 0x93, 0x92, 0x7b, 0x43, 0xf8, 0xe4, 0xfe, 0xbc, 0xfd, - 0xc5, 0x6e, 0xe1, 0xe1, 0x9e, 0x70, 0xb9, 0x24, 0x0f, 0x50, 0x49, 0xa6, 0xd1, 0x64, 0x57, 0x49, - 0x58, 0xe9, 0x7b, 0xa7, 0x6f, 0x0e, 0xfc, 0xc9, 0x60, 0xd7, 0x97, 0xbc, 0xeb, 0x58, 0xc7, 0xb6, - 0x66, 0x1f, 0xe8, 0x06, 0x60, 0x6f, 0x8f, 0xa7, 0x7e, 0x37, 0x09, 0xd9, 0x45, 0x36, 0xca, 0x86, - 0xa3, 0x3a, 0x6f, 0x71, 0x23, 0x80, 0x6c, 0xfe, 0xbd, 0x28, 0xf6, 0xa1, 0x3b, 0xef, 0xd3, 0x6d, - 0xd9, 0xbe, 0xde, 0x99, 0x64, 0xf7, 0x9f, 0xf8, 0xeb, 0x89, 0x61, 0x7e, 0x32, 0xfb, 0xf4, 0x14, - 0xbd, 0xbb, 0xc0, 0x3e, 0x51, 0xf7, 0x31, 0x09, 0x0e, 0x53, 0x2c, 0x2f, 0xde, 0x28, 0xa6, 0x78, - 0x61, 0xa6, 0xab, 0xc7, 0x2c, 0xab, 0xbe, 0x23, 0x18, 0xf6, 0x51, 0xb9, 0xfb, 0xf9, 0x65, 0xf2, - 0x63, 0xbe, 0xc1, 0xc3, 0x6c, 0x65, 0x65, 0xac, 0xd1, 0x46, 0x69, 0x87, 0xf6, 0xf5, 0x89, 0x83, - 0xef, 0xeb, 0x2f, 0x43, 0xc6, 0x97, 0xe9, 0xf3, 0xc9, 0x88, 0x77, 0xbc, 0xc2, 0x87, 0x68, 0x7e, - 0x62, 0xf4, 0x71, 0x09, 0x0e, 0x77, 0x5c, 0x04, 0xe9, 0x7f, 0x23, 0xec, 0xf3, 0x90, 0x2e, 0x64, - 0x9c, 0x8e, 0x7c, 0x65, 0x65, 0xbc, 0xd5, 0xa9, 0x9a, 0x58, 0x87, 0xa1, 0xc0, 0x02, 0x96, 0x17, - 0xff, 0x53, 0xb4, 0xf7, 0xeb, 0xcd, 0x41, 0x06, 0xa8, 0x00, 0x29, 0xbc, 0x6b, 0x1a, 0x96, 0x83, - 0x6b, 0xf4, 0xca, 0x43, 0x4a, 0x71, 0xdb, 0xf2, 0x2a, 0xa0, 0xf6, 0xc9, 0x0d, 0x7f, 0x45, 0x31, - 0xed, 0x7d, 0x45, 0x71, 0x1c, 0x92, 0xfe, 0xef, 0x0c, 0xb2, 0xc6, 0xdd, 0xbb, 0x2d, 0xf4, 0x7f, - 0x03, 0x00, 0x00, 0xff, 0xff, 0x67, 0xcd, 0x4f, 0x75, 0x24, 0x8e, 0x00, 0x00, + 0x04, 0x01, 0xd0, 0xe1, 0x9f, 0x0c, 0x27, 0xee, 0xe3, 0x9d, 0xd5, 0x6b, 0x8b, 0xa5, 0x07, 0x61, + 0x94, 0x62, 0x3c, 0xc1, 0xa7, 0x5e, 0x6d, 0xe4, 0xc6, 0x66, 0xa4, 0x13, 0x29, 0x65, 0x84, 0x81, + 0xd7, 0x38, 0x54, 0xfe, 0xb5, 0x18, 0x24, 0x68, 0x62, 0x19, 0x85, 0xcc, 0xe6, 0xfb, 0xd6, 0xcb, + 0x95, 0x85, 0xb5, 0xab, 0xa5, 0xe5, 0x72, 0x56, 0x42, 0x23, 0x00, 0x14, 0x70, 0x71, 0x79, 0x6d, + 0x6e, 0x33, 0x1b, 0x73, 0xdb, 0x4b, 0xab, 0x9b, 0x67, 0x4f, 0x67, 0xe3, 0x2e, 0xc1, 0x55, 0x06, + 0x48, 0xf8, 0x11, 0x9e, 0x38, 0x95, 0x4d, 0xa2, 0x2c, 0x0c, 0x31, 0x06, 0x4b, 0xef, 0x2d, 0x2f, + 0x9c, 0x3d, 0x9d, 0x1d, 0x08, 0x42, 0x9e, 0x38, 0x95, 0x1d, 0x44, 0xc3, 0x90, 0xa6, 0x90, 0xd2, + 0xda, 0xda, 0x72, 0x36, 0xe5, 0xf2, 0xdc, 0xd8, 0x54, 0x96, 0x56, 0x17, 0xb3, 0x69, 0x97, 0xe7, + 0xa2, 0xb2, 0x76, 0x75, 0x3d, 0x0b, 0x2e, 0x87, 0x95, 0xf2, 0xc6, 0xc6, 0xdc, 0x62, 0x39, 0x9b, + 0x71, 0x31, 0x4a, 0xef, 0xdb, 0x2c, 0x6f, 0x64, 0x87, 0x02, 0x62, 0x3d, 0x71, 0x2a, 0x3b, 0xec, + 0x0e, 0x51, 0x5e, 0xbd, 0xba, 0x92, 0x1d, 0x41, 0x63, 0x30, 0xcc, 0x86, 0x10, 0x42, 0x8c, 0x86, + 0x40, 0x67, 0x4f, 0x67, 0xb3, 0x9e, 0x20, 0x8c, 0xcb, 0x58, 0x00, 0x70, 0xf6, 0x74, 0x16, 0xc9, + 0xf3, 0x90, 0xa4, 0x6e, 0x88, 0x10, 0x8c, 0x2c, 0xcf, 0x95, 0xca, 0xcb, 0x95, 0xb5, 0xf5, 0xcd, + 0xa5, 0xb5, 0xd5, 0xb9, 0xe5, 0xac, 0xe4, 0xc1, 0x94, 0xf2, 0x33, 0x57, 0x97, 0x94, 0xf2, 0x42, + 0x36, 0xe6, 0x87, 0xad, 0x97, 0xe7, 0x36, 0xcb, 0x0b, 0xd9, 0xb8, 0x5c, 0x85, 0x89, 0x4e, 0x09, + 0xb5, 0x63, 0x08, 0xf9, 0x7c, 0x21, 0xd6, 0xc5, 0x17, 0x28, 0xaf, 0xb0, 0x2f, 0xc8, 0xdf, 0x8e, + 0xc1, 0x78, 0x87, 0x45, 0xa5, 0xe3, 0x20, 0x4f, 0x43, 0x92, 0xf9, 0x32, 0x5b, 0x66, 0x1f, 0xea, + 0xb8, 0x3a, 0x51, 0xcf, 0x6e, 0x5b, 0x6a, 0x29, 0x9d, 0xbf, 0xd4, 0x88, 0x77, 0x29, 0x35, 0x08, + 0x8b, 0x36, 0x87, 0xfd, 0x91, 0xb6, 0xe4, 0xcf, 0xd6, 0xc7, 0xb3, 0xbd, 0xac, 0x8f, 0x14, 0xd6, + 0xdf, 0x22, 0x90, 0xec, 0xb0, 0x08, 0x5c, 0x80, 0xb1, 0x36, 0x46, 0x3d, 0x27, 0xe3, 0x8f, 0x4a, + 0x90, 0xeb, 0x66, 0x9c, 0x88, 0x94, 0x18, 0x0b, 0xa4, 0xc4, 0x0b, 0x61, 0x0b, 0xde, 0xdb, 0x7d, + 0x12, 0xda, 0xe6, 0xfa, 0xab, 0x12, 0x4c, 0x76, 0x2e, 0x29, 0x3b, 0xca, 0xf0, 0x14, 0x0c, 0x34, + 0xb1, 0xb3, 0x63, 0x88, 0xb2, 0xea, 0x81, 0x0e, 0x8b, 0x35, 0xe9, 0x0e, 0x4f, 0x36, 0xa7, 0xf2, + 0xaf, 0xf6, 0xf1, 0x6e, 0x75, 0x21, 0x93, 0xa6, 0x4d, 0xd2, 0x4f, 0xc6, 0xe0, 0x70, 0x47, 0xe6, + 0x1d, 0x05, 0x3d, 0x0e, 0xa0, 0xe9, 0x66, 0xcb, 0x61, 0xa5, 0x13, 0xcb, 0xc4, 0x69, 0x0a, 0xa1, + 0xc9, 0x8b, 0x64, 0xd9, 0x96, 0xe3, 0xf6, 0xc7, 0x69, 0x3f, 0x30, 0x10, 0x45, 0x38, 0xe7, 0x09, + 0x9a, 0xa0, 0x82, 0x4e, 0x75, 0xd1, 0xb4, 0xcd, 0x31, 0x1f, 0x83, 0x6c, 0xb5, 0xa1, 0x61, 0xdd, + 0xa9, 0xd8, 0x8e, 0x85, 0xd5, 0xa6, 0xa6, 0xd7, 0xe9, 0x52, 0x93, 0x2a, 0x26, 0xb7, 0xd5, 0x86, + 0x8d, 0x95, 0x51, 0xd6, 0xbd, 0x21, 0x7a, 0x09, 0x05, 0x75, 0x20, 0xcb, 0x47, 0x31, 0x10, 0xa0, + 0x60, 0xdd, 0x2e, 0x85, 0xfc, 0x99, 0x34, 0x64, 0x7c, 0x05, 0x38, 0xba, 0x17, 0x86, 0x9e, 0x53, + 0x6f, 0xa8, 0x15, 0xb1, 0xa9, 0x62, 0x96, 0xc8, 0x10, 0xd8, 0x3a, 0xdf, 0x58, 0x3d, 0x06, 0x13, + 0x14, 0xc5, 0x68, 0x39, 0xd8, 0xaa, 0x54, 0x1b, 0xaa, 0x6d, 0x53, 0xa3, 0xa5, 0x28, 0x2a, 0x22, + 0x7d, 0x6b, 0xa4, 0x6b, 0x5e, 0xf4, 0xa0, 0x33, 0x30, 0x4e, 0x29, 0x9a, 0xad, 0x86, 0xa3, 0x99, + 0x0d, 0x5c, 0x21, 0xdb, 0x3c, 0x9b, 0x2e, 0x39, 0xae, 0x64, 0x63, 0x04, 0x63, 0x85, 0x23, 0x10, + 0x89, 0x6c, 0xb4, 0x00, 0xc7, 0x29, 0x59, 0x1d, 0xeb, 0xd8, 0x52, 0x1d, 0x5c, 0xc1, 0x1f, 0x6c, + 0xa9, 0x0d, 0xbb, 0xa2, 0xea, 0xb5, 0xca, 0x8e, 0x6a, 0xef, 0xe4, 0x26, 0x08, 0x83, 0x52, 0x2c, + 0x27, 0x29, 0x47, 0x08, 0xe2, 0x22, 0xc7, 0x2b, 0x53, 0xb4, 0x39, 0xbd, 0x76, 0x49, 0xb5, 0x77, + 0x50, 0x11, 0x26, 0x29, 0x17, 0xdb, 0xb1, 0x34, 0xbd, 0x5e, 0xa9, 0xee, 0xe0, 0xea, 0xf5, 0x4a, + 0xcb, 0xd9, 0x3e, 0x97, 0x3b, 0xea, 0x1f, 0x9f, 0x4a, 0xb8, 0x41, 0x71, 0xe6, 0x09, 0xca, 0x55, + 0x67, 0xfb, 0x1c, 0xda, 0x80, 0x21, 0x32, 0x19, 0x4d, 0xed, 0x79, 0x5c, 0xd9, 0x36, 0x2c, 0xba, + 0x86, 0x8e, 0x74, 0x48, 0x4d, 0x3e, 0x0b, 0x16, 0xd6, 0x38, 0xc1, 0x8a, 0x51, 0xc3, 0xc5, 0xe4, + 0xc6, 0x7a, 0xb9, 0xbc, 0xa0, 0x64, 0x04, 0x97, 0x8b, 0x86, 0x45, 0x1c, 0xaa, 0x6e, 0xb8, 0x06, + 0xce, 0x30, 0x87, 0xaa, 0x1b, 0xc2, 0xbc, 0x67, 0x60, 0xbc, 0x5a, 0x65, 0x3a, 0x6b, 0xd5, 0x0a, + 0xdf, 0x8c, 0xd9, 0xb9, 0x6c, 0xc0, 0x58, 0xd5, 0xea, 0x22, 0x43, 0xe0, 0x3e, 0x6e, 0xa3, 0xf3, + 0x70, 0xd8, 0x33, 0x96, 0x9f, 0x70, 0xac, 0x4d, 0xcb, 0x30, 0xe9, 0x19, 0x18, 0x37, 0xf7, 0xda, + 0x09, 0x51, 0x60, 0x44, 0x73, 0x2f, 0x4c, 0xf6, 0x24, 0x4c, 0x98, 0x3b, 0x66, 0x3b, 0xdd, 0x49, + 0x3f, 0x1d, 0x32, 0x77, 0xcc, 0x30, 0xe1, 0xbb, 0xe8, 0xce, 0xdc, 0xc2, 0x55, 0xd5, 0xc1, 0xb5, + 0xdc, 0x3d, 0x7e, 0x74, 0x5f, 0x07, 0x2a, 0x40, 0xb6, 0x5a, 0xad, 0x60, 0x5d, 0xdd, 0x6a, 0xe0, + 0x8a, 0x6a, 0x61, 0x5d, 0xb5, 0x73, 0xd3, 0x14, 0x39, 0xe1, 0x58, 0x2d, 0xac, 0x8c, 0x54, 0xab, + 0x65, 0xda, 0x39, 0x47, 0xfb, 0xd0, 0x49, 0x18, 0x33, 0xb6, 0x9e, 0xab, 0x32, 0x8f, 0xac, 0x98, + 0x16, 0xde, 0xd6, 0x76, 0x73, 0xf7, 0x53, 0xf3, 0x8e, 0x92, 0x0e, 0xea, 0x8f, 0xeb, 0x14, 0x8c, + 0x1e, 0x82, 0x6c, 0xd5, 0xde, 0x51, 0x2d, 0x93, 0xa6, 0x64, 0xdb, 0x54, 0xab, 0x38, 0xf7, 0x2e, + 0x86, 0xca, 0xe0, 0xab, 0x02, 0x4c, 0x22, 0xc2, 0xbe, 0xa9, 0x6d, 0x3b, 0x82, 0xe3, 0x83, 0x2c, + 0x22, 0x28, 0x8c, 0x73, 0x3b, 0x01, 0x59, 0x62, 0x89, 0xc0, 0xc0, 0x27, 0x28, 0xda, 0x88, 0xb9, + 0x63, 0xfa, 0xc7, 0xbd, 0x0f, 0x86, 0x09, 0xa6, 0x37, 0xe8, 0x43, 0xac, 0x70, 0x33, 0x77, 0x7c, + 0x23, 0x9e, 0x86, 0x49, 0x82, 0xd4, 0xc4, 0x8e, 0x5a, 0x53, 0x1d, 0xd5, 0x87, 0xfd, 0x08, 0xc5, + 0x26, 0x66, 0x5f, 0xe1, 0x9d, 0x01, 0x39, 0xad, 0xd6, 0xd6, 0x9e, 0xeb, 0x58, 0x8f, 0x32, 0x39, + 0x09, 0x4c, 0xb8, 0xd6, 0x5d, 0x2b, 0xce, 0xe5, 0x22, 0x0c, 0xf9, 0xfd, 0x1e, 0xa5, 0x81, 0x79, + 0x7e, 0x56, 0x22, 0x45, 0xd0, 0xfc, 0xda, 0x02, 0x29, 0x5f, 0xde, 0x5f, 0xce, 0xc6, 0x48, 0x19, + 0xb5, 0xbc, 0xb4, 0x59, 0xae, 0x28, 0x57, 0x57, 0x37, 0x97, 0x56, 0xca, 0xd9, 0xb8, 0xaf, 0xb0, + 0xbf, 0x9c, 0x48, 0x3d, 0x90, 0x7d, 0x50, 0x7e, 0x35, 0x06, 0x23, 0xc1, 0x9d, 0x1a, 0xfa, 0x21, + 0xb8, 0x47, 0x1c, 0xab, 0xd8, 0xd8, 0xa9, 0xdc, 0xd4, 0x2c, 0x1a, 0x90, 0x4d, 0x95, 0x2d, 0x8e, + 0xae, 0xff, 0x4c, 0x70, 0xac, 0x0d, 0xec, 0x3c, 0xab, 0x59, 0x24, 0xdc, 0x9a, 0xaa, 0x83, 0x96, + 0x61, 0x5a, 0x37, 0x2a, 0xb6, 0xa3, 0xea, 0x35, 0xd5, 0xaa, 0x55, 0xbc, 0x03, 0xad, 0x8a, 0x5a, + 0xad, 0x62, 0xdb, 0x36, 0xd8, 0x42, 0xe8, 0x72, 0x39, 0xa6, 0x1b, 0x1b, 0x1c, 0xd9, 0x5b, 0x21, + 0xe6, 0x38, 0x6a, 0xc8, 0x7d, 0xe3, 0xdd, 0xdc, 0xf7, 0x28, 0xa4, 0x9b, 0xaa, 0x59, 0xc1, 0xba, + 0x63, 0xed, 0xd1, 0xfa, 0x3c, 0xa5, 0xa4, 0x9a, 0xaa, 0x59, 0x26, 0xed, 0xb7, 0x65, 0x9b, 0x74, + 0x39, 0x91, 0x4a, 0x65, 0xd3, 0x97, 0x13, 0xa9, 0x74, 0x16, 0xe4, 0xd7, 0xe2, 0x30, 0xe4, 0xaf, + 0xd7, 0xc9, 0xf6, 0xa7, 0x4a, 0x57, 0x2c, 0x89, 0xe6, 0xb4, 0xfb, 0xf6, 0xad, 0xee, 0x0b, 0xf3, + 0x64, 0x29, 0x2b, 0x0e, 0xb0, 0xe2, 0x58, 0x61, 0x94, 0xa4, 0x8c, 0x20, 0xce, 0x86, 0x59, 0x31, + 0x92, 0x52, 0x78, 0x0b, 0x2d, 0xc2, 0xc0, 0x73, 0x36, 0xe5, 0x3d, 0x40, 0x79, 0xdf, 0xbf, 0x3f, + 0xef, 0xcb, 0x1b, 0x94, 0x79, 0xfa, 0xf2, 0x46, 0x65, 0x75, 0x4d, 0x59, 0x99, 0x5b, 0x56, 0x38, + 0x39, 0x3a, 0x02, 0x89, 0x86, 0xfa, 0xfc, 0x5e, 0x70, 0xd1, 0xa3, 0xa0, 0x5e, 0x27, 0xe1, 0x08, + 0x24, 0x6e, 0x62, 0xf5, 0x7a, 0x70, 0xa9, 0xa1, 0xa0, 0xbb, 0x18, 0x0c, 0xb3, 0x90, 0xa4, 0xf6, + 0x42, 0x00, 0xdc, 0x62, 0xd9, 0x43, 0x28, 0x05, 0x89, 0xf9, 0x35, 0x85, 0x04, 0x44, 0x16, 0x86, + 0x18, 0xb4, 0xb2, 0xbe, 0x54, 0x9e, 0x2f, 0x67, 0x63, 0xf2, 0x19, 0x18, 0x60, 0x46, 0x20, 0xc1, + 0xe2, 0x9a, 0x21, 0x7b, 0x88, 0x37, 0x39, 0x0f, 0x49, 0xf4, 0x5e, 0x5d, 0x29, 0x95, 0x95, 0x6c, + 0x2c, 0x38, 0xd5, 0x89, 0x6c, 0x52, 0xb6, 0x61, 0xc8, 0x5f, 0x87, 0xbf, 0x3d, 0x9b, 0xf1, 0x6f, + 0x48, 0x90, 0xf1, 0xd5, 0xd5, 0xa4, 0x20, 0x52, 0x1b, 0x0d, 0xe3, 0x66, 0x45, 0x6d, 0x68, 0xaa, + 0xcd, 0x5d, 0x03, 0x28, 0x68, 0x8e, 0x40, 0x7a, 0x9d, 0xba, 0xb7, 0x29, 0x44, 0x92, 0xd9, 0x01, + 0xf9, 0x4b, 0x12, 0x64, 0xc3, 0x85, 0x6d, 0x48, 0x4c, 0xe9, 0x9d, 0x14, 0x53, 0xfe, 0xa2, 0x04, + 0x23, 0xc1, 0x6a, 0x36, 0x24, 0xde, 0xbd, 0xef, 0xa8, 0x78, 0x7f, 0x18, 0x83, 0xe1, 0x40, 0x0d, + 0xdb, 0xab, 0x74, 0x1f, 0x84, 0x31, 0xad, 0x86, 0x9b, 0xa6, 0xe1, 0x60, 0xbd, 0xba, 0x57, 0x69, + 0xe0, 0x1b, 0xb8, 0x91, 0x93, 0x69, 0xd2, 0x98, 0xdd, 0xbf, 0x4a, 0x2e, 0x2c, 0x79, 0x74, 0xcb, + 0x84, 0xac, 0x38, 0xbe, 0xb4, 0x50, 0x5e, 0x59, 0x5f, 0xdb, 0x2c, 0xaf, 0xce, 0xbf, 0xaf, 0x72, + 0x75, 0xf5, 0xca, 0xea, 0xda, 0xb3, 0xab, 0x4a, 0x56, 0x0b, 0xa1, 0xdd, 0xc5, 0xb0, 0x5f, 0x87, + 0x6c, 0x58, 0x28, 0x74, 0x0f, 0x74, 0x12, 0x2b, 0x7b, 0x08, 0x8d, 0xc3, 0xe8, 0xea, 0x5a, 0x65, + 0x63, 0x69, 0xa1, 0x5c, 0x29, 0x5f, 0xbc, 0x58, 0x9e, 0xdf, 0xdc, 0x60, 0xe7, 0x1e, 0x2e, 0xf6, + 0x66, 0x20, 0xc0, 0xe5, 0x2f, 0xc4, 0x61, 0xbc, 0x83, 0x24, 0x68, 0x8e, 0xef, 0x58, 0xd8, 0x26, + 0xea, 0xd1, 0x5e, 0xa4, 0x2f, 0x90, 0x9a, 0x61, 0x5d, 0xb5, 0x1c, 0xbe, 0xc1, 0x79, 0x08, 0x88, + 0x95, 0x74, 0x47, 0xdb, 0xd6, 0xb0, 0xc5, 0xcf, 0x93, 0xd8, 0x36, 0x66, 0xd4, 0x83, 0xb3, 0x23, + 0xa5, 0x47, 0x00, 0x99, 0x86, 0xad, 0x39, 0xda, 0x0d, 0x5c, 0xd1, 0x74, 0x71, 0xf8, 0x44, 0xb6, + 0x35, 0x09, 0x25, 0x2b, 0x7a, 0x96, 0x74, 0xc7, 0xc5, 0xd6, 0x71, 0x5d, 0x0d, 0x61, 0x93, 0x64, + 0x1e, 0x57, 0xb2, 0xa2, 0xc7, 0xc5, 0xbe, 0x17, 0x86, 0x6a, 0x46, 0x8b, 0xd4, 0x7a, 0x0c, 0x8f, + 0xac, 0x1d, 0x92, 0x92, 0x61, 0x30, 0x17, 0x85, 0x57, 0xf1, 0xde, 0xa9, 0xd7, 0x90, 0x92, 0x61, + 0x30, 0x86, 0xf2, 0x20, 0x8c, 0xaa, 0xf5, 0xba, 0x45, 0x98, 0x0b, 0x46, 0x6c, 0x5f, 0x32, 0xe2, + 0x82, 0x29, 0x62, 0xfe, 0x32, 0xa4, 0x84, 0x1d, 0xc8, 0x52, 0x4d, 0x2c, 0x51, 0x31, 0xd9, 0x66, + 0x3b, 0x76, 0x22, 0xad, 0xa4, 0x74, 0xd1, 0x79, 0x2f, 0x0c, 0x69, 0x76, 0xc5, 0x3b, 0xc4, 0x8f, + 0xcd, 0xc4, 0x4e, 0xa4, 0x94, 0x8c, 0x66, 0xbb, 0x07, 0xa0, 0xf2, 0x57, 0x63, 0x30, 0x12, 0x7c, + 0x08, 0x81, 0x16, 0x20, 0xd5, 0x30, 0xaa, 0x2a, 0x75, 0x2d, 0xf6, 0x04, 0xec, 0x44, 0xc4, 0x73, + 0x8b, 0xc2, 0x32, 0xc7, 0x57, 0x5c, 0xca, 0xfc, 0x6f, 0x4b, 0x90, 0x12, 0x60, 0x34, 0x09, 0x09, + 0x53, 0x75, 0x76, 0x28, 0xbb, 0x64, 0x29, 0x96, 0x95, 0x14, 0xda, 0x26, 0x70, 0xdb, 0x54, 0x75, + 0xea, 0x02, 0x1c, 0x4e, 0xda, 0x64, 0x5e, 0x1b, 0x58, 0xad, 0xd1, 0x4d, 0x8f, 0xd1, 0x6c, 0x62, + 0xdd, 0xb1, 0xc5, 0xbc, 0x72, 0xf8, 0x3c, 0x07, 0xa3, 0x87, 0x61, 0xcc, 0xb1, 0x54, 0xad, 0x11, + 0xc0, 0x4d, 0x50, 0xdc, 0xac, 0xe8, 0x70, 0x91, 0x8b, 0x70, 0x44, 0xf0, 0xad, 0x61, 0x47, 0xad, + 0xee, 0xe0, 0x9a, 0x47, 0x34, 0x40, 0x0f, 0x37, 0xee, 0xe1, 0x08, 0x0b, 0xbc, 0x5f, 0xd0, 0xca, + 0xaf, 0x4a, 0x30, 0x26, 0xb6, 0x69, 0x35, 0xd7, 0x58, 0x2b, 0x00, 0xaa, 0xae, 0x1b, 0x8e, 0xdf, + 0x5c, 0xed, 0xae, 0xdc, 0x46, 0x57, 0x98, 0x73, 0x89, 0x14, 0x1f, 0x83, 0x7c, 0x13, 0xc0, 0xeb, + 0xe9, 0x6a, 0xb6, 0x69, 0xc8, 0xf0, 0x27, 0x4c, 0xf4, 0x31, 0x25, 0xdb, 0xd8, 0x03, 0x03, 0x91, + 0xfd, 0x1c, 0x9a, 0x80, 0xe4, 0x16, 0xae, 0x6b, 0x3a, 0x3f, 0x37, 0x66, 0x0d, 0x71, 0xfc, 0x92, + 0x70, 0x8f, 0x5f, 0x4a, 0x9f, 0x92, 0x60, 0xbc, 0x6a, 0x34, 0xc3, 0xf2, 0x96, 0xb2, 0xa1, 0xd3, + 0x05, 0xfb, 0x92, 0xf4, 0xfe, 0xa7, 0xea, 0x9a, 0xb3, 0xd3, 0xda, 0x2a, 0x54, 0x8d, 0xe6, 0x6c, + 0xdd, 0x68, 0xa8, 0x7a, 0xdd, 0x7b, 0xce, 0x4a, 0x7f, 0x54, 0x1f, 0xad, 0x63, 0xfd, 0xd1, 0xba, + 0xe1, 0x7b, 0xea, 0x7a, 0xc1, 0xfb, 0xf9, 0xa7, 0x92, 0xf4, 0x33, 0xb1, 0xf8, 0xe2, 0x7a, 0xe9, + 0x6b, 0xb1, 0xfc, 0x22, 0x1b, 0x6e, 0x5d, 0x98, 0x47, 0xc1, 0xdb, 0x0d, 0x5c, 0x25, 0x2a, 0xc3, + 0x77, 0x1e, 0x86, 0x89, 0xba, 0x51, 0x37, 0x28, 0xc7, 0x59, 0xf2, 0x8b, 0x3f, 0xb9, 0x4d, 0xbb, + 0xd0, 0x7c, 0xe4, 0x63, 0xde, 0xe2, 0x2a, 0x8c, 0x73, 0xe4, 0x0a, 0x7d, 0x74, 0xc4, 0x36, 0x36, + 0x68, 0xdf, 0x53, 0xb5, 0xdc, 0x2f, 0xbf, 0x4e, 0x17, 0x74, 0x65, 0x8c, 0x93, 0x92, 0x3e, 0xb6, + 0xf7, 0x29, 0x2a, 0x70, 0x38, 0xc0, 0x8f, 0x85, 0x2d, 0xb6, 0x22, 0x38, 0xfe, 0x06, 0xe7, 0x38, + 0xee, 0xe3, 0xb8, 0xc1, 0x49, 0x8b, 0xf3, 0x30, 0xdc, 0x0f, 0xaf, 0x7f, 0xce, 0x79, 0x0d, 0x61, + 0x3f, 0x93, 0x45, 0x18, 0xa5, 0x4c, 0xaa, 0x2d, 0xdb, 0x31, 0x9a, 0x34, 0x27, 0xee, 0xcf, 0xe6, + 0x37, 0x5f, 0x67, 0x71, 0x34, 0x42, 0xc8, 0xe6, 0x5d, 0xaa, 0x62, 0x11, 0xe8, 0xd3, 0xb2, 0x1a, + 0xae, 0x36, 0x22, 0x38, 0x7c, 0x8b, 0x0b, 0xe2, 0xe2, 0x17, 0xaf, 0xc1, 0x04, 0xf9, 0x4d, 0x53, + 0x96, 0x5f, 0x92, 0xe8, 0x23, 0xb8, 0xdc, 0xab, 0x1f, 0x65, 0xa1, 0x3a, 0xee, 0x32, 0xf0, 0xc9, + 0xe4, 0x9b, 0xc5, 0x3a, 0x76, 0x1c, 0x6c, 0xd9, 0x15, 0xb5, 0xd1, 0x49, 0x3c, 0xdf, 0x19, 0x46, + 0xee, 0xf3, 0xdf, 0x0d, 0xce, 0xe2, 0x22, 0xa3, 0x9c, 0x6b, 0x34, 0x8a, 0x57, 0xe1, 0x9e, 0x0e, + 0x5e, 0xd1, 0x03, 0xcf, 0x2f, 0x70, 0x9e, 0x13, 0x6d, 0x9e, 0x41, 0xd8, 0xae, 0x83, 0x80, 0xbb, + 0x73, 0xd9, 0x03, 0xcf, 0x9f, 0xe6, 0x3c, 0x11, 0xa7, 0x15, 0x53, 0x4a, 0x38, 0x5e, 0x86, 0xb1, + 0x1b, 0xd8, 0xda, 0x32, 0x6c, 0x7e, 0x6e, 0xd4, 0x03, 0xbb, 0x2f, 0x72, 0x76, 0xa3, 0x9c, 0x90, + 0x1e, 0x24, 0x11, 0x5e, 0xe7, 0x21, 0xb5, 0xad, 0x56, 0x71, 0x0f, 0x2c, 0x5e, 0xe2, 0x2c, 0x06, + 0x09, 0x3e, 0x21, 0x9d, 0x83, 0xa1, 0xba, 0xc1, 0x57, 0xad, 0x68, 0xf2, 0x2f, 0x71, 0xf2, 0x8c, + 0xa0, 0xe1, 0x2c, 0x4c, 0xc3, 0x6c, 0x35, 0xc8, 0x92, 0x16, 0xcd, 0xe2, 0xaf, 0x0b, 0x16, 0x82, + 0x86, 0xb3, 0xe8, 0xc3, 0xac, 0x2f, 0x0b, 0x16, 0xb6, 0xcf, 0x9e, 0x4f, 0x43, 0xc6, 0xd0, 0x1b, + 0x7b, 0x86, 0xde, 0x8b, 0x10, 0x5f, 0xe6, 0x1c, 0x80, 0x93, 0x10, 0x06, 0x17, 0x20, 0xdd, 0xeb, + 0x44, 0xfc, 0x8d, 0xef, 0x8a, 0xf0, 0x10, 0x33, 0xb0, 0x08, 0xa3, 0x22, 0x41, 0x69, 0x86, 0xde, + 0x03, 0x8b, 0xbf, 0xc9, 0x59, 0x8c, 0xf8, 0xc8, 0xb8, 0x1a, 0x0e, 0xb6, 0x9d, 0x3a, 0xee, 0x85, + 0xc9, 0x57, 0x85, 0x1a, 0x9c, 0x84, 0x9b, 0x72, 0x0b, 0xeb, 0xd5, 0x9d, 0xde, 0x38, 0xfc, 0x9c, + 0x30, 0xa5, 0xa0, 0x21, 0x2c, 0xe6, 0x61, 0xb8, 0xa9, 0x5a, 0xf6, 0x8e, 0xda, 0xe8, 0x69, 0x3a, + 0xfe, 0x16, 0xe7, 0x31, 0xe4, 0x12, 0x71, 0x8b, 0xb4, 0xf4, 0x7e, 0xd8, 0x7c, 0x4d, 0x58, 0xc4, + 0x47, 0xc6, 0x43, 0xcf, 0x76, 0xe8, 0x21, 0x5b, 0x3f, 0xdc, 0x7e, 0x5e, 0x84, 0x1e, 0xa3, 0x5d, + 0xf1, 0x73, 0xbc, 0x00, 0x69, 0x5b, 0x7b, 0xbe, 0x27, 0x36, 0xbf, 0x20, 0x66, 0x9a, 0x12, 0x10, + 0xe2, 0xf7, 0xc1, 0x91, 0x8e, 0xcb, 0x44, 0x0f, 0xcc, 0xfe, 0x36, 0x67, 0x36, 0xd9, 0x61, 0xa9, + 0xe0, 0x29, 0xa1, 0x5f, 0x96, 0x7f, 0x47, 0xa4, 0x04, 0x1c, 0xe2, 0xb5, 0x4e, 0xf6, 0x11, 0xb6, + 0xba, 0xdd, 0x9f, 0xd5, 0x7e, 0x51, 0x58, 0x8d, 0xd1, 0x06, 0xac, 0xb6, 0x09, 0x93, 0x9c, 0x63, + 0x7f, 0xf3, 0xfa, 0x4b, 0x22, 0xb1, 0x32, 0xea, 0xab, 0xc1, 0xd9, 0xfd, 0x00, 0xe4, 0x5d, 0x73, + 0x8a, 0x82, 0xd5, 0xae, 0x34, 0x55, 0xb3, 0x07, 0xce, 0xbf, 0xcc, 0x39, 0x8b, 0x8c, 0xef, 0x56, + 0xbc, 0xf6, 0x8a, 0x6a, 0x12, 0xe6, 0xef, 0x85, 0x9c, 0x60, 0xde, 0xd2, 0x2d, 0x5c, 0x35, 0xea, + 0xba, 0xf6, 0x3c, 0xae, 0xf5, 0xc0, 0xfa, 0x57, 0x42, 0x53, 0x75, 0xd5, 0x47, 0x4e, 0x38, 0x2f, + 0x41, 0xd6, 0xad, 0x55, 0x2a, 0x5a, 0xd3, 0x34, 0x2c, 0x27, 0x82, 0xe3, 0xd7, 0xc5, 0x4c, 0xb9, + 0x74, 0x4b, 0x94, 0xac, 0x58, 0x06, 0xf6, 0xe4, 0xb9, 0x57, 0x97, 0xfc, 0x55, 0xce, 0x68, 0xd8, + 0xa3, 0xe2, 0x89, 0xa3, 0x6a, 0x34, 0x4d, 0xd5, 0xea, 0x25, 0xff, 0xfd, 0x5d, 0x91, 0x38, 0x38, + 0x09, 0x4f, 0x1c, 0xce, 0x9e, 0x89, 0xc9, 0x6a, 0xdf, 0x03, 0x87, 0x5f, 0x13, 0x89, 0x43, 0xd0, + 0x70, 0x16, 0xa2, 0x60, 0xe8, 0x81, 0xc5, 0xdf, 0x13, 0x2c, 0x04, 0x0d, 0x61, 0xf1, 0x8c, 0xb7, + 0xd0, 0x5a, 0xb8, 0xae, 0xd9, 0x8e, 0xc5, 0xca, 0xe4, 0xfd, 0x59, 0xfd, 0xfd, 0xef, 0x06, 0x8b, + 0x30, 0xc5, 0x47, 0x4a, 0x32, 0x11, 0x3f, 0x76, 0xa5, 0xbb, 0xa8, 0x68, 0xc1, 0x7e, 0x5d, 0x64, + 0x22, 0x1f, 0x19, 0x91, 0xcd, 0x57, 0x21, 0x12, 0xb3, 0x57, 0xc9, 0xde, 0xa1, 0x07, 0x76, 0xff, + 0x20, 0x24, 0xdc, 0x86, 0xa0, 0x25, 0x3c, 0x7d, 0xf5, 0x4f, 0x4b, 0xbf, 0x8e, 0xf7, 0x7a, 0xf2, + 0xce, 0x7f, 0x18, 0xaa, 0x7f, 0xae, 0x32, 0x4a, 0x96, 0x43, 0x46, 0x43, 0xf5, 0x14, 0x8a, 0xba, + 0x67, 0x94, 0xfb, 0xd1, 0x37, 0xb9, 0xbe, 0xc1, 0x72, 0xaa, 0xb8, 0x4c, 0x9c, 0x3c, 0x58, 0xf4, + 0x44, 0x33, 0xfb, 0xe8, 0x9b, 0xae, 0x9f, 0x07, 0x6a, 0x9e, 0xe2, 0x45, 0x18, 0x0e, 0x14, 0x3c, + 0xd1, 0xac, 0x3e, 0xc6, 0x59, 0x0d, 0xf9, 0xeb, 0x9d, 0xe2, 0x19, 0x48, 0x90, 0xe2, 0x25, 0x9a, + 0xfc, 0x2f, 0x72, 0x72, 0x8a, 0x5e, 0x7c, 0x37, 0xa4, 0x44, 0xd1, 0x12, 0x4d, 0xfa, 0x71, 0x4e, + 0xea, 0x92, 0x10, 0x72, 0x51, 0xb0, 0x44, 0x93, 0xff, 0x25, 0x41, 0x2e, 0x48, 0x08, 0x79, 0xef, + 0x26, 0xfc, 0xc6, 0x8f, 0x27, 0xf8, 0xa2, 0x23, 0x6c, 0x77, 0x01, 0x06, 0x79, 0xa5, 0x12, 0x4d, + 0xfd, 0x49, 0x3e, 0xb8, 0xa0, 0x28, 0x3e, 0x09, 0xc9, 0x1e, 0x0d, 0xfe, 0x13, 0x9c, 0x94, 0xe1, + 0x17, 0xe7, 0x21, 0xe3, 0xab, 0x4e, 0xa2, 0xc9, 0xff, 0x0a, 0x27, 0xf7, 0x53, 0x11, 0xd1, 0x79, + 0x75, 0x12, 0xcd, 0xe0, 0x53, 0x42, 0x74, 0x4e, 0x41, 0xcc, 0x26, 0x0a, 0x93, 0x68, 0xea, 0x4f, + 0x0b, 0xab, 0x0b, 0x92, 0xe2, 0xd3, 0x90, 0x76, 0x17, 0x9b, 0x68, 0xfa, 0xcf, 0x70, 0x7a, 0x8f, + 0x86, 0x58, 0xc0, 0xb7, 0xd8, 0x45, 0xb3, 0xf8, 0xab, 0xc2, 0x02, 0x3e, 0x2a, 0x12, 0x46, 0xe1, + 0x02, 0x26, 0x9a, 0xd3, 0x67, 0x45, 0x18, 0x85, 0xea, 0x17, 0x32, 0x9b, 0x34, 0xe7, 0x47, 0xb3, + 0xf8, 0x49, 0x31, 0x9b, 0x14, 0x9f, 0x88, 0x11, 0xae, 0x08, 0xa2, 0x79, 0xfc, 0x35, 0x21, 0x46, + 0xa8, 0x20, 0x28, 0xae, 0x03, 0x6a, 0xaf, 0x06, 0xa2, 0xf9, 0x7d, 0x8e, 0xf3, 0x1b, 0x6b, 0x2b, + 0x06, 0x8a, 0xcf, 0xc2, 0x64, 0xe7, 0x4a, 0x20, 0x9a, 0xeb, 0xe7, 0xdf, 0x0c, 0xed, 0xdd, 0xfc, + 0x85, 0x40, 0x71, 0xd3, 0x5b, 0x52, 0xfc, 0x55, 0x40, 0x34, 0xdb, 0x2f, 0xbc, 0x19, 0x4c, 0xdc, + 0xfe, 0x22, 0xa0, 0x38, 0x07, 0xe0, 0x2d, 0xc0, 0xd1, 0xbc, 0xbe, 0xc8, 0x79, 0xf9, 0x88, 0x48, + 0x68, 0xf0, 0xf5, 0x37, 0x9a, 0xfe, 0x25, 0x11, 0x1a, 0x9c, 0x82, 0x84, 0x86, 0x58, 0x7a, 0xa3, + 0xa9, 0xbf, 0x24, 0x42, 0x43, 0x90, 0x10, 0xcf, 0xf6, 0xad, 0x6e, 0xd1, 0x1c, 0xbe, 0x2c, 0x3c, + 0xdb, 0x47, 0x55, 0x5c, 0x85, 0xb1, 0xb6, 0x05, 0x31, 0x9a, 0xd5, 0xcf, 0x70, 0x56, 0xd9, 0xf0, + 0x7a, 0xe8, 0x5f, 0xbc, 0xf8, 0x62, 0x18, 0xcd, 0xed, 0x2b, 0xa1, 0xc5, 0x8b, 0xaf, 0x85, 0xc5, + 0x0b, 0x90, 0xd2, 0x5b, 0x8d, 0x06, 0x09, 0x1e, 0xb4, 0xff, 0xdd, 0xc0, 0xdc, 0x7f, 0xfa, 0x3e, + 0xb7, 0x8e, 0x20, 0x28, 0x9e, 0x81, 0x24, 0x6e, 0x6e, 0xe1, 0x5a, 0x14, 0xe5, 0x77, 0xbe, 0x2f, + 0x12, 0x26, 0xc1, 0x2e, 0x3e, 0x0d, 0xc0, 0x8e, 0x46, 0xe8, 0xe3, 0xc1, 0x08, 0xda, 0xff, 0xfc, + 0x7d, 0x7e, 0x19, 0xc7, 0x23, 0xf1, 0x18, 0xb0, 0xab, 0x3d, 0xfb, 0x33, 0xf8, 0x6e, 0x90, 0x01, + 0x9d, 0x91, 0xf3, 0x30, 0xf8, 0x9c, 0x6d, 0xe8, 0x8e, 0x5a, 0x8f, 0xa2, 0xfe, 0x2f, 0x9c, 0x5a, + 0xe0, 0x13, 0x83, 0x35, 0x0d, 0x0b, 0x3b, 0x6a, 0xdd, 0x8e, 0xa2, 0xfd, 0xaf, 0x9c, 0xd6, 0x25, + 0x20, 0xc4, 0x55, 0xd5, 0x76, 0x7a, 0xd1, 0xfb, 0xbf, 0x09, 0x62, 0x41, 0x40, 0x84, 0x26, 0xbf, + 0xaf, 0xe3, 0xbd, 0x28, 0xda, 0xef, 0x09, 0xa1, 0x39, 0x7e, 0xf1, 0xdd, 0x90, 0x26, 0x3f, 0xd9, + 0x0d, 0xbb, 0x08, 0xe2, 0x3f, 0xe6, 0xc4, 0x1e, 0x05, 0x19, 0xd9, 0x76, 0x6a, 0x8e, 0x16, 0x6d, + 0xec, 0xdb, 0x7c, 0xa6, 0x05, 0x7e, 0x71, 0x0e, 0x32, 0xb6, 0x53, 0xab, 0xb5, 0x78, 0x7d, 0x1a, + 0x41, 0xfe, 0xdf, 0xbf, 0xef, 0x1e, 0x59, 0xb8, 0x34, 0x64, 0xb6, 0x6f, 0x5e, 0x77, 0x4c, 0x83, + 0x3e, 0x02, 0x89, 0xe2, 0xf0, 0x26, 0xe7, 0xe0, 0x23, 0x29, 0xce, 0xc3, 0x10, 0xd1, 0xc5, 0xc2, + 0x26, 0xa6, 0xcf, 0xab, 0x22, 0x58, 0xfc, 0x0f, 0x6e, 0x80, 0x00, 0x51, 0xe9, 0x47, 0xbe, 0xf5, + 0xda, 0x94, 0xf4, 0xca, 0x6b, 0x53, 0xd2, 0x1f, 0xbe, 0x36, 0x25, 0x7d, 0xfa, 0xdb, 0x53, 0x87, + 0x5e, 0xf9, 0xf6, 0xd4, 0xa1, 0xdf, 0xfd, 0xf6, 0xd4, 0xa1, 0xce, 0xc7, 0xc6, 0xb0, 0x68, 0x2c, + 0x1a, 0xec, 0xc0, 0xf8, 0xfd, 0x72, 0xe0, 0xb8, 0xb8, 0x6e, 0x78, 0xa7, 0xb5, 0xee, 0x26, 0x07, + 0x3e, 0x16, 0x87, 0xa9, 0xaa, 0x61, 0x37, 0x0d, 0x7b, 0x76, 0x4b, 0xb5, 0xf1, 0xec, 0x8d, 0xc7, + 0xb7, 0xb0, 0xa3, 0x3e, 0x3e, 0x5b, 0x35, 0x34, 0x9d, 0x1f, 0xfb, 0x8e, 0xb3, 0xfe, 0x02, 0xe9, + 0x2f, 0xf0, 0xfe, 0x7c, 0xc7, 0x13, 0x62, 0x79, 0x11, 0x12, 0xf3, 0x86, 0xa6, 0xa3, 0x09, 0x48, + 0xd6, 0xb0, 0x6e, 0x34, 0xf9, 0x05, 0x30, 0xd6, 0x40, 0xf7, 0xc1, 0x80, 0xda, 0x34, 0x5a, 0xba, + 0xc3, 0x8e, 0xcb, 0x4b, 0x99, 0x6f, 0xdd, 0x9a, 0x3e, 0xf4, 0x7b, 0xb7, 0xa6, 0xe3, 0x4b, 0xba, + 0xa3, 0xf0, 0xae, 0x62, 0xe2, 0x8d, 0x97, 0xa7, 0x25, 0xf9, 0x32, 0x0c, 0x2e, 0xe0, 0xea, 0x41, + 0x78, 0x2d, 0xe0, 0x6a, 0x88, 0xd7, 0x43, 0x90, 0x5a, 0xd2, 0x1d, 0x76, 0x45, 0xef, 0x38, 0xc4, + 0x35, 0x9d, 0xdd, 0xfa, 0x08, 0x8d, 0x4f, 0xe0, 0x04, 0x75, 0x01, 0x57, 0x5d, 0xd4, 0x1a, 0xae, + 0x86, 0x51, 0x09, 0x7b, 0x02, 0x2f, 0x2d, 0xfc, 0xee, 0xbf, 0x9f, 0x3a, 0xf4, 0xc2, 0x6b, 0x53, + 0x87, 0xba, 0xcd, 0x4f, 0xc0, 0xfc, 0xdc, 0xc4, 0xec, 0xcf, 0xa3, 0x76, 0xed, 0xfa, 0x2c, 0x09, + 0x2d, 0x7b, 0x6b, 0x80, 0xdd, 0x6a, 0x86, 0x4f, 0xc7, 0x60, 0x3a, 0x7c, 0xa4, 0x4e, 0xfc, 0xd8, + 0x76, 0xd4, 0xa6, 0xd9, 0xed, 0xc5, 0xa9, 0x0b, 0x90, 0xde, 0x14, 0x38, 0x28, 0x07, 0x83, 0x36, + 0xae, 0x1a, 0x7a, 0xcd, 0xa6, 0x22, 0xc7, 0x15, 0xd1, 0x24, 0x06, 0xd4, 0x55, 0xdd, 0xb0, 0xf9, + 0x75, 0x4d, 0xd6, 0x28, 0xfd, 0x94, 0xd4, 0x9f, 0x63, 0x8d, 0xb8, 0x43, 0x51, 0xf3, 0xac, 0x4b, + 0xef, 0x7f, 0x78, 0xbf, 0xa7, 0x11, 0x54, 0x3d, 0x4f, 0x05, 0xdf, 0xa3, 0x87, 0xa9, 0xf0, 0xa3, + 0x87, 0x67, 0x71, 0xa3, 0x71, 0x45, 0x37, 0x6e, 0xea, 0x9b, 0x01, 0x93, 0xfc, 0x2b, 0x09, 0x66, + 0xe8, 0x85, 0x75, 0xab, 0xa9, 0xe9, 0xce, 0x6c, 0x43, 0xdb, 0xb2, 0x67, 0xb7, 0x34, 0xc7, 0x66, + 0x96, 0xe3, 0x36, 0x99, 0xf0, 0x30, 0x0a, 0x04, 0xa3, 0x40, 0x30, 0xe4, 0xd3, 0x90, 0x2a, 0x69, + 0xce, 0x9c, 0x65, 0xa9, 0x7b, 0x08, 0x41, 0x82, 0xc0, 0xb8, 0x51, 0xe8, 0x6f, 0x62, 0x11, 0xdc, + 0xc0, 0x4d, 0x9b, 0x3e, 0xf4, 0x4a, 0x28, 0xac, 0x51, 0xba, 0xda, 0x75, 0x26, 0x2f, 0xf8, 0x34, + 0xf5, 0x89, 0xe4, 0xfb, 0xc9, 0x22, 0xa1, 0x93, 0xb8, 0xae, 0x3e, 0x5f, 0x4b, 0xc0, 0x71, 0x1f, + 0x42, 0xd5, 0xda, 0x33, 0x1d, 0x1a, 0x92, 0xc6, 0x36, 0x57, 0x66, 0xcc, 0xa7, 0x0c, 0xeb, 0xee, + 0x12, 0x66, 0xdb, 0x90, 0x5c, 0x27, 0x74, 0x44, 0x11, 0xc7, 0x70, 0xd4, 0x06, 0xd7, 0x8e, 0x35, + 0x08, 0x94, 0x5d, 0xda, 0x8f, 0x31, 0xa8, 0x26, 0xee, 0xeb, 0x37, 0xb0, 0xba, 0xcd, 0xee, 0x3e, + 0xc6, 0xe9, 0xb3, 0xcf, 0x14, 0x01, 0xd0, 0x6b, 0x8e, 0x13, 0x90, 0x54, 0x5b, 0xec, 0xb1, 0x5d, + 0xfc, 0xc4, 0x90, 0xc2, 0x1a, 0xf2, 0x15, 0x18, 0xe4, 0x8f, 0x0a, 0x50, 0x16, 0xe2, 0xd7, 0xf1, + 0x1e, 0x1d, 0x67, 0x48, 0x21, 0x3f, 0x51, 0x01, 0x92, 0x54, 0x78, 0x7e, 0xa9, 0x3b, 0x57, 0x68, + 0x93, 0xbe, 0x40, 0x85, 0x54, 0x18, 0x9a, 0x7c, 0x19, 0x52, 0x0b, 0x46, 0x53, 0xd3, 0x8d, 0x20, + 0xb7, 0x34, 0xe3, 0x46, 0x65, 0x36, 0x5b, 0x3c, 0x9c, 0x15, 0xd6, 0x40, 0x93, 0x30, 0xc0, 0xee, + 0xc2, 0xf2, 0x47, 0x8f, 0xbc, 0x25, 0xcf, 0xc3, 0x20, 0xe5, 0xbd, 0x66, 0x92, 0xf9, 0x75, 0x2f, + 0x22, 0xa5, 0xf9, 0x9b, 0x11, 0x9c, 0x7d, 0xcc, 0x13, 0x16, 0x41, 0xa2, 0xa6, 0x3a, 0x2a, 0xd7, + 0x9b, 0xfe, 0x96, 0x9f, 0x82, 0x14, 0x67, 0x62, 0xa3, 0x53, 0x10, 0x37, 0x4c, 0x9b, 0x3f, 0x3c, + 0xcc, 0x77, 0x53, 0x65, 0xcd, 0x2c, 0x25, 0x48, 0x22, 0x50, 0x08, 0x72, 0x49, 0xe9, 0xea, 0x2f, + 0xe7, 0xfa, 0xf7, 0x17, 0x36, 0x8c, 0xeb, 0x2c, 0x5f, 0x8e, 0xc1, 0x94, 0xaf, 0xf7, 0x06, 0xb6, + 0x48, 0xbd, 0x1c, 0x70, 0x7d, 0xe4, 0x13, 0x92, 0xf7, 0x77, 0x71, 0x97, 0x77, 0x43, 0x7c, 0xce, + 0x34, 0x51, 0x1e, 0x52, 0xec, 0x21, 0xa1, 0xc1, 0xfc, 0x25, 0xa1, 0xb8, 0x6d, 0xd2, 0x67, 0x1b, + 0xdb, 0xce, 0x4d, 0xd5, 0x72, 0x5f, 0x17, 0x11, 0x6d, 0xf9, 0x3c, 0xa4, 0xe7, 0x0d, 0xdd, 0xc6, + 0xba, 0xdd, 0xa2, 0xa1, 0xb3, 0xd5, 0x30, 0xaa, 0xd7, 0x39, 0x07, 0xd6, 0x20, 0x06, 0x57, 0x4d, + 0x93, 0x52, 0x26, 0x14, 0xf2, 0x93, 0xa5, 0xde, 0xd2, 0x46, 0x57, 0x13, 0x9d, 0xef, 0xdf, 0x44, + 0x5c, 0x49, 0xd7, 0x46, 0xbf, 0x2f, 0xc1, 0xb1, 0xf6, 0x80, 0xba, 0x8e, 0xf7, 0xec, 0x7e, 0xe3, + 0xe9, 0x1c, 0xa4, 0xd7, 0xe9, 0x3b, 0x9b, 0x57, 0xf0, 0x1e, 0xca, 0xc3, 0x20, 0xae, 0x9d, 0x3a, + 0x73, 0xe6, 0xf1, 0xf3, 0xcc, 0xdb, 0x2f, 0x1d, 0x52, 0x04, 0xa0, 0x98, 0x22, 0x5a, 0xbd, 0xf1, + 0xe5, 0x69, 0xa9, 0x94, 0x84, 0xb8, 0xdd, 0x6a, 0xde, 0x55, 0x1f, 0xf8, 0x42, 0x32, 0x90, 0x00, + 0x59, 0x46, 0xbd, 0xa1, 0x36, 0xb4, 0x9a, 0xea, 0xbd, 0x4d, 0x9b, 0xf5, 0xe9, 0x48, 0x31, 0x3a, + 0xab, 0x98, 0xdf, 0xd7, 0x52, 0xf2, 0xaf, 0x48, 0x30, 0x74, 0x4d, 0x70, 0xde, 0xc0, 0x0e, 0xba, + 0x00, 0xe0, 0x8e, 0x24, 0xc2, 0xe2, 0x68, 0x21, 0x3c, 0x56, 0xc1, 0xa5, 0x51, 0x7c, 0xe8, 0xe8, + 0x49, 0xea, 0x68, 0xa6, 0x61, 0xf3, 0x57, 0x04, 0x22, 0x48, 0x5d, 0x64, 0xf4, 0x08, 0x20, 0x9a, + 0xc1, 0x2a, 0x37, 0x0c, 0x47, 0xd3, 0xeb, 0x15, 0xd3, 0xb8, 0xc9, 0x5f, 0xbc, 0x8a, 0x2b, 0x59, + 0xda, 0x73, 0x8d, 0x76, 0xac, 0x13, 0x38, 0x11, 0x3a, 0xed, 0x72, 0x21, 0xeb, 0x9f, 0x5a, 0xab, + 0x59, 0xd8, 0xb6, 0x79, 0x92, 0x12, 0x4d, 0x74, 0x01, 0x06, 0xcd, 0xd6, 0x56, 0x45, 0x64, 0x84, + 0xcc, 0xa9, 0x63, 0x9d, 0xe2, 0x5b, 0xcc, 0x3f, 0x8f, 0xf0, 0x01, 0xb3, 0xb5, 0x45, 0xbc, 0xe1, + 0x5e, 0x18, 0xea, 0x20, 0x4c, 0xe6, 0x86, 0x27, 0x07, 0x7d, 0x15, 0x98, 0x6b, 0x50, 0x31, 0x2d, + 0xcd, 0xb0, 0x34, 0x67, 0x8f, 0x3e, 0xe1, 0x8f, 0x2b, 0x59, 0xd1, 0xb1, 0xce, 0xe1, 0xf2, 0x75, + 0x18, 0xdd, 0xd0, 0x9a, 0x26, 0xbd, 0x93, 0xc2, 0x25, 0x3f, 0xe3, 0xc9, 0x27, 0x45, 0xcb, 0xd7, + 0x55, 0xb2, 0x58, 0x9b, 0x64, 0xa5, 0x67, 0xba, 0x7a, 0xe7, 0x93, 0xfd, 0x7b, 0x67, 0xb0, 0x60, + 0xf9, 0x93, 0x7c, 0x20, 0xf8, 0xf8, 0x72, 0xef, 0x4b, 0x4f, 0xbd, 0x3a, 0x66, 0x54, 0xd9, 0x93, + 0x8f, 0x2c, 0x02, 0xf2, 0xfb, 0x2f, 0xab, 0xf9, 0x88, 0x44, 0x9a, 0x8f, 0x0c, 0x32, 0xf9, 0x3c, + 0x0c, 0xaf, 0xab, 0x96, 0xb3, 0x81, 0x9d, 0x4b, 0x58, 0xad, 0x61, 0x2b, 0xb8, 0xee, 0x0e, 0x8b, + 0x75, 0x17, 0x41, 0x82, 0x2e, 0xae, 0x6c, 0xdd, 0xa1, 0xbf, 0xe5, 0x1d, 0x48, 0xd0, 0x7b, 0x40, + 0xee, 0x9a, 0xcc, 0x29, 0xd8, 0x9a, 0x4c, 0xb2, 0xe9, 0x9e, 0x83, 0x6d, 0x4e, 0xc2, 0x1a, 0xe8, + 0xb4, 0x58, 0x59, 0xe3, 0xfb, 0xaf, 0xac, 0xdc, 0x55, 0xf9, 0xfa, 0xda, 0x80, 0xc1, 0x12, 0x49, + 0xc6, 0x4b, 0x0b, 0xae, 0x20, 0x92, 0x27, 0x08, 0x5a, 0x81, 0x51, 0x53, 0xb5, 0x1c, 0x7a, 0x01, + 0x7a, 0x87, 0x6a, 0xc1, 0xa3, 0x61, 0xba, 0x3d, 0x36, 0x03, 0xca, 0xf2, 0x51, 0x86, 0x4d, 0x3f, + 0x50, 0xfe, 0xa3, 0x04, 0x0c, 0x70, 0x63, 0xbc, 0x1b, 0x06, 0xb9, 0x59, 0xb9, 0xff, 0x1e, 0x2f, + 0xb4, 0x2f, 0x4d, 0x05, 0x77, 0x09, 0xe1, 0xfc, 0x04, 0x0d, 0x7a, 0x00, 0x52, 0xd5, 0x1d, 0x55, + 0xd3, 0x2b, 0x5a, 0x4d, 0xd4, 0xf2, 0xaf, 0xdd, 0x9a, 0x1e, 0x9c, 0x27, 0xb0, 0xa5, 0x05, 0x65, + 0x90, 0x76, 0x2e, 0xd5, 0x48, 0x2d, 0xb0, 0x83, 0xb5, 0xfa, 0x8e, 0xc3, 0x63, 0x90, 0xb7, 0xd0, + 0x39, 0x48, 0x10, 0x97, 0xe1, 0xaf, 0xc7, 0xe4, 0xdb, 0xf6, 0x58, 0x6e, 0xdd, 0x5a, 0x4a, 0x91, + 0x81, 0x3f, 0xfd, 0x07, 0xd3, 0x92, 0x42, 0x29, 0xd0, 0x3c, 0x0c, 0x37, 0x54, 0xdb, 0xa9, 0xd0, + 0x35, 0x8c, 0x0c, 0x9f, 0xa4, 0x2c, 0x8e, 0xb4, 0x1b, 0x84, 0x1b, 0x96, 0x8b, 0x9e, 0x21, 0x54, + 0x0c, 0x54, 0x43, 0x27, 0x20, 0x4b, 0x99, 0x54, 0x8d, 0x66, 0x53, 0x73, 0x58, 0x75, 0x35, 0x40, + 0xed, 0x3e, 0x42, 0xe0, 0xf3, 0x14, 0x4c, 0x6b, 0xac, 0xa3, 0x90, 0xa6, 0x17, 0xf2, 0x29, 0x0a, + 0xbb, 0x7c, 0x96, 0x22, 0x00, 0xda, 0xf9, 0x20, 0x8c, 0x7a, 0x19, 0x94, 0xa1, 0xa4, 0x18, 0x17, + 0x0f, 0x4c, 0x11, 0x1f, 0x83, 0x09, 0x1d, 0xef, 0xd2, 0xeb, 0x70, 0x01, 0xec, 0x34, 0xc5, 0x46, + 0xa4, 0xef, 0x5a, 0x90, 0xe2, 0x5d, 0x30, 0x52, 0x15, 0xc6, 0x67, 0xb8, 0x40, 0x71, 0x87, 0x5d, + 0x28, 0x45, 0x3b, 0x02, 0x29, 0xd5, 0x34, 0x19, 0x42, 0x86, 0x67, 0x50, 0xd3, 0xa4, 0x5d, 0x27, + 0x61, 0x8c, 0xea, 0x68, 0x61, 0xbb, 0xd5, 0x70, 0x38, 0x93, 0x21, 0x8a, 0x33, 0x4a, 0x3a, 0x14, + 0x06, 0xa7, 0xb8, 0xf7, 0xc1, 0x30, 0xbe, 0xa1, 0xd5, 0xb0, 0x5e, 0xc5, 0x0c, 0x6f, 0x98, 0xe2, + 0x0d, 0x09, 0x20, 0x45, 0x7a, 0x08, 0xdc, 0xcc, 0x58, 0x11, 0x59, 0x7b, 0x84, 0xf1, 0x13, 0xf0, + 0x39, 0x06, 0x96, 0x1f, 0x81, 0xc4, 0x82, 0xea, 0xa8, 0xa4, 0xc4, 0x70, 0x76, 0xd9, 0x52, 0x34, + 0xa4, 0x90, 0x9f, 0x1d, 0xc3, 0xed, 0x8d, 0x18, 0x24, 0xae, 0x19, 0x0e, 0x46, 0x4f, 0xf8, 0xca, + 0xc2, 0x91, 0x4e, 0x3e, 0xbe, 0xa1, 0xd5, 0x75, 0x5c, 0x5b, 0xb1, 0xeb, 0xbe, 0x37, 0x6a, 0x3d, + 0x17, 0x8b, 0x05, 0x5c, 0x6c, 0x02, 0x92, 0x96, 0xd1, 0xd2, 0x6b, 0xe2, 0x2e, 0x17, 0x6d, 0xa0, + 0x32, 0xa4, 0x5c, 0xcf, 0x49, 0x44, 0x79, 0xce, 0x28, 0xf1, 0x1c, 0xe2, 0xd7, 0x1c, 0xa0, 0x0c, + 0x6e, 0x71, 0x07, 0x2a, 0x41, 0xda, 0x4d, 0x79, 0xdc, 0x03, 0x7b, 0x73, 0x62, 0x8f, 0x8c, 0x2c, + 0x41, 0xae, 0x3f, 0xb8, 0x06, 0x65, 0x5e, 0x98, 0x75, 0x3b, 0xb8, 0x45, 0x03, 0xae, 0xc6, 0xdf, + 0xee, 0x1d, 0xa4, 0x7a, 0x79, 0xae, 0xc6, 0xde, 0xf0, 0x3d, 0x06, 0x69, 0x5b, 0xab, 0xeb, 0xaa, + 0xd3, 0xb2, 0x30, 0xf7, 0x46, 0x0f, 0x20, 0x7f, 0x26, 0x06, 0x03, 0xcc, 0xbb, 0x7d, 0x76, 0x93, + 0x3a, 0xdb, 0x2d, 0xd6, 0xcd, 0x6e, 0xf1, 0x83, 0xdb, 0x6d, 0x0e, 0xc0, 0x15, 0xc6, 0xe6, 0x2f, + 0x5d, 0x76, 0xa8, 0x33, 0x98, 0x88, 0x1b, 0x5a, 0x9d, 0x07, 0xaf, 0x8f, 0xc8, 0xf5, 0xa0, 0xa4, + 0x2f, 0x4f, 0x5e, 0x80, 0xf4, 0x96, 0xe6, 0x54, 0x54, 0xb2, 0x79, 0xa4, 0x26, 0xcc, 0x9c, 0x9a, + 0x2a, 0x74, 0xda, 0x65, 0x16, 0xc4, 0x16, 0x53, 0x49, 0x6d, 0xf1, 0x5f, 0xf2, 0xef, 0x4b, 0xa4, + 0x56, 0xe6, 0x03, 0xa2, 0x39, 0x18, 0x16, 0x8a, 0x56, 0xb6, 0x1b, 0x6a, 0x9d, 0x3b, 0xe3, 0xf1, + 0xae, 0xda, 0x5e, 0x6c, 0xa8, 0x75, 0x25, 0xc3, 0x15, 0x24, 0x8d, 0xce, 0x13, 0x1b, 0xeb, 0x32, + 0xb1, 0x01, 0x4f, 0x8a, 0x1f, 0xcc, 0x93, 0x02, 0x73, 0x9e, 0x08, 0xcf, 0xf9, 0xd7, 0x63, 0x74, + 0xcf, 0x64, 0x1a, 0xb6, 0xda, 0x78, 0x3b, 0x42, 0xec, 0x28, 0xa4, 0x4d, 0xa3, 0x51, 0x61, 0x3d, + 0xec, 0xd2, 0x64, 0xca, 0x34, 0x1a, 0x4a, 0x9b, 0x1f, 0x25, 0xef, 0x50, 0xfc, 0x0d, 0xdc, 0x01, + 0xab, 0x0d, 0x86, 0xad, 0x66, 0xc1, 0x10, 0x33, 0x05, 0x5f, 0x30, 0x1f, 0x23, 0x36, 0xa0, 0x2b, + 0xb0, 0xd4, 0xbe, 0xc0, 0x33, 0xb1, 0x19, 0xa6, 0xc2, 0xf1, 0x08, 0x05, 0x5b, 0x5f, 0x3a, 0x6d, + 0xb6, 0xfd, 0x7e, 0xae, 0x70, 0x3c, 0xf9, 0xa7, 0x24, 0x80, 0x65, 0x62, 0x59, 0xaa, 0x2f, 0x59, + 0xea, 0x6c, 0x2a, 0x42, 0x25, 0x30, 0xf2, 0x54, 0xb7, 0x49, 0xe3, 0xe3, 0x0f, 0xd9, 0x7e, 0xb9, + 0xe7, 0x61, 0xd8, 0x73, 0x46, 0x1b, 0x0b, 0x61, 0xa6, 0xf6, 0x29, 0xee, 0x37, 0xb0, 0xa3, 0x0c, + 0xdd, 0xf0, 0xb5, 0xe4, 0x7f, 0x22, 0x41, 0x9a, 0xca, 0xb4, 0x82, 0x1d, 0x35, 0x30, 0x87, 0xd2, + 0xc1, 0xe7, 0xf0, 0x38, 0x00, 0x63, 0x63, 0x6b, 0xcf, 0x63, 0xee, 0x59, 0x69, 0x0a, 0xd9, 0xd0, + 0x9e, 0xc7, 0xe8, 0xac, 0x6b, 0xf0, 0xf8, 0xfe, 0x06, 0x17, 0xc5, 0x3f, 0x37, 0xfb, 0x3d, 0x30, + 0x48, 0xbf, 0x7a, 0xb2, 0x6b, 0xf3, 0x7a, 0x7e, 0x40, 0x6f, 0x35, 0x37, 0x77, 0x6d, 0xf9, 0x39, + 0x18, 0xdc, 0xdc, 0x65, 0x47, 0x30, 0x47, 0x21, 0x6d, 0x19, 0x06, 0x5f, 0xf8, 0x59, 0xc1, 0x95, + 0x22, 0x00, 0xba, 0xce, 0x89, 0x63, 0x87, 0x98, 0x77, 0xec, 0xe0, 0x9d, 0x9b, 0xc4, 0x7b, 0x3a, + 0x37, 0x39, 0xf9, 0x6f, 0x24, 0xc8, 0xf8, 0xf2, 0x03, 0x7a, 0x1c, 0x0e, 0x97, 0x96, 0xd7, 0xe6, + 0xaf, 0x54, 0x96, 0x16, 0x2a, 0x17, 0x97, 0xe7, 0x16, 0xbd, 0xd7, 0x02, 0xf2, 0x93, 0x2f, 0xbe, + 0x34, 0x83, 0x7c, 0xb8, 0x57, 0xf5, 0xeb, 0xba, 0x71, 0x53, 0x47, 0xb3, 0x30, 0x11, 0x24, 0x99, + 0x2b, 0x6d, 0x94, 0x57, 0x37, 0xb3, 0x52, 0xfe, 0xf0, 0x8b, 0x2f, 0xcd, 0x8c, 0xf9, 0x28, 0xe6, + 0xb6, 0x6c, 0xac, 0x3b, 0xed, 0x04, 0xf3, 0x6b, 0x2b, 0x2b, 0x4b, 0x9b, 0xd9, 0x58, 0x1b, 0x01, + 0x5f, 0x01, 0x1e, 0x82, 0xb1, 0x20, 0xc1, 0xea, 0xd2, 0x72, 0x36, 0x9e, 0x47, 0x2f, 0xbe, 0x34, + 0x33, 0xe2, 0xc3, 0x5e, 0xd5, 0x1a, 0xf9, 0xd4, 0x27, 0xbe, 0x32, 0x75, 0xe8, 0xe7, 0x7e, 0x76, + 0x4a, 0x22, 0x9a, 0x0d, 0x07, 0x72, 0x04, 0x7a, 0x04, 0xee, 0xd9, 0x58, 0x5a, 0x5c, 0x2d, 0x2f, + 0x54, 0x56, 0x36, 0x16, 0x2b, 0xec, 0x73, 0x08, 0xae, 0x76, 0xa3, 0x2f, 0xbe, 0x34, 0x93, 0xe1, + 0x2a, 0x75, 0xc3, 0x5e, 0x57, 0xca, 0xd7, 0xd6, 0x36, 0xcb, 0x59, 0x89, 0x61, 0xaf, 0x5b, 0xf8, + 0x86, 0xe1, 0xb0, 0xcf, 0x22, 0x3d, 0x06, 0x47, 0x3a, 0x60, 0xbb, 0x8a, 0x8d, 0xbd, 0xf8, 0xd2, + 0xcc, 0xf0, 0xba, 0x85, 0x59, 0xfc, 0x50, 0x8a, 0x02, 0xe4, 0xda, 0x29, 0xd6, 0xd6, 0xd7, 0x36, + 0xe6, 0x96, 0xb3, 0x33, 0xf9, 0xec, 0x8b, 0x2f, 0xcd, 0x0c, 0x89, 0x64, 0x48, 0xf0, 0x3d, 0xcd, + 0xee, 0xe6, 0xc6, 0xeb, 0x2f, 0xc7, 0x60, 0xaa, 0xed, 0xf2, 0x35, 0x7f, 0x64, 0xd1, 0xed, 0xa0, + 0xb8, 0x08, 0xa9, 0x05, 0xf1, 0x24, 0xa4, 0xdf, 0x73, 0xe2, 0x9f, 0xec, 0xf3, 0x9c, 0x78, 0x58, + 0x8c, 0x24, 0x8e, 0x89, 0x4f, 0x46, 0x1f, 0x13, 0x0b, 0xf9, 0x0f, 0x70, 0x4a, 0xfc, 0x1f, 0x1e, + 0x86, 0xfb, 0xf9, 0xe1, 0xba, 0xed, 0xa8, 0xd7, 0x35, 0xbd, 0xee, 0x3e, 0xc2, 0xe0, 0x6d, 0x6e, + 0x94, 0x49, 0xfe, 0x14, 0x43, 0x40, 0xf7, 0x7d, 0x90, 0x91, 0xdf, 0x77, 0x6f, 0x1b, 0xbd, 0x67, + 0x8d, 0x98, 0xa1, 0x7c, 0xc4, 0x23, 0x17, 0xf9, 0x93, 0x12, 0x8c, 0x5c, 0xd2, 0x6c, 0xc7, 0xb0, + 0xb4, 0xaa, 0xda, 0xa0, 0x6f, 0x39, 0x9c, 0xed, 0x75, 0xd1, 0x08, 0xe5, 0xb0, 0xa7, 0x61, 0xe0, + 0x86, 0xda, 0x60, 0xd9, 0x3a, 0x4e, 0x3f, 0xca, 0xd0, 0xd9, 0x10, 0x5e, 0xce, 0x16, 0x0c, 0x18, + 0x99, 0xfc, 0x8b, 0x31, 0x18, 0xa5, 0x51, 0x6e, 0xb3, 0xcf, 0xf5, 0x90, 0x1d, 0x6a, 0x09, 0x12, + 0x96, 0xea, 0xf0, 0x43, 0xd7, 0x52, 0x81, 0x3f, 0x1c, 0x79, 0x20, 0xfa, 0x81, 0x47, 0x61, 0x01, + 0x57, 0x15, 0x4a, 0x8b, 0x7e, 0x18, 0x52, 0x4d, 0x75, 0xb7, 0x42, 0xf9, 0xb0, 0x7d, 0xdf, 0x5c, + 0x7f, 0x7c, 0x6e, 0xdf, 0x9a, 0x1e, 0xdd, 0x53, 0x9b, 0x8d, 0xa2, 0x2c, 0xf8, 0xc8, 0xca, 0x60, + 0x53, 0xdd, 0x25, 0x22, 0x22, 0x13, 0x46, 0x09, 0xb4, 0xba, 0xa3, 0xea, 0x75, 0xcc, 0x06, 0xa1, + 0x47, 0xc8, 0xa5, 0x4b, 0x7d, 0x0f, 0x32, 0xe9, 0x0d, 0xe2, 0x63, 0x27, 0x2b, 0xc3, 0x4d, 0x75, + 0x77, 0x9e, 0x02, 0xc8, 0x88, 0xc5, 0xd4, 0xe7, 0x5e, 0x9e, 0x3e, 0x44, 0x1f, 0x38, 0xbd, 0x2a, + 0x01, 0x78, 0x16, 0x43, 0x3f, 0x0c, 0xd9, 0xaa, 0xdb, 0xa2, 0xb4, 0x36, 0x9f, 0xc3, 0x07, 0xbb, + 0xcd, 0x45, 0xc8, 0xde, 0xac, 0xe8, 0x78, 0xe5, 0xd6, 0xb4, 0xa4, 0x8c, 0x56, 0x43, 0x53, 0xf1, + 0x01, 0xc8, 0xb4, 0xcc, 0x9a, 0xea, 0xe0, 0x0a, 0xdd, 0x05, 0xc7, 0x22, 0x0b, 0x98, 0x29, 0xc2, + 0xeb, 0xf6, 0xad, 0x69, 0xc4, 0xd4, 0xf2, 0x11, 0xcb, 0xb4, 0xac, 0x01, 0x06, 0x21, 0x04, 0x3e, + 0x9d, 0x7e, 0x4b, 0x82, 0xcc, 0x82, 0xef, 0xb6, 0x51, 0x0e, 0x06, 0x9b, 0x86, 0xae, 0x5d, 0xe7, + 0xfe, 0x98, 0x56, 0x44, 0x13, 0xe5, 0x21, 0xc5, 0x5e, 0xfc, 0x72, 0xf6, 0xc4, 0x51, 0xb2, 0x68, + 0x13, 0xaa, 0x9b, 0x78, 0xcb, 0xd6, 0xc4, 0x6c, 0x28, 0xa2, 0x89, 0x2e, 0x42, 0xd6, 0xc6, 0xd5, + 0x96, 0xa5, 0x39, 0x7b, 0x95, 0xaa, 0xa1, 0x3b, 0x6a, 0xd5, 0x61, 0xaf, 0x10, 0x95, 0x8e, 0xde, + 0xbe, 0x35, 0x7d, 0x0f, 0x93, 0x35, 0x8c, 0x21, 0x2b, 0xa3, 0x02, 0x34, 0xcf, 0x20, 0x64, 0x84, + 0x1a, 0x76, 0x54, 0xad, 0x61, 0xd3, 0x9a, 0x30, 0xad, 0x88, 0xa6, 0x4f, 0x97, 0x9f, 0x18, 0xf4, + 0x1f, 0x1c, 0x5e, 0x84, 0xac, 0x61, 0x62, 0x2b, 0x50, 0x61, 0x4b, 0xe1, 0x91, 0xc3, 0x18, 0xb2, + 0x32, 0x2a, 0x40, 0xa2, 0xfa, 0xbe, 0x48, 0xa6, 0x59, 0x6c, 0xb3, 0xcd, 0xd6, 0x96, 0x38, 0x6f, + 0x0c, 0xf0, 0x09, 0x63, 0xc8, 0x64, 0x42, 0x39, 0x68, 0x9d, 0x42, 0x48, 0x85, 0xfc, 0x9c, 0xaa, + 0x35, 0xc4, 0xcb, 0xad, 0x0a, 0x6f, 0xa1, 0x25, 0x18, 0xb0, 0x1d, 0xd5, 0x69, 0xb1, 0x5a, 0x24, + 0x59, 0x7a, 0xfc, 0x7f, 0xdf, 0x9a, 0x7e, 0xb4, 0x07, 0x27, 0x2e, 0x19, 0x7a, 0x6d, 0x83, 0x12, + 0x2a, 0x9c, 0x01, 0xba, 0x08, 0x03, 0x8e, 0x71, 0x1d, 0xeb, 0xdc, 0x46, 0x7d, 0x05, 0x30, 0x7d, + 0x56, 0xcb, 0xa8, 0x91, 0x03, 0xd9, 0x1a, 0x6e, 0xe0, 0x3a, 0x2b, 0x08, 0x77, 0x54, 0xb2, 0x11, + 0xa3, 0x1f, 0xa2, 0x2a, 0x2d, 0xf5, 0x1d, 0x65, 0xdc, 0x40, 0x61, 0x7e, 0xb2, 0x32, 0xea, 0x82, + 0x36, 0x28, 0x04, 0x5d, 0x09, 0xdc, 0x7b, 0xe3, 0x5f, 0x6b, 0xbb, 0xaf, 0x5b, 0x28, 0xf9, 0x9c, + 0x56, 0x1c, 0xdf, 0xf8, 0x6f, 0xcd, 0x5d, 0x84, 0x6c, 0x4b, 0xdf, 0x32, 0x74, 0xfa, 0x42, 0x1a, + 0xdf, 0x99, 0x90, 0xad, 0x6e, 0xdc, 0x3f, 0x6b, 0x61, 0x0c, 0x59, 0x19, 0x75, 0x41, 0x97, 0xd8, + 0xfe, 0xa5, 0x06, 0x23, 0x1e, 0x16, 0x8d, 0xc4, 0x74, 0x64, 0x24, 0xde, 0xcb, 0x23, 0xf1, 0x70, + 0x78, 0x14, 0x2f, 0x18, 0x87, 0x5d, 0x20, 0x21, 0x43, 0x97, 0x00, 0xbc, 0xf8, 0xa7, 0xc7, 0x38, + 0x99, 0x53, 0x72, 0x74, 0x12, 0x11, 0x5b, 0x5f, 0x8f, 0x16, 0x7d, 0x18, 0xc6, 0x9b, 0x9a, 0x5e, + 0xb1, 0x71, 0x63, 0xbb, 0xc2, 0x0d, 0x4c, 0x58, 0xd2, 0xef, 0x89, 0x94, 0x96, 0xfb, 0xf3, 0x87, + 0xdb, 0xb7, 0xa6, 0xf3, 0x3c, 0x47, 0xb6, 0xb3, 0x94, 0x95, 0xb1, 0xa6, 0xa6, 0x6f, 0xe0, 0xc6, + 0xf6, 0x82, 0x0b, 0x2b, 0x0e, 0x7d, 0xe2, 0xe5, 0xe9, 0x43, 0x3c, 0x1e, 0x0f, 0xc9, 0x67, 0xe9, + 0xc3, 0x07, 0x1e, 0x47, 0xd8, 0x26, 0xbb, 0x29, 0x55, 0x34, 0xe8, 0x81, 0x4f, 0x5a, 0xf1, 0x00, + 0x2c, 0x8e, 0x5f, 0xf8, 0x77, 0x33, 0x92, 0xfc, 0x0b, 0x12, 0x0c, 0x2c, 0x5c, 0x5b, 0x57, 0x35, + 0x0b, 0x2d, 0xc1, 0x98, 0xe7, 0x39, 0xc1, 0x28, 0x3e, 0x76, 0xfb, 0xd6, 0x74, 0x2e, 0xec, 0x5c, + 0x6e, 0x18, 0x7b, 0x0e, 0x2c, 0xe2, 0x78, 0xa9, 0xdb, 0x96, 0x3b, 0xc0, 0xaa, 0x0d, 0x45, 0x6e, + 0xdf, 0x90, 0x87, 0xd4, 0x2c, 0xc3, 0x20, 0x93, 0xd6, 0x46, 0x45, 0x48, 0x9a, 0xe4, 0x07, 0x7f, + 0xb2, 0x32, 0xd5, 0xd5, 0x79, 0x29, 0xbe, 0x7b, 0xce, 0x4b, 0x48, 0xe4, 0xcf, 0xc4, 0x00, 0x16, + 0xae, 0x5d, 0xdb, 0xb4, 0x34, 0xb3, 0x81, 0x9d, 0x3b, 0xa9, 0xf9, 0x26, 0x1c, 0xf6, 0xed, 0xef, + 0xac, 0x6a, 0x48, 0xfb, 0x99, 0xdb, 0xb7, 0xa6, 0x8f, 0x85, 0xb5, 0xf7, 0xa1, 0xc9, 0xca, 0xb8, + 0xb7, 0xd3, 0xb3, 0xaa, 0x1d, 0xb9, 0xd6, 0x6c, 0xc7, 0xe5, 0x1a, 0xef, 0xce, 0xd5, 0x87, 0xe6, + 0xe7, 0xba, 0x60, 0x3b, 0x9d, 0x4d, 0xbb, 0x01, 0x19, 0xcf, 0x24, 0x36, 0x5a, 0x80, 0x94, 0xc3, + 0x7f, 0x73, 0x0b, 0xcb, 0xdd, 0x2d, 0x2c, 0xc8, 0xb8, 0x95, 0x5d, 0x4a, 0xf9, 0x4f, 0x25, 0x00, + 0xcf, 0x67, 0x7f, 0x30, 0x5d, 0x8c, 0xa4, 0x72, 0x9e, 0x78, 0xe3, 0x07, 0xaa, 0xc5, 0x38, 0x75, + 0xc8, 0x9e, 0x3f, 0x1e, 0x83, 0xf1, 0xab, 0x22, 0xf3, 0xfc, 0xc0, 0xdb, 0x60, 0x1d, 0x06, 0xb1, + 0xee, 0x58, 0x1a, 0x35, 0x02, 0x99, 0xed, 0xc7, 0xba, 0xcd, 0x76, 0x07, 0x9d, 0xe8, 0x17, 0x55, + 0xc4, 0x33, 0x09, 0xce, 0x26, 0x64, 0x8d, 0x4f, 0xc5, 0x21, 0xd7, 0x8d, 0x12, 0xcd, 0xc3, 0x68, + 0xd5, 0xc2, 0x14, 0x50, 0xf1, 0x1f, 0x82, 0x96, 0xf2, 0x5e, 0xe9, 0x18, 0x42, 0x90, 0x95, 0x11, + 0x01, 0xe1, 0xab, 0x47, 0x1d, 0x48, 0x5d, 0x47, 0xdc, 0x8e, 0x60, 0xf5, 0x58, 0xc8, 0xc9, 0x7c, + 0xf9, 0x10, 0x83, 0x04, 0x19, 0xb0, 0xf5, 0x63, 0xc4, 0x83, 0xd2, 0x05, 0xe4, 0x83, 0x30, 0xaa, + 0xe9, 0x9a, 0xa3, 0xa9, 0x8d, 0xca, 0x96, 0xda, 0x50, 0xf5, 0xea, 0x41, 0xca, 0x62, 0x96, 0xf2, + 0xf9, 0xb0, 0x21, 0x76, 0xb2, 0x32, 0xc2, 0x21, 0x25, 0x06, 0x40, 0x97, 0x60, 0x50, 0x0c, 0x95, + 0x38, 0x50, 0xb5, 0x21, 0xc8, 0xfd, 0x15, 0x5c, 0x1c, 0xc6, 0x14, 0x5c, 0xfb, 0xff, 0x53, 0xd1, + 0xdf, 0x54, 0xac, 0x00, 0xb0, 0x70, 0x27, 0x09, 0xf6, 0x00, 0xb3, 0x41, 0x12, 0x46, 0x9a, 0x71, + 0x58, 0xb0, 0x1d, 0xdf, 0x7c, 0xdc, 0x8a, 0xc1, 0x90, 0x7f, 0x3e, 0xfe, 0x9c, 0xae, 0x4a, 0x68, + 0xc9, 0xcb, 0x44, 0x09, 0xfe, 0x1d, 0xca, 0x2e, 0x99, 0xa8, 0xcd, 0x7b, 0xf7, 0x4f, 0x41, 0x7f, + 0x12, 0x83, 0x81, 0x75, 0xd5, 0x52, 0x9b, 0x36, 0xaa, 0xb6, 0x55, 0x9a, 0xe2, 0xe0, 0xb4, 0xed, + 0x6b, 0xc3, 0xfc, 0xd0, 0x21, 0xa2, 0xd0, 0xfc, 0x5c, 0x87, 0x42, 0xf3, 0x3d, 0x30, 0x42, 0xf6, + 0xbb, 0xbe, 0x3b, 0x20, 0xc4, 0xda, 0xc3, 0xa5, 0x23, 0x1e, 0x97, 0x60, 0x3f, 0xdb, 0x0e, 0x5f, + 0xf3, 0x5f, 0x02, 0xc9, 0x10, 0x0c, 0x2f, 0x31, 0x13, 0xf2, 0x49, 0x6f, 0xdf, 0xe9, 0xeb, 0x94, + 0x15, 0x68, 0xaa, 0xbb, 0x65, 0xd6, 0x40, 0xcb, 0x80, 0x76, 0xdc, 0xa3, 0x8f, 0x8a, 0x67, 0x4e, + 0x42, 0x7f, 0xfc, 0xf6, 0xad, 0xe9, 0x23, 0x8c, 0xbe, 0x1d, 0x47, 0x56, 0xc6, 0x3c, 0xa0, 0xe0, + 0x76, 0x1a, 0x80, 0xe8, 0x55, 0x61, 0x57, 0x48, 0xd9, 0x76, 0xe7, 0xf0, 0xed, 0x5b, 0xd3, 0x63, + 0x8c, 0x8b, 0xd7, 0x27, 0x2b, 0x69, 0xd2, 0x58, 0x20, 0xbf, 0x7d, 0x9e, 0xfd, 0x15, 0x09, 0x90, + 0x97, 0xf2, 0x15, 0x6c, 0x9b, 0x64, 0xbb, 0x46, 0x0a, 0x71, 0x5f, 0xd5, 0x2c, 0xed, 0x5f, 0x88, + 0x7b, 0xf4, 0xa2, 0x10, 0xf7, 0x45, 0xca, 0x79, 0x2f, 0x3d, 0xc6, 0xf8, 0x3c, 0x76, 0xb8, 0x6f, + 0x5b, 0x98, 0x37, 0x34, 0x41, 0xdd, 0x96, 0x0f, 0x0f, 0xc9, 0xff, 0x52, 0x82, 0x23, 0x6d, 0x1e, + 0xe5, 0x0a, 0xfb, 0x17, 0x00, 0x59, 0xbe, 0x4e, 0xfe, 0x51, 0x31, 0x26, 0x74, 0xdf, 0x0e, 0x3a, + 0x66, 0xb5, 0xe5, 0xdd, 0x3b, 0x97, 0xe1, 0xd9, 0x85, 0xdd, 0x7f, 0x2c, 0xc1, 0x84, 0x7f, 0x78, + 0x57, 0x91, 0x55, 0x18, 0xf2, 0x8f, 0xce, 0x55, 0xb8, 0xbf, 0x17, 0x15, 0xb8, 0xf4, 0x01, 0x7a, + 0xf4, 0x8c, 0x17, 0xae, 0xec, 0x70, 0xec, 0xf1, 0x9e, 0xad, 0x21, 0x64, 0x0a, 0x87, 0x6d, 0x82, + 0xce, 0xc7, 0xff, 0x91, 0x20, 0xb1, 0x6e, 0x18, 0x0d, 0x64, 0xc0, 0x98, 0x6e, 0x38, 0x15, 0xe2, + 0x59, 0xb8, 0x56, 0xe1, 0x9b, 0x6e, 0x96, 0x07, 0xe7, 0xfb, 0x33, 0xd2, 0x77, 0x6e, 0x4d, 0xb7, + 0xb3, 0x52, 0x46, 0x75, 0xc3, 0x29, 0x51, 0xc8, 0x26, 0xdb, 0x92, 0x7f, 0x18, 0x86, 0x83, 0x83, + 0xb1, 0x2c, 0xf9, 0x6c, 0xdf, 0x83, 0x05, 0xd9, 0xdc, 0xbe, 0x35, 0x3d, 0xe1, 0x45, 0x8c, 0x0b, + 0x96, 0x95, 0xa1, 0x2d, 0xdf, 0xe8, 0xec, 0x7e, 0xdc, 0xf7, 0x5e, 0x9e, 0x96, 0x4a, 0x17, 0xbb, + 0x9e, 0x80, 0x3f, 0xb2, 0xaf, 0x08, 0xbb, 0xee, 0x31, 0x6e, 0xf0, 0xd8, 0xfb, 0x1b, 0xa3, 0x30, + 0xdd, 0xe5, 0x9c, 0xd7, 0xd9, 0x3d, 0xd0, 0x11, 0x6f, 0xc4, 0x19, 0x6c, 0xbe, 0xa7, 0x63, 0x65, + 0xf9, 0xa5, 0x04, 0xa0, 0x15, 0xbb, 0x3e, 0x4f, 0x8a, 0x08, 0xdf, 0x9d, 0xae, 0xd0, 0x19, 0x85, + 0xf4, 0x96, 0xce, 0x28, 0x56, 0x02, 0xbb, 0xfe, 0x58, 0x7f, 0x47, 0x87, 0x3d, 0x6f, 0xfd, 0xe3, + 0x6f, 0xcb, 0xd6, 0xbf, 0x73, 0x65, 0x90, 0xb8, 0x73, 0x5b, 0x88, 0xe4, 0x81, 0xb6, 0x10, 0x93, + 0x30, 0xc0, 0x8f, 0xec, 0xd8, 0x87, 0xd4, 0x79, 0x0b, 0x9d, 0x11, 0x9f, 0x95, 0x1e, 0xec, 0x2d, + 0x37, 0x33, 0xec, 0x62, 0xea, 0x13, 0x22, 0x33, 0x7f, 0x36, 0x0e, 0xd9, 0x15, 0xbb, 0x5e, 0xae, + 0x69, 0xce, 0x5d, 0xf2, 0x8e, 0xa7, 0xbb, 0x6f, 0xa4, 0xd0, 0xed, 0x5b, 0xd3, 0x23, 0xcc, 0x0a, + 0xfb, 0xe8, 0xde, 0x84, 0xd1, 0xd0, 0xf9, 0x34, 0xf7, 0x85, 0x85, 0x83, 0x1c, 0x93, 0x87, 0x58, + 0xc9, 0xb4, 0xee, 0xf5, 0x79, 0x24, 0xda, 0xed, 0xec, 0x7e, 0xcc, 0x05, 0x2e, 0xdd, 0xcd, 0x53, + 0x27, 0x6f, 0x56, 0xfe, 0x48, 0x82, 0xcc, 0x8a, 0x2d, 0xf6, 0x72, 0xf8, 0x07, 0x74, 0x5f, 0xfb, + 0xa4, 0xfb, 0x8e, 0x4b, 0xbc, 0x37, 0xef, 0x13, 0xef, 0xbd, 0x78, 0x8a, 0xfe, 0x76, 0x8c, 0xa6, + 0xa7, 0x12, 0xae, 0x6b, 0xba, 0xbb, 0x86, 0xe1, 0x3f, 0xaf, 0xe5, 0xb9, 0x67, 0xd0, 0xc4, 0x41, + 0x0d, 0xfa, 0x86, 0x04, 0xc3, 0x2b, 0x76, 0xfd, 0xaa, 0x5e, 0xfb, 0x7f, 0xdd, 0x77, 0xee, 0xf8, + 0x12, 0xfe, 0xcf, 0x62, 0x70, 0xd2, 0xbf, 0xe6, 0x7e, 0xb0, 0x85, 0xad, 0x3d, 0x77, 0x59, 0x35, + 0xd5, 0xba, 0xa6, 0xfb, 0x9f, 0x62, 0x1f, 0xf1, 0x0b, 0x4c, 0x71, 0x85, 0xd8, 0xb2, 0x0e, 0x99, + 0x75, 0xb5, 0x8e, 0x15, 0xfc, 0xc1, 0x16, 0xb6, 0x9d, 0x0e, 0xef, 0xa6, 0x4c, 0xc2, 0x80, 0xb1, + 0xbd, 0x2d, 0xae, 0xa8, 0x24, 0x14, 0xde, 0x42, 0x13, 0x90, 0x6c, 0x68, 0x4d, 0x8d, 0x19, 0x25, + 0xa1, 0xb0, 0x06, 0x9a, 0x86, 0x4c, 0x95, 0xe8, 0x5e, 0x61, 0x77, 0x7a, 0x13, 0xe2, 0xdb, 0x1b, + 0x2d, 0xdd, 0xd9, 0x24, 0x10, 0xf9, 0x69, 0x18, 0x62, 0xe3, 0xf1, 0x3a, 0xf4, 0x08, 0xa4, 0xe8, + 0x1d, 0x4c, 0x6f, 0xd4, 0x41, 0xd2, 0xbe, 0xc2, 0xde, 0x63, 0x61, 0x5c, 0xd8, 0xc0, 0xac, 0x51, + 0x2a, 0x75, 0x35, 0xe5, 0x89, 0xe8, 0x64, 0xc7, 0x0c, 0xe5, 0x9a, 0xf1, 0x37, 0x92, 0x70, 0x98, + 0x3f, 0x5e, 0x56, 0x4d, 0x6d, 0x76, 0xc7, 0x71, 0xc4, 0x0b, 0x62, 0xc0, 0x37, 0x80, 0xaa, 0xa9, + 0xc9, 0x7b, 0x90, 0xb8, 0xe4, 0x38, 0x26, 0x3a, 0x09, 0x49, 0xab, 0xd5, 0xc0, 0xe2, 0x1c, 0x74, + 0xa2, 0xe0, 0xe1, 0x14, 0x08, 0x82, 0xd2, 0x6a, 0x60, 0x85, 0xa1, 0xa0, 0x32, 0x4c, 0x6f, 0xb7, + 0x1a, 0x8d, 0xbd, 0x4a, 0x0d, 0xd3, 0x7f, 0x9b, 0xe4, 0xfe, 0xe3, 0x01, 0xbc, 0x6b, 0xaa, 0xba, + 0x5b, 0x7c, 0xa4, 0x94, 0x63, 0x14, 0x6d, 0x81, 0x62, 0x89, 0x7f, 0x3a, 0x50, 0x16, 0x38, 0xf2, + 0xef, 0xc5, 0x20, 0x25, 0x58, 0xd3, 0x17, 0x4b, 0x70, 0x03, 0x57, 0x1d, 0x43, 0x3c, 0x28, 0x74, + 0xdb, 0x08, 0x41, 0xbc, 0xce, 0xa7, 0x28, 0x7d, 0xe9, 0x90, 0x42, 0x1a, 0x04, 0xe6, 0xbe, 0xee, + 0x43, 0x60, 0x66, 0x8b, 0xcc, 0x5a, 0xc2, 0x34, 0xc4, 0x81, 0xc5, 0xa5, 0x43, 0x0a, 0x6d, 0xa1, + 0x1c, 0x0c, 0x90, 0x00, 0x72, 0xd8, 0x37, 0x21, 0x09, 0x9c, 0xb7, 0xd1, 0x24, 0x24, 0x4d, 0xd5, + 0xa9, 0xb2, 0x7b, 0xb8, 0xa4, 0x83, 0x35, 0x49, 0x4c, 0xb0, 0x77, 0x71, 0xc3, 0xff, 0x93, 0x84, + 0x18, 0x83, 0x7d, 0xf4, 0x8c, 0xc8, 0xbd, 0xae, 0x3a, 0x0e, 0xb6, 0x74, 0xc2, 0x90, 0xa1, 0xd3, + 0x77, 0xc8, 0x8c, 0xda, 0x1e, 0xff, 0x3f, 0x29, 0xf4, 0x37, 0xff, 0xc7, 0x0c, 0xd4, 0x1f, 0x2a, + 0xb4, 0x93, 0xfd, 0x7b, 0xa8, 0x21, 0x01, 0x2c, 0x11, 0xa4, 0x32, 0x8c, 0xab, 0xb5, 0x9a, 0xc6, + 0xfe, 0x65, 0x49, 0x65, 0x4b, 0xa3, 0x1b, 0x6c, 0x9b, 0xfe, 0xf3, 0xaf, 0x6e, 0x73, 0x81, 0x3c, + 0x82, 0x12, 0xc7, 0x2f, 0xa5, 0x61, 0xd0, 0x64, 0x42, 0xc9, 0x17, 0x60, 0xac, 0x4d, 0x52, 0x22, + 0xdf, 0x75, 0x4d, 0xaf, 0x89, 0x77, 0xa0, 0xc8, 0x6f, 0x02, 0xa3, 0x1f, 0x2e, 0x64, 0x8f, 0x60, + 0xe9, 0xef, 0xd2, 0x8f, 0x75, 0xbf, 0xcb, 0x31, 0xe2, 0xbb, 0xcb, 0xa1, 0x9a, 0x5a, 0x29, 0x4d, + 0xf9, 0xf3, 0x2b, 0x1c, 0x73, 0xbc, 0x83, 0x5d, 0xdf, 0x28, 0x18, 0x56, 0x7d, 0xb6, 0x8e, 0x75, + 0x51, 0x51, 0x93, 0x2e, 0xd5, 0xd4, 0x6c, 0xea, 0x8e, 0xde, 0x87, 0x14, 0xed, 0x0b, 0xbe, 0xdf, + 0xf4, 0x66, 0x47, 0x62, 0x71, 0x6e, 0x7d, 0xc9, 0xf5, 0xe3, 0x6f, 0xc6, 0xe0, 0x98, 0xcf, 0x8f, + 0x7d, 0xc8, 0xed, 0xee, 0x9c, 0xef, 0xec, 0xf1, 0x3d, 0x7c, 0x86, 0xf0, 0x0a, 0x24, 0x08, 0x3e, + 0x8a, 0xf8, 0xb7, 0x09, 0xb9, 0x5f, 0xfa, 0x17, 0xff, 0x48, 0xa6, 0x4e, 0xd1, 0x79, 0x56, 0x28, + 0x93, 0xd2, 0xc7, 0x7b, 0xb7, 0x5f, 0xd6, 0xfb, 0x86, 0xa4, 0x7d, 0xe7, 0xcc, 0x18, 0xb6, 0xe1, + 0xeb, 0x67, 0x40, 0xee, 0xb2, 0x4d, 0x61, 0x19, 0x73, 0xff, 0x8d, 0x51, 0x1f, 0xe9, 0xb8, 0xdb, + 0x3d, 0x99, 0xfd, 0x66, 0xb0, 0xc7, 0x2d, 0xd4, 0x2e, 0x4c, 0x3e, 0x43, 0xc6, 0xf6, 0x0e, 0x8f, + 0x44, 0x62, 0x9f, 0x74, 0x1f, 0x79, 0x4b, 0xfc, 0x7f, 0xaf, 0x89, 0xe7, 0xd7, 0xe0, 0xc9, 0xc7, + 0x37, 0x44, 0x0f, 0x14, 0xba, 0xae, 0x17, 0x05, 0xdf, 0x62, 0xa1, 0xf8, 0x28, 0xe5, 0x9f, 0x97, + 0xe0, 0x9e, 0xb6, 0xa1, 0x79, 0x8e, 0x5f, 0xec, 0xf0, 0x06, 0x54, 0xcf, 0x77, 0x67, 0xfc, 0x6f, + 0x43, 0x2d, 0x76, 0x10, 0xf6, 0xc1, 0x48, 0x61, 0x99, 0x14, 0x01, 0x69, 0x9f, 0x82, 0xc3, 0x41, + 0x61, 0x85, 0x99, 0xde, 0x05, 0x23, 0xc1, 0x9a, 0x80, 0x9b, 0x6b, 0x38, 0x50, 0x15, 0xc8, 0x95, + 0xb0, 0x9d, 0x5d, 0x5d, 0xcb, 0x90, 0x76, 0x51, 0xf9, 0x6e, 0xa4, 0x67, 0x55, 0x3d, 0x4a, 0xf9, + 0x33, 0x12, 0xcc, 0x04, 0x47, 0xf0, 0x8a, 0x6f, 0xbb, 0x3f, 0x61, 0xef, 0xd8, 0x14, 0xbf, 0x21, + 0xc1, 0xbd, 0xfb, 0xc8, 0xc4, 0x0d, 0xf0, 0x3c, 0x4c, 0xf8, 0xce, 0xc7, 0x44, 0x0a, 0x17, 0xd3, + 0x7e, 0x32, 0xfa, 0x60, 0xcf, 0x3d, 0x0e, 0x3a, 0x4a, 0x8c, 0xf2, 0xb5, 0x3f, 0x98, 0x1e, 0x6f, + 0xef, 0xb3, 0x95, 0xf1, 0xf6, 0x33, 0xad, 0x3b, 0xe8, 0x1f, 0x5f, 0x90, 0xe0, 0xa1, 0xa0, 0xaa, + 0x1d, 0x1e, 0x5a, 0xbd, 0x53, 0xf3, 0xf0, 0x6f, 0x25, 0x38, 0xd9, 0x8b, 0x70, 0x7c, 0x42, 0xb6, + 0x60, 0xdc, 0x3b, 0xa5, 0x0e, 0xcf, 0xc7, 0xc3, 0x7d, 0x3c, 0xde, 0xe3, 0x5e, 0x8a, 0x5c, 0x6e, + 0x77, 0xc1, 0xf0, 0x26, 0x0f, 0x2c, 0xff, 0x94, 0xbb, 0x46, 0x0e, 0x16, 0xfe, 0xc2, 0xc8, 0x81, + 0xd2, 0xbf, 0xc3, 0x5c, 0xc4, 0x3a, 0xcc, 0x85, 0x6f, 0x17, 0x72, 0x83, 0xe7, 0xad, 0x0e, 0x27, + 0xd3, 0x1f, 0x80, 0xf1, 0x0e, 0xae, 0xcc, 0xa3, 0xba, 0x0f, 0x4f, 0x56, 0x50, 0xbb, 0xb3, 0xca, + 0x7b, 0x30, 0x4d, 0xc7, 0xed, 0x60, 0xe8, 0xbb, 0xad, 0x72, 0x93, 0xe7, 0x96, 0x8e, 0x43, 0x73, + 0xdd, 0x97, 0x60, 0x80, 0xcd, 0x33, 0x57, 0xf7, 0x00, 0x8e, 0xc2, 0x19, 0xc8, 0x3f, 0x2d, 0x72, + 0xd9, 0x82, 0x10, 0xbb, 0x73, 0x0c, 0xf5, 0xa2, 0xeb, 0x1d, 0x8a, 0x21, 0x9f, 0x31, 0x5e, 0x15, + 0x59, 0xad, 0xb3, 0x74, 0xdc, 0x1c, 0xd5, 0x3b, 0x96, 0xd5, 0x98, 0x6d, 0xee, 0x6e, 0xfa, 0xfa, + 0x59, 0x91, 0xbe, 0x5c, 0x9d, 0x22, 0xd2, 0xd7, 0x3b, 0x63, 0x7a, 0x37, 0x91, 0x45, 0x88, 0xf9, + 0x67, 0x31, 0x91, 0x7d, 0x4f, 0x82, 0x23, 0x54, 0x37, 0xff, 0xe3, 0x8e, 0x7e, 0x4d, 0xfe, 0x08, + 0x20, 0xdb, 0xaa, 0x56, 0x3a, 0x46, 0x77, 0xd6, 0xb6, 0xaa, 0xd7, 0x02, 0xeb, 0xcb, 0x23, 0x80, + 0x6a, 0xb6, 0x13, 0xc6, 0x66, 0x97, 0x43, 0xb3, 0x35, 0xdb, 0xb9, 0xb6, 0xcf, 0x6a, 0x94, 0xb8, + 0x03, 0xd3, 0xf9, 0x8a, 0x04, 0xf9, 0x4e, 0x2a, 0xf3, 0xe9, 0xd3, 0x60, 0x32, 0xf0, 0xe8, 0x2c, + 0x3c, 0x83, 0x8f, 0xf4, 0xf2, 0xc0, 0x28, 0x14, 0x46, 0x87, 0x2d, 0x7c, 0xb7, 0xeb, 0x80, 0xe9, + 0xa0, 0x87, 0xb6, 0x57, 0xd6, 0xef, 0x58, 0xf8, 0xfc, 0x6a, 0x5b, 0x5e, 0xfd, 0x33, 0x51, 0x7b, + 0xef, 0xc2, 0x54, 0x17, 0xa9, 0xef, 0xf6, 0xba, 0xb7, 0xd3, 0x75, 0x32, 0xef, 0x74, 0xf9, 0x7e, + 0x9a, 0x47, 0x42, 0xf0, 0xc5, 0x03, 0xdf, 0x5e, 0xac, 0xd3, 0x3b, 0x9e, 0xf2, 0xfb, 0xe0, 0x68, + 0x47, 0x2a, 0x2e, 0x5b, 0x11, 0x12, 0x3b, 0x9a, 0xed, 0x70, 0xb1, 0x1e, 0xe8, 0x26, 0x56, 0x88, + 0x9a, 0xd2, 0xc8, 0x08, 0xb2, 0x94, 0xf5, 0xba, 0x61, 0x34, 0xb8, 0x18, 0xf2, 0x15, 0x18, 0xf3, + 0xc1, 0xf8, 0x20, 0x67, 0x21, 0x61, 0x1a, 0xfc, 0xab, 0x26, 0x99, 0x53, 0xc7, 0xba, 0x0d, 0x42, + 0x68, 0xb8, 0xda, 0x14, 0x5f, 0x9e, 0x00, 0xc4, 0x98, 0xd1, 0x9b, 0x15, 0x62, 0x88, 0x0d, 0x18, + 0x0f, 0x40, 0xf9, 0x20, 0x3f, 0x04, 0x03, 0x26, 0x85, 0xb8, 0xef, 0xce, 0x75, 0x1b, 0x86, 0x62, + 0xb9, 0xdf, 0x91, 0xa0, 0xad, 0x53, 0xdf, 0x39, 0x0c, 0x49, 0xca, 0x15, 0x7d, 0x5e, 0x02, 0xf0, + 0xdd, 0x93, 0x28, 0x74, 0x63, 0xd3, 0x79, 0x4f, 0x9c, 0x9f, 0xed, 0x19, 0x9f, 0xd7, 0x6c, 0x27, + 0x7f, 0xec, 0x5f, 0xbf, 0xfe, 0xd9, 0xd8, 0xfd, 0x48, 0x9e, 0xed, 0xb2, 0x1b, 0xf7, 0xc5, 0xcb, + 0x57, 0x03, 0x9f, 0xd4, 0x78, 0xb4, 0xb7, 0xa1, 0x84, 0x64, 0x85, 0x5e, 0xd1, 0xb9, 0x60, 0x17, + 0xa8, 0x60, 0x67, 0xd0, 0x13, 0xd1, 0x82, 0xcd, 0x7e, 0x28, 0x18, 0x34, 0x1f, 0x41, 0xbf, 0x23, + 0xc1, 0x44, 0xa7, 0x2d, 0x1d, 0x3a, 0xd7, 0x9b, 0x14, 0xed, 0x25, 0x45, 0xfe, 0xfc, 0x01, 0x28, + 0xb9, 0x2a, 0x8b, 0x54, 0x95, 0x39, 0xf4, 0xf4, 0x01, 0x54, 0x99, 0xf5, 0xad, 0x3b, 0xe8, 0x7f, + 0x49, 0x70, 0x7c, 0xdf, 0x1d, 0x12, 0x9a, 0xeb, 0x4d, 0xca, 0x7d, 0x6a, 0xa7, 0x7c, 0xe9, 0xad, + 0xb0, 0xe0, 0x1a, 0x3f, 0x43, 0x35, 0xbe, 0x82, 0x96, 0x0e, 0xa2, 0xb1, 0x57, 0x11, 0xf9, 0x75, + 0xff, 0xcd, 0xe0, 0x7d, 0xdb, 0xfd, 0xdd, 0xa9, 0x6d, 0xe3, 0x11, 0x11, 0x18, 0xed, 0x45, 0xad, + 0xfc, 0x5e, 0xaa, 0x82, 0x82, 0xd6, 0xdf, 0xe2, 0xa4, 0xcd, 0x7e, 0x28, 0x98, 0xf8, 0x3f, 0x82, + 0xfe, 0xa7, 0xd4, 0xf9, 0xfa, 0xec, 0x93, 0xfb, 0x8a, 0xd8, 0x7d, 0x53, 0x95, 0x3f, 0xd7, 0x3f, + 0x21, 0x57, 0xb2, 0x49, 0x95, 0xac, 0x23, 0x7c, 0xa7, 0x95, 0xec, 0x38, 0x89, 0xe8, 0xb7, 0x24, + 0x98, 0xe8, 0xb4, 0x27, 0x89, 0x08, 0xcb, 0x7d, 0x36, 0x59, 0x11, 0x61, 0xb9, 0xdf, 0x06, 0x48, + 0xfe, 0x21, 0xaa, 0xfc, 0x59, 0x74, 0xba, 0x9b, 0xf2, 0xfb, 0xce, 0x22, 0x89, 0xc5, 0x7d, 0x8b, + 0xfc, 0x88, 0x58, 0xec, 0x65, 0x1f, 0x13, 0x11, 0x8b, 0x3d, 0xed, 0x31, 0xa2, 0x63, 0xd1, 0xd5, + 0xac, 0xc7, 0x69, 0xb4, 0xd1, 0x37, 0x25, 0x18, 0x0e, 0x54, 0xc4, 0xe8, 0xf1, 0x7d, 0x05, 0xed, + 0xb4, 0x61, 0xc8, 0x9f, 0xea, 0x87, 0x84, 0xeb, 0xb2, 0x44, 0x75, 0x99, 0x47, 0x73, 0x07, 0xd1, + 0xc5, 0x0a, 0x48, 0xfc, 0x8a, 0x04, 0xe3, 0x1d, 0xaa, 0xcc, 0x88, 0x28, 0xec, 0x5e, 0x34, 0xe7, + 0xcf, 0xf5, 0x4f, 0xc8, 0xb5, 0xba, 0x48, 0xb5, 0x7a, 0x0f, 0x7a, 0xea, 0x20, 0x5a, 0xf9, 0xd6, + 0xe7, 0x5b, 0xde, 0x6d, 0x44, 0xdf, 0x38, 0xe8, 0x6c, 0x9f, 0x82, 0x09, 0x85, 0x9e, 0xec, 0x9b, + 0x8e, 0xeb, 0xf3, 0x2c, 0xd5, 0xe7, 0x19, 0xb4, 0xf6, 0xd6, 0xf4, 0x69, 0x5f, 0xd6, 0xbf, 0xde, + 0xfe, 0xe2, 0xeb, 0xfe, 0x5e, 0xd4, 0xb1, 0x58, 0xcd, 0x3f, 0xd1, 0x17, 0x0d, 0x57, 0xea, 0x1c, + 0x55, 0xea, 0x14, 0x7a, 0xac, 0x9b, 0x52, 0xbe, 0x2b, 0xa7, 0x9a, 0xbe, 0x6d, 0xcc, 0x7e, 0x88, + 0x95, 0xc0, 0x1f, 0x41, 0x3f, 0x2a, 0xae, 0xfb, 0x9d, 0xd8, 0x77, 0x5c, 0x5f, 0x1d, 0x9b, 0x7f, + 0xa8, 0x07, 0x4c, 0x2e, 0xd7, 0xfd, 0x54, 0xae, 0x29, 0x74, 0xac, 0x9b, 0x5c, 0xa4, 0x96, 0x45, + 0x9f, 0x94, 0xdc, 0x1b, 0xc2, 0x27, 0xf7, 0xe7, 0xed, 0x2f, 0x76, 0xf3, 0x0f, 0xf7, 0x84, 0xcb, + 0x25, 0x79, 0x80, 0x4a, 0x32, 0x83, 0xa6, 0xba, 0x4a, 0xc2, 0x4a, 0xdf, 0x3b, 0x7d, 0x73, 0xe0, + 0x8f, 0x07, 0xbb, 0xbe, 0xe4, 0x5d, 0xc7, 0x3a, 0xb6, 0x35, 0xfb, 0x40, 0x37, 0x00, 0x7b, 0x7b, + 0x3c, 0xf5, 0x3b, 0x49, 0x18, 0x5a, 0x64, 0xa3, 0x6c, 0x38, 0xaa, 0xf3, 0x16, 0x37, 0x02, 0xc8, + 0xe6, 0xdf, 0x8b, 0x62, 0x1f, 0xba, 0xf3, 0x3e, 0xdd, 0x36, 0xd4, 0xd7, 0x3b, 0x93, 0xec, 0xfe, + 0x13, 0x7f, 0x3d, 0x31, 0xcc, 0x4f, 0x66, 0x9f, 0x9e, 0xa2, 0x77, 0x17, 0xd8, 0x27, 0xea, 0x3e, + 0x26, 0xc1, 0x61, 0x8a, 0xe5, 0xc5, 0x1b, 0xc5, 0x14, 0x2f, 0xcc, 0x74, 0xf5, 0x98, 0x65, 0xd5, + 0x77, 0x04, 0xc3, 0x3e, 0x2a, 0x77, 0x3f, 0xbf, 0x4c, 0x7e, 0xcc, 0x37, 0x78, 0x98, 0xad, 0xac, + 0x8c, 0x37, 0xda, 0x28, 0xed, 0xd0, 0xbe, 0x3e, 0x71, 0xf0, 0x7d, 0xfd, 0x65, 0xc8, 0xf8, 0x32, + 0x7d, 0x2e, 0x19, 0xf1, 0x8e, 0x57, 0xf8, 0x10, 0xcd, 0x4f, 0x8c, 0x3e, 0x2e, 0xc1, 0xe1, 0x8e, + 0x8b, 0x20, 0xfd, 0x6f, 0x84, 0x7d, 0x1e, 0xd2, 0x85, 0x8c, 0xd3, 0x91, 0xaf, 0xac, 0x4c, 0xb4, + 0x3a, 0x55, 0x13, 0xeb, 0x30, 0x1c, 0x58, 0xc0, 0x72, 0xe2, 0x7f, 0x8a, 0xf6, 0x7e, 0xbd, 0x39, + 0xc8, 0x00, 0xe5, 0x21, 0x85, 0x77, 0x4d, 0xc3, 0x72, 0x70, 0x8d, 0x5e, 0x79, 0x48, 0x29, 0x6e, + 0x5b, 0x5e, 0x05, 0xd4, 0x3e, 0xb9, 0xe1, 0xaf, 0x28, 0xa6, 0xbd, 0xaf, 0x28, 0x4e, 0x40, 0xd2, + 0xff, 0x9d, 0x41, 0xd6, 0xb8, 0x7b, 0xb7, 0x85, 0xfe, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x99, + 0x63, 0xc7, 0x34, 0x4c, 0x8e, 0x00, 0x00, } r := bytes.NewReader(gzipped) gzipr, err := compress_gzip.NewReader(r) diff --git a/x/upgrade/abci_test.go b/x/upgrade/abci_test.go index 1c3d652245..5950a17f13 100644 --- a/x/upgrade/abci_test.go +++ b/x/upgrade/abci_test.go @@ -3,6 +3,7 @@ package upgrade_test import ( "encoding/json" "errors" + "fmt" "io/ioutil" "os" "testing" @@ -20,6 +21,8 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/module" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" "github.com/cosmos/cosmos-sdk/x/upgrade" "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" "github.com/cosmos/cosmos-sdk/x/upgrade/types" @@ -224,16 +227,27 @@ func TestNoSpuriousUpgrades(t *testing.T) { } func TestPlanStringer(t *testing.T) { + clientState := &ibctmtypes.ClientState{ChainId: "gaiachain"} + cs, err := clienttypes.PackClientState(clientState) + require.NoError(t, err) + ti, err := time.Parse(time.RFC3339, "2020-01-01T00:00:00Z") require.Nil(t, err) require.Equal(t, `Upgrade Plan Name: test Time: 2020-01-01T00:00:00Z - Info: `, types.Plan{Name: "test", Time: ti}.String()) + Info: + Upgraded IBC Client: no upgraded client provided`, types.Plan{Name: "test", Time: ti}.String()) require.Equal(t, `Upgrade Plan Name: test Height: 100 - Info: `, types.Plan{Name: "test", Height: 100}.String()) + Info: + Upgraded IBC Client: no upgraded client provided`, types.Plan{Name: "test", Height: 100}.String()) + require.Equal(t, fmt.Sprintf(`Upgrade Plan + Name: test + Height: 100 + Info: + Upgraded IBC Client: %s`, clientState), types.Plan{Name: "test", Height: 100, UpgradedClientState: cs}.String()) } func VerifyNotDone(t *testing.T, newCtx sdk.Context, name string) { diff --git a/x/upgrade/keeper/keeper.go b/x/upgrade/keeper/keeper.go index ab85479823..9c943facf9 100644 --- a/x/upgrade/keeper/keeper.go +++ b/x/upgrade/keeper/keeper.go @@ -17,6 +17,8 @@ import ( store "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + ibcexported "github.com/cosmos/cosmos-sdk/x/ibc/exported" "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) @@ -52,6 +54,8 @@ func (k Keeper) SetUpgradeHandler(name string, upgradeHandler types.UpgradeHandl // ScheduleUpgrade schedules an upgrade based on the specified plan. // If there is another Plan already scheduled, it will overwrite it // (implicitly cancelling the current plan) +// ScheduleUpgrade will also write the upgraded client to the upgraded client path +// if an upgraded client is specified in the plan func (k Keeper) ScheduleUpgrade(ctx sdk.Context, plan types.Plan) error { if err := plan.ValidateBasic(); err != nil { return err @@ -69,13 +73,48 @@ func (k Keeper) ScheduleUpgrade(ctx sdk.Context, plan types.Plan) error { return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "upgrade with name %s has already been completed", plan.Name) } - bz := k.cdc.MustMarshalBinaryBare(&plan) store := ctx.KVStore(k.storeKey) + + bz := k.cdc.MustMarshalBinaryBare(&plan) store.Set(types.PlanKey(), bz) + if plan.UpgradedClientState != nil { + clientState, err := clienttypes.UnpackClientState(plan.UpgradedClientState) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "could not unpack clientstate: %v", err) + } + return k.SetUpgradedClient(ctx, clientState) + } + // delete upgraded client key to remove any upgraded client set by outdated plan + store.Delete(types.UpgradedClientKey()) return nil } +// SetUpgradedClient sets the expected upgraded client for the next version of this chain +func (k Keeper) SetUpgradedClient(ctx sdk.Context, cs ibcexported.ClientState) error { + // zero out any custom fields before setting + cs = cs.ZeroCustomFields() + bz, err := clienttypes.MarshalClientState(k.cdc, cs) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "could not marshal clientstate: %v", err) + } + + store := ctx.KVStore(k.storeKey) + store.Set(types.UpgradedClientKey(), bz) + return nil +} + +// GetUpgradedClient gets the expected upgraded client for the next version of this chain +func (k Keeper) GetUpgradedClient(ctx sdk.Context) (ibcexported.ClientState, error) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.UpgradedClientKey()) + if len(bz) == 0 { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "no upgraded client in store") + } + + return clienttypes.UnmarshalClientState(k.cdc, bz) +} + // GetDoneHeight returns the height at which the given upgrade was executed func (k Keeper) GetDoneHeight(ctx sdk.Context, name string) int64 { store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte{types.DoneByte}) diff --git a/x/upgrade/keeper/keeper_test.go b/x/upgrade/keeper/keeper_test.go index 3fa408ba21..7d3dc284c7 100644 --- a/x/upgrade/keeper/keeper_test.go +++ b/x/upgrade/keeper/keeper_test.go @@ -3,11 +3,17 @@ package keeper_test import ( "path/filepath" "testing" + "time" "github.com/stretchr/testify/suite" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/cosmos/cosmos-sdk/simapp" store "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) @@ -17,6 +23,7 @@ type KeeperTestSuite struct { homeDir string app *simapp.SimApp + ctx sdk.Context } func (s *KeeperTestSuite) SetupTest() { @@ -28,6 +35,10 @@ func (s *KeeperTestSuite) SetupTest() { s.T().Log("home dir:", homeDir) s.homeDir = homeDir s.app = app + s.ctx = app.BaseApp.NewContext(false, tmproto.Header{ + Time: time.Now(), + Height: 10, + }) } func (s *KeeperTestSuite) TestReadUpgradeInfoFromDisk() { @@ -48,6 +59,197 @@ func (s *KeeperTestSuite) TestReadUpgradeInfoFromDisk() { s.Require().Equal(expected, ui) } +func (s *KeeperTestSuite) TestScheduleUpgrade() { + clientState := &ibctmtypes.ClientState{ChainId: "gaiachain"} + cs, err := clienttypes.PackClientState(clientState) + s.Require().NoError(err) + + altClientState := &ibctmtypes.ClientState{ChainId: "ethermint"} + altCs, err := clienttypes.PackClientState(altClientState) + s.Require().NoError(err) + + consState := ibctmtypes.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("app_hash")), []byte("next_vals_hash")) + consAny, err := clienttypes.PackConsensusState(consState) + s.Require().NoError(err) + + cases := []struct { + name string + plan types.Plan + setup func() + expPass bool + }{ + { + name: "successful time schedule", + plan: types.Plan{ + Name: "all-good", + Info: "some text here", + Time: s.ctx.BlockTime().Add(time.Hour), + }, + setup: func() {}, + expPass: true, + }, + { + name: "successful height schedule", + plan: types.Plan{ + Name: "all-good", + Info: "some text here", + Height: 123450000, + }, + setup: func() {}, + expPass: true, + }, + { + name: "successful ibc schedule", + plan: types.Plan{ + Name: "all-good", + Info: "some text here", + Height: 123450000, + UpgradedClientState: cs, + }, + setup: func() {}, + expPass: true, + }, + { + name: "successful overwrite", + plan: types.Plan{ + Name: "all-good", + Info: "some text here", + Height: 123450000, + }, + setup: func() { + s.app.UpgradeKeeper.ScheduleUpgrade(s.ctx, types.Plan{ + Name: "alt-good", + Info: "new text here", + Height: 543210000, + }) + }, + expPass: true, + }, + { + name: "successful IBC overwrite", + plan: types.Plan{ + Name: "all-good", + Info: "some text here", + Height: 123450000, + UpgradedClientState: cs, + }, + setup: func() { + s.app.UpgradeKeeper.ScheduleUpgrade(s.ctx, types.Plan{ + Name: "alt-good", + Info: "new text here", + Height: 543210000, + UpgradedClientState: altCs, + }) + }, + expPass: true, + }, + { + name: "successful IBC overwrite with non IBC plan", + plan: types.Plan{ + Name: "all-good", + Info: "some text here", + Height: 123450000, + }, + setup: func() { + s.app.UpgradeKeeper.ScheduleUpgrade(s.ctx, types.Plan{ + Name: "alt-good", + Info: "new text here", + Height: 543210000, + UpgradedClientState: altCs, + }) + }, + expPass: true, + }, + + { + name: "unsuccessful schedule: invalid plan", + plan: types.Plan{ + Height: 123450000, + }, + setup: func() {}, + expPass: false, + }, + { + name: "unsuccessful time schedule: due date in past", + plan: types.Plan{ + Name: "all-good", + Info: "some text here", + Time: s.ctx.BlockTime(), + }, + setup: func() {}, + expPass: false, + }, + { + name: "unsuccessful height schedule: due date in past", + plan: types.Plan{ + Name: "all-good", + Info: "some text here", + Height: 1, + }, + setup: func() {}, + expPass: false, + }, + { + name: "unsuccessful schedule: schedule already executed", + plan: types.Plan{ + Name: "all-good", + Info: "some text here", + Height: 123450000, + }, + setup: func() { + s.app.UpgradeKeeper.SetUpgradeHandler("all-good", func(_ sdk.Context, _ types.Plan) {}) + s.app.UpgradeKeeper.ApplyUpgrade(s.ctx, types.Plan{ + Name: "all-good", + Info: "some text here", + Height: 123450000, + }) + }, + expPass: false, + }, + { + name: "unsuccessful IBC schedule: UpgradedClientState is not valid client state", + plan: types.Plan{ + Name: "all-good", + Info: "some text here", + Height: 123450000, + UpgradedClientState: consAny, + }, + setup: func() {}, + expPass: false, + }, + } + + for _, tc := range cases { + tc := tc + + s.Run(tc.name, func() { + // reset suite + s.SetupTest() + + // setup test case + tc.setup() + + err := s.app.UpgradeKeeper.ScheduleUpgrade(s.ctx, tc.plan) + + if tc.expPass { + s.Require().NoError(err, "valid test case failed") + if tc.plan.UpgradedClientState != nil { + got, err := s.app.UpgradeKeeper.GetUpgradedClient(s.ctx) + s.Require().NoError(err) + s.Require().Equal(clientState, got, "upgradedClient not equal to expected value") + } else { + // check that upgraded client is empty if latest plan does not specify an upgraded client + got, err := s.app.UpgradeKeeper.GetUpgradedClient(s.ctx) + s.Require().Error(err) + s.Require().Nil(got) + } + } else { + s.Require().Error(err, "invalid test case passed") + } + }) + } +} + func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } diff --git a/x/upgrade/types/keys.go b/x/upgrade/types/keys.go index cda224623b..593cd52f5f 100644 --- a/x/upgrade/types/keys.go +++ b/x/upgrade/types/keys.go @@ -19,6 +19,9 @@ const ( PlanByte = 0x0 // DoneByte is a prefix for to look up completed upgrade plan by name DoneByte = 0x1 + + // KeyUpgradedClient is the key under which upgraded client is stored in the upgrade store + KeyUpgradedClient = "upgradedClient" ) // PlanKey is the key under which the current plan is saved @@ -26,3 +29,10 @@ const ( func PlanKey() []byte { return []byte{PlanByte} } + +// UpgradedClientKey is the key under which the upgraded client state is saved +// Connecting IBC chains can verify against the upgraded client in this path before +// upgrading their clients +func UpgradedClientKey() []byte { + return []byte(KeyUpgradedClient) +} diff --git a/x/upgrade/types/plan.go b/x/upgrade/types/plan.go index 4f31063bc7..672bb98b5e 100644 --- a/x/upgrade/types/plan.go +++ b/x/upgrade/types/plan.go @@ -5,17 +5,31 @@ import ( "strings" "time" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + ibcexported "github.com/cosmos/cosmos-sdk/x/ibc/exported" ) +var _ codectypes.UnpackInterfacesMessage = Plan{} + func (p Plan) String() string { due := p.DueAt() dueUp := strings.ToUpper(due[0:1]) + due[1:] + var upgradedClientStr string + upgradedClient, err := clienttypes.UnpackClientState(p.UpgradedClientState) + if err != nil { + upgradedClientStr = "no upgraded client provided" + } else { + upgradedClientStr = fmt.Sprintf("%s", upgradedClient) + } return fmt.Sprintf(`Upgrade Plan Name: %s %s - Info: %s`, p.Name, dueUp, p.Info) + Info: %s + Upgraded IBC Client: %s`, p.Name, dueUp, p.Info, upgradedClientStr) } // ValidateBasic does basic validation of a Plan @@ -32,6 +46,9 @@ func (p Plan) ValidateBasic() error { if !p.Time.IsZero() && p.Height != 0 { return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "cannot set both time and height") } + if !p.Time.IsZero() && p.UpgradedClientState != nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "IBC chain upgrades must only set height") + } return nil } @@ -54,3 +71,14 @@ func (p Plan) DueAt() string { } return fmt.Sprintf("height: %d", p.Height) } + +// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces +func (p Plan) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { + // UpgradedClientState may be nil + if p.UpgradedClientState == nil { + return nil + } + + var clientState ibcexported.ClientState + return unpacker.UnpackAny(p.UpgradedClientState, &clientState) +} diff --git a/x/upgrade/types/plan_test.go b/x/upgrade/types/plan_test.go index 47ed2ca7ec..65d401b61f 100644 --- a/x/upgrade/types/plan_test.go +++ b/x/upgrade/types/plan_test.go @@ -1,6 +1,7 @@ package types import ( + "fmt" "testing" "time" @@ -9,6 +10,9 @@ import ( "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -21,6 +25,9 @@ func mustParseTime(s string) time.Time { } func TestPlanString(t *testing.T) { + cs, err := clienttypes.PackClientState(&ibctmtypes.ClientState{}) + require.NoError(t, err) + cases := map[string]struct { p Plan expect string @@ -31,7 +38,7 @@ func TestPlanString(t *testing.T) { Info: "https://foo.bar", Time: mustParseTime("2019-07-08T11:33:55Z"), }, - expect: "Upgrade Plan\n Name: due_time\n Time: 2019-07-08T11:33:55Z\n Info: https://foo.bar", + expect: "Upgrade Plan\n Name: due_time\n Time: 2019-07-08T11:33:55Z\n Info: https://foo.bar\n Upgraded IBC Client: no upgraded client provided", }, "with height": { p: Plan{ @@ -39,13 +46,23 @@ func TestPlanString(t *testing.T) { Info: "https://foo.bar/baz", Height: 7890, }, - expect: "Upgrade Plan\n Name: by height\n Height: 7890\n Info: https://foo.bar/baz", + expect: "Upgrade Plan\n Name: by height\n Height: 7890\n Info: https://foo.bar/baz\n Upgraded IBC Client: no upgraded client provided", }, + "with IBC client": { + p: Plan{ + Name: "by height", + Info: "https://foo.bar/baz", + Height: 7890, + UpgradedClientState: cs, + }, + expect: fmt.Sprintf("Upgrade Plan\n Name: by height\n Height: 7890\n Info: https://foo.bar/baz\n Upgraded IBC Client: %s", &ibctmtypes.ClientState{}), + }, + "neither": { p: Plan{ Name: "almost-empty", }, - expect: "Upgrade Plan\n Name: almost-empty\n Height: 0\n Info: ", + expect: "Upgrade Plan\n Name: almost-empty\n Height: 0\n Info: \n Upgraded IBC Client: no upgraded client provided", }, } @@ -59,6 +76,9 @@ func TestPlanString(t *testing.T) { } func TestPlanValid(t *testing.T) { + cs, err := clienttypes.PackClientState(&ibctmtypes.ClientState{}) + require.NoError(t, err) + cases := map[string]struct { p Plan valid bool @@ -71,6 +91,15 @@ func TestPlanValid(t *testing.T) { }, valid: true, }, + "proper ibc upgrade": { + p: Plan{ + Name: "ibc-all-good", + Info: "some text here", + Height: 123450000, + UpgradedClientState: cs, + }, + valid: true, + }, "proper by height": { p: Plan{ Name: "all-good", @@ -95,6 +124,15 @@ func TestPlanValid(t *testing.T) { Height: -12345, }, }, + "time due date defined for IBC plan": { + p: Plan{ + Name: "ibc-all-good", + Info: "some text here", + Time: mustParseTime("2019-07-08T11:33:55Z"), + UpgradedClientState: cs, + }, + valid: false, + }, } for name, tc := range cases { diff --git a/x/upgrade/types/upgrade.pb.go b/x/upgrade/types/upgrade.pb.go index 420a8db538..cb608f8747 100644 --- a/x/upgrade/types/upgrade.pb.go +++ b/x/upgrade/types/upgrade.pb.go @@ -5,6 +5,7 @@ package types import ( fmt "fmt" + types "github.com/cosmos/cosmos-sdk/codec/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" @@ -46,6 +47,12 @@ type Plan struct { // Any application specific upgrade info to be included on-chain // such as a git commit that validators could automatically upgrade to Info string `protobuf:"bytes,4,opt,name=info,proto3" json:"info,omitempty"` + // IBC-enabled chains can opt-in to including the upgraded client state in its upgrade plan + // This will make the chain commit to the correct upgraded (self) client state before the upgrade occurs, + // so that connecting chains can verify that the new upgraded client is valid by verifying a proof on the + // previous version of the chain. + // This will allow IBC connections to persist smoothly across planned chain upgrades + UpgradedClientState *types.Any `protobuf:"bytes,5,opt,name=upgraded_client_state,json=upgradedClientState,proto3" json:"upgraded_client_state,omitempty" yaml:"upgraded_client_state"` } func (m *Plan) Reset() { *m = Plan{} } @@ -170,30 +177,34 @@ func init() { } var fileDescriptor_ccf2a7d4d7b48dca = []byte{ - // 368 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x92, 0xbf, 0x4e, 0xf3, 0x30, - 0x14, 0xc5, 0xe3, 0xaf, 0xf9, 0x2a, 0xea, 0x6e, 0x56, 0x55, 0xa2, 0x0a, 0x9c, 0xa8, 0x62, 0xe8, - 0x00, 0x8e, 0x5a, 0x24, 0x84, 0x18, 0xcb, 0x8e, 0xaa, 0x00, 0x0b, 0x12, 0x83, 0x93, 0xba, 0x69, - 0x44, 0x12, 0x47, 0xb1, 0xcb, 0x9f, 0x17, 0x60, 0xa5, 0x8f, 0xc0, 0xe3, 0x74, 0xec, 0xd8, 0x09, - 0x68, 0xbb, 0xf0, 0x18, 0x28, 0x76, 0x82, 0x18, 0x18, 0x99, 0x72, 0xcf, 0xd5, 0x2f, 0xe7, 0x9e, - 0x9b, 0x5c, 0x78, 0x10, 0x70, 0x91, 0x70, 0xe1, 0xce, 0xb2, 0x30, 0xa7, 0x63, 0xe6, 0xde, 0xf7, - 0x7d, 0x26, 0x69, 0xbf, 0xd2, 0x24, 0xcb, 0xb9, 0xe4, 0xa8, 0xad, 0x29, 0x52, 0x75, 0x4b, 0xaa, - 0xd3, 0x0a, 0x79, 0xc8, 0x15, 0xe2, 0x16, 0x95, 0xa6, 0x3b, 0x76, 0xc8, 0x79, 0x18, 0x33, 0x57, - 0x29, 0x7f, 0x36, 0x71, 0x65, 0x94, 0x30, 0x21, 0x69, 0x92, 0x69, 0xa0, 0xfb, 0x0c, 0xa0, 0x39, - 0x8a, 0x69, 0x8a, 0x10, 0x34, 0x53, 0x9a, 0x30, 0x0b, 0x38, 0xa0, 0xd7, 0xf0, 0x54, 0x8d, 0x4e, - 0xa1, 0x59, 0xf0, 0xd6, 0x3f, 0x07, 0xf4, 0x9a, 0x83, 0x0e, 0xd1, 0x66, 0xa4, 0x32, 0x23, 0x57, - 0x95, 0xd9, 0x70, 0x67, 0xf1, 0x66, 0x1b, 0xf3, 0x77, 0x1b, 0x78, 0xea, 0x0d, 0xd4, 0x86, 0xf5, - 0x29, 0x8b, 0xc2, 0xa9, 0xb4, 0x6a, 0x0e, 0xe8, 0xd5, 0xbc, 0x52, 0x15, 0x53, 0xa2, 0x74, 0xc2, - 0x2d, 0x53, 0x4f, 0x29, 0xea, 0x33, 0xf3, 0xf3, 0xd5, 0x06, 0xdd, 0x17, 0x00, 0x77, 0x2f, 0xf9, - 0x44, 0x3e, 0xd0, 0x9c, 0x5d, 0xeb, 0xdd, 0x46, 0x39, 0xcf, 0xb8, 0xa0, 0x31, 0x6a, 0xc1, 0xff, - 0x32, 0x92, 0x71, 0x15, 0x4e, 0x0b, 0xe4, 0xc0, 0xe6, 0x98, 0x89, 0x20, 0x8f, 0x32, 0x19, 0xf1, - 0x54, 0x85, 0x6c, 0x78, 0x3f, 0x5b, 0xe8, 0x04, 0x9a, 0x59, 0x4c, 0x53, 0x95, 0xa1, 0x39, 0xd8, - 0x23, 0xbf, 0x7f, 0x3a, 0x52, 0xec, 0x3f, 0x34, 0x8b, 0x0d, 0x3c, 0xc5, 0x97, 0x89, 0x6e, 0xe1, - 0xfe, 0x39, 0x4d, 0x03, 0x16, 0xff, 0x71, 0x2c, 0x6d, 0x3f, 0xbc, 0x58, 0xac, 0xb1, 0xb1, 0x5a, - 0x63, 0x63, 0xb1, 0xc1, 0x60, 0xb9, 0xc1, 0xe0, 0x63, 0x83, 0xc1, 0x7c, 0x8b, 0x8d, 0xe5, 0x16, - 0x1b, 0xab, 0x2d, 0x36, 0x6e, 0x0e, 0xc3, 0x48, 0x4e, 0x67, 0x3e, 0x09, 0x78, 0xe2, 0x96, 0xb7, - 0xa1, 0x1f, 0x47, 0x62, 0x7c, 0xe7, 0x3e, 0x7e, 0x1f, 0x8a, 0x7c, 0xca, 0x98, 0xf0, 0xeb, 0xea, - 0xb7, 0x1c, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0xdc, 0xda, 0x23, 0xdb, 0x47, 0x02, 0x00, 0x00, + // 426 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x52, 0x31, 0x6f, 0xd4, 0x30, + 0x18, 0x8d, 0x69, 0x5a, 0x51, 0xdf, 0x66, 0x8e, 0x12, 0x4e, 0xc5, 0x89, 0x4e, 0x0c, 0x37, 0x80, + 0xa3, 0x16, 0x09, 0xa1, 0x6e, 0xa4, 0x3b, 0xaa, 0x52, 0x58, 0x90, 0x50, 0xe5, 0x24, 0xbe, 0x9c, + 0xc1, 0xb1, 0xa3, 0xd8, 0x07, 0xe4, 0x57, 0xd0, 0x9f, 0xc0, 0xcf, 0xb9, 0xb1, 0x63, 0xa7, 0x42, + 0xef, 0x16, 0xe6, 0xfe, 0x02, 0x14, 0x3b, 0x41, 0x08, 0x3a, 0x76, 0xf2, 0xf7, 0x3d, 0xbd, 0xef, + 0x3d, 0xfb, 0xf9, 0x83, 0x4f, 0x73, 0xa5, 0x2b, 0xa5, 0xe3, 0x65, 0x5d, 0x36, 0xb4, 0x60, 0xf1, + 0xe7, 0x83, 0x8c, 0x19, 0x7a, 0x30, 0xf4, 0xa4, 0x6e, 0x94, 0x51, 0x68, 0xcf, 0xb1, 0xc8, 0x80, + 0xf6, 0xac, 0xc9, 0xe3, 0x52, 0xa9, 0x52, 0xb0, 0xd8, 0xb2, 0xb2, 0xe5, 0x3c, 0xa6, 0xb2, 0x75, + 0x23, 0x93, 0x71, 0xa9, 0x4a, 0x65, 0xcb, 0xb8, 0xab, 0x7a, 0x34, 0xfc, 0x77, 0xc0, 0xf0, 0x8a, + 0x69, 0x43, 0xab, 0xda, 0x11, 0xa6, 0x37, 0x00, 0xfa, 0x27, 0x82, 0x4a, 0x84, 0xa0, 0x2f, 0x69, + 0xc5, 0x02, 0x10, 0x81, 0xd9, 0x6e, 0x6a, 0x6b, 0xf4, 0x0a, 0xfa, 0x1d, 0x3f, 0xb8, 0x17, 0x81, + 0xd9, 0xe8, 0x70, 0x42, 0x9c, 0x18, 0x19, 0xc4, 0xc8, 0xdb, 0x41, 0x2c, 0xb9, 0xbf, 0xba, 0x0a, + 0xbd, 0xf3, 0x1f, 0x21, 0x48, 0xed, 0x04, 0xda, 0x83, 0x3b, 0x0b, 0xc6, 0xcb, 0x85, 0x09, 0xb6, + 0x22, 0x30, 0xdb, 0x4a, 0xfb, 0xae, 0x73, 0xe1, 0x72, 0xae, 0x02, 0xdf, 0xb9, 0x74, 0x35, 0xfa, + 0x08, 0x1f, 0xf6, 0xef, 0x2c, 0xce, 0x72, 0xc1, 0x99, 0x34, 0x67, 0xda, 0x50, 0xc3, 0x82, 0x6d, + 0x6b, 0x3b, 0xfe, 0xcf, 0xf6, 0xb5, 0x6c, 0x93, 0xe8, 0xe6, 0x2a, 0xdc, 0x6f, 0x69, 0x25, 0x8e, + 0xa6, 0xb7, 0x0e, 0x4f, 0xd3, 0x07, 0x03, 0x7e, 0x6c, 0xe1, 0xd3, 0x0e, 0x3d, 0xf2, 0x7f, 0x7d, + 0x0f, 0xc1, 0xf4, 0x1b, 0x80, 0x8f, 0x4e, 0xd5, 0xdc, 0x7c, 0xa1, 0x0d, 0x7b, 0xe7, 0x58, 0x27, + 0x8d, 0xaa, 0x95, 0xa6, 0x02, 0x8d, 0xe1, 0xb6, 0xe1, 0x46, 0x0c, 0x41, 0xb8, 0x06, 0x45, 0x70, + 0x54, 0x30, 0x9d, 0x37, 0xbc, 0x36, 0x5c, 0x49, 0x1b, 0xc8, 0x6e, 0xfa, 0x37, 0x84, 0x5e, 0x42, + 0xbf, 0x16, 0x54, 0xda, 0xf7, 0x8e, 0x0e, 0xf7, 0xc9, 0xed, 0x3f, 0x48, 0xba, 0xac, 0x13, 0xbf, + 0x4b, 0x2b, 0xb5, 0xfc, 0xfe, 0x46, 0x1f, 0xe0, 0x93, 0x63, 0x2a, 0x73, 0x26, 0xee, 0xf8, 0x5a, + 0x4e, 0x3e, 0x79, 0xb3, 0xba, 0xc6, 0xde, 0xe5, 0x35, 0xf6, 0x56, 0x6b, 0x0c, 0x2e, 0xd6, 0x18, + 0xfc, 0x5c, 0x63, 0x70, 0xbe, 0xc1, 0xde, 0xc5, 0x06, 0x7b, 0x97, 0x1b, 0xec, 0xbd, 0x7f, 0x56, + 0x72, 0xb3, 0x58, 0x66, 0x24, 0x57, 0x55, 0xdc, 0xaf, 0xa8, 0x3b, 0x9e, 0xeb, 0xe2, 0x53, 0xfc, + 0xf5, 0xcf, 0xbe, 0x9a, 0xb6, 0x66, 0x3a, 0xdb, 0xb1, 0x7f, 0xf1, 0xe2, 0x77, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xca, 0x9e, 0x7a, 0x5d, 0xce, 0x02, 0x00, 0x00, } func (this *Plan) Equal(that interface{}) bool { @@ -227,6 +238,9 @@ func (this *Plan) Equal(that interface{}) bool { if this.Info != that1.Info { return false } + if !this.UpgradedClientState.Equal(that1.UpgradedClientState) { + return false + } return true } func (this *SoftwareUpgradeProposal) Equal(that interface{}) bool { @@ -306,6 +320,18 @@ func (m *Plan) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.UpgradedClientState != nil { + { + size, err := m.UpgradedClientState.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintUpgrade(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } if len(m.Info) > 0 { i -= len(m.Info) copy(dAtA[i:], m.Info) @@ -318,12 +344,12 @@ func (m *Plan) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x18 } - n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) - if err1 != nil { - return 0, err1 + n2, err2 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) + if err2 != nil { + return 0, err2 } - i -= n1 - i = encodeVarintUpgrade(dAtA, i, uint64(n1)) + i -= n2 + i = encodeVarintUpgrade(dAtA, i, uint64(n2)) i-- dAtA[i] = 0x12 if len(m.Name) > 0 { @@ -450,6 +476,10 @@ func (m *Plan) Size() (n int) { if l > 0 { n += 1 + l + sovUpgrade(uint64(l)) } + if m.UpgradedClientState != nil { + l = m.UpgradedClientState.Size() + n += 1 + l + sovUpgrade(uint64(l)) + } return n } @@ -640,6 +670,42 @@ func (m *Plan) Unmarshal(dAtA []byte) error { } m.Info = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UpgradedClientState", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowUpgrade + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthUpgrade + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthUpgrade + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.UpgradedClientState == nil { + m.UpgradedClientState = &types.Any{} + } + if err := m.UpgradedClientState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipUpgrade(dAtA[iNdEx:])